""" novelWriter – Main GUI Novel Tree Class Tester ============================================== This file is a part of novelWriter Copyright (C) 2021 Veronica Berglyd Olsen and novelWriter contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ from __future__ import annotations from pathlib import Path import pytest from PyQt6.QtCore import QEvent, QPoint, Qt from PyQt6.QtGui import QFocusEvent from PyQt6.QtWidgets import QInputDialog, QToolTip from novelwriter import CONFIG, SHARED from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.enum import nwFocus, nwItemType from novelwriter.gui.noveltree import GuiNovelTree, NovelTreeColumn from novelwriter.types import QtMouseLeft, QtMouseMiddle from tests.tools import C, buildTestProject @pytest.mark.gui def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd): """Test navigating the novel tree.""" monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True)) buildTestProject(nwGUI, projPath) nwGUI._switchFocus(nwFocus.TREE) nwGUI.projView.projTree.clearSelection() nwGUI.projView.projTree.setSelectedHandle(C.hCharRoot) nwGUI.projView.projTree.newTreeItem(nwItemType.FILE) contentPath = SHARED.project.storage.contentPath assert isinstance(contentPath, Path) (contentPath / "0000000000010.nwd").write_text( "# Jane Doe\n\n@tag: Jane\n\n", encoding="utf-8" ) (contentPath / "000000000000f.nwd").write_text(( "### Scene One\n\n" "@pov: Jane\n" "@focus: Jane\n\n" "% Synopsis: This is a scene." ), encoding="utf-8") novelView = nwGUI.novelView novelTree = novelView.novelTree novelBar = novelView.novelBar # Show/Hide Scrollbars # ==================== CONFIG.hideVScroll = True CONFIG.hideHScroll = True novelView.initSettings() assert not novelTree.verticalScrollBar().isVisible() assert not novelTree.horizontalScrollBar().isVisible() CONFIG.hideVScroll = False CONFIG.hideHScroll = False novelView.initSettings() assert novelTree.verticalScrollBar().isEnabled() assert novelTree.horizontalScrollBar().isEnabled() # Populate Tree # ============= novelView.setTreeFocus() nwGUI.projStack.setCurrentWidget(nwGUI.novelView) nwGUI.rebuildIndex() novelTree._populateTree(rootHandle=None) assert novelTree.topLevelItemCount() == 3 # Rebuild should preserve selection topItem = novelTree.topLevelItem(0) assert not topItem.isSelected() topItem.setSelected(True) assert novelTree.selectedItems()[0] == topItem assert novelView.getSelectedHandle() == (C.hTitlePage, "T0001") # Refresh using the slot for the button novelBar._refreshNovelTree() assert novelTree.topLevelItem(0).isSelected() # Open Items # ========== # Clear selection novelTree.clearSelection() scItem = novelTree.topLevelItem(2) scItem.setSelected(True) assert scItem.isSelected() # Clear selection with mouse vPort = novelTree.viewport() qtbot.mouseClick(vPort, QtMouseLeft, pos=vPort.rect().center(), delay=10) assert not scItem.isSelected() # Double-click item scItem.setSelected(True) assert scItem.isSelected() assert nwGUI.docEditor.docHandle is None novelTree._treeDoubleClick(scItem, 0) assert nwGUI.docEditor.docHandle == C.hSceneDoc # Open item with middle mouse button scItem.setSelected(True) assert scItem.isSelected() assert nwGUI.docViewer.docHandle is None qtbot.mouseClick(vPort, QtMouseMiddle, pos=vPort.rect().center(), delay=10) assert nwGUI.docViewer.docHandle is None scRect = novelTree.visualItemRect(scItem) oldData = scItem.data(novelTree.C_TITLE, novelTree.D_HANDLE) scItem.setData(novelTree.C_TITLE, novelTree.D_HANDLE, None) qtbot.mouseClick(vPort, QtMouseMiddle, pos=scRect.center(), delay=10) assert nwGUI.docViewer.docHandle is None scItem.setData(novelTree.C_TITLE, novelTree.D_HANDLE, oldData) qtbot.mouseClick(vPort, QtMouseMiddle, pos=scRect.center(), delay=10) assert nwGUI.docViewer.docHandle == C.hSceneDoc # Last Column # =========== novelBar.setLastColType(NovelTreeColumn.HIDDEN) assert novelTree.isColumnHidden(novelTree.C_EXTRA) is True assert novelTree.lastColType == NovelTreeColumn.HIDDEN assert novelTree._getLastColumnText(C.hSceneDoc, "T0001") == ("", "") novelBar.setLastColType(NovelTreeColumn.PLOT) assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False assert novelTree.lastColType == NovelTreeColumn.PLOT assert novelTree._getLastColumnText(C.hSceneDoc, "T0001") == ( "", "" ) novelBar.setLastColType(NovelTreeColumn.FOCUS) assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False assert novelTree.lastColType == NovelTreeColumn.FOCUS assert novelTree._getLastColumnText(C.hSceneDoc, "T0001") == ( "Jane", "Focus: Jane" ) novelBar.setLastColType(NovelTreeColumn.POV) assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False assert novelTree.lastColType == NovelTreeColumn.POV assert novelTree._getLastColumnText(C.hSceneDoc, "T0001") == ( "Jane", "Point of View: Jane" ) novelTree._lastCol = None assert novelTree._getLastColumnText("0000000000000", "T0000") == ("", "") # This forces the resizeEvent function to process labels spSize = nwGUI.splitMain.sizes() nwGUI.splitMain.setSizes([spSize[0] + 10, spSize[1] - 10]) # Resize the last column with monkeypatch.context() as mp: mp.setattr(QInputDialog, "getInt", lambda *a, **k: (40, True)) novelBar._selectLastColumnSize() # Item Meta # ========= ttText = "" def showText(pos, text): nonlocal ttText ttText = text mIndex = novelTree.model().index(2, novelTree.C_MORE) with monkeypatch.context() as mp: mp.setattr(QToolTip, "showText", showText) ttText = "" novelTree._treeItemClicked(mIndex) assert ttText == ( "

Point of View: Jane
Focus: Jane

" "

Synopsis: This is a scene.

" ) ttText = "" novelTree._popMetaBox(QPoint(1, 1), C.hInvalid, "T0001") assert ttText == "" # Set Default Root # ================ SHARED.project.data.setLastHandle(C.hInvalid, "novelTree") novelView.openProjectTasks() assert novelBar.novelValue.handle == C.hNovelRoot # Tree Focus # ========== with monkeypatch.context() as mp: mp.setattr(GuiNovelTree, "hasFocus", lambda *a: False) assert novelView.treeHasFocus() is False mp.setattr(GuiNovelTree, "hasFocus", lambda *a: True) assert novelView.treeHasFocus() is True # Other Checks # ============ scItem = novelTree.topLevelItem(2) scItem.setSelected(True) assert scItem.isSelected() novelTree.focusOutEvent(QFocusEvent(QEvent.Type.None_, Qt.FocusReason.MouseFocusReason)) assert not scItem.isSelected() # Close # ===== # qtbot.stop() nwGUI.closeProject()