From 325c8dc68d57dfefcb4641bed0255b2622be7c9a Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 12 Dec 2020 17:39:28 +0100
Subject: [PATCH] Split up the main gui test file
---
...=> guiEditor_Main_Final_031b4af5197ec.nwd} | 0
...=> guiEditor_Main_Final_0e17daca5f3e1.nwd} | 0
...=> guiEditor_Main_Final_1a6562590ef19.nwd} | 0
...=> guiEditor_Main_Final_41cfc0d1f2d12.nwd} | 0
...nwx => guiEditor_Main_Final_nwProject.nwx} | 0
...x => guiEditor_Main_Initial_nwProject.nwx} | 0
tests/test_gui_doceditor.py | 506 ++++++
tests/test_gui_docviewer.py | 165 ++
tests/test_gui_main.py | 1526 -----------------
tests/test_gui_mainmenu.py | 533 ++++++
tests/test_gui_outline.py | 73 +
tests/test_gui_projtree.py | 138 ++
tests/test_gui_theme.py | 170 ++
13 files changed, 1585 insertions(+), 1526 deletions(-)
rename tests/reference/{gui/1_031b4af5197ec.nwd => guiEditor_Main_Final_031b4af5197ec.nwd} (100%)
rename tests/reference/{gui/1_0e17daca5f3e1.nwd => guiEditor_Main_Final_0e17daca5f3e1.nwd} (100%)
rename tests/reference/{gui/1_1a6562590ef19.nwd => guiEditor_Main_Final_1a6562590ef19.nwd} (100%)
rename tests/reference/{gui/1_41cfc0d1f2d12.nwd => guiEditor_Main_Final_41cfc0d1f2d12.nwd} (100%)
rename tests/reference/{gui/1_nwProject.nwx => guiEditor_Main_Final_nwProject.nwx} (100%)
rename tests/reference/{gui/0_nwProject.nwx => guiEditor_Main_Initial_nwProject.nwx} (100%)
create mode 100644 tests/test_gui_doceditor.py
create mode 100644 tests/test_gui_docviewer.py
delete mode 100644 tests/test_gui_main.py
create mode 100644 tests/test_gui_mainmenu.py
create mode 100644 tests/test_gui_outline.py
create mode 100644 tests/test_gui_projtree.py
create mode 100644 tests/test_gui_theme.py
diff --git a/tests/reference/gui/1_031b4af5197ec.nwd b/tests/reference/guiEditor_Main_Final_031b4af5197ec.nwd
similarity index 100%
rename from tests/reference/gui/1_031b4af5197ec.nwd
rename to tests/reference/guiEditor_Main_Final_031b4af5197ec.nwd
diff --git a/tests/reference/gui/1_0e17daca5f3e1.nwd b/tests/reference/guiEditor_Main_Final_0e17daca5f3e1.nwd
similarity index 100%
rename from tests/reference/gui/1_0e17daca5f3e1.nwd
rename to tests/reference/guiEditor_Main_Final_0e17daca5f3e1.nwd
diff --git a/tests/reference/gui/1_1a6562590ef19.nwd b/tests/reference/guiEditor_Main_Final_1a6562590ef19.nwd
similarity index 100%
rename from tests/reference/gui/1_1a6562590ef19.nwd
rename to tests/reference/guiEditor_Main_Final_1a6562590ef19.nwd
diff --git a/tests/reference/gui/1_41cfc0d1f2d12.nwd b/tests/reference/guiEditor_Main_Final_41cfc0d1f2d12.nwd
similarity index 100%
rename from tests/reference/gui/1_41cfc0d1f2d12.nwd
rename to tests/reference/guiEditor_Main_Final_41cfc0d1f2d12.nwd
diff --git a/tests/reference/gui/1_nwProject.nwx b/tests/reference/guiEditor_Main_Final_nwProject.nwx
similarity index 100%
rename from tests/reference/gui/1_nwProject.nwx
rename to tests/reference/guiEditor_Main_Final_nwProject.nwx
diff --git a/tests/reference/gui/0_nwProject.nwx b/tests/reference/guiEditor_Main_Initial_nwProject.nwx
similarity index 100%
rename from tests/reference/gui/0_nwProject.nwx
rename to tests/reference/guiEditor_Main_Initial_nwProject.nwx
diff --git a/tests/test_gui_doceditor.py b/tests/test_gui_doceditor.py
new file mode 100644
index 00000000..5b09ca95
--- /dev/null
+++ b/tests/test_gui_doceditor.py
@@ -0,0 +1,506 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Main GUI Editor Class Tester
+"""
+
+import pytest
+import os
+
+from shutil import copyfile
+from tools import cmpFiles
+
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QTextCursor
+from PyQt5.QtWidgets import QAction, QMessageBox
+
+from nw.constants import nwItemType, nwDocAction
+
+keyDelay = 2
+typeDelay = 1
+stepDelay = 20
+
+@pytest.mark.gui
+def testGuiEditor_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, refDir, outDir):
+ """Test the document editor.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ # Create new, save, close project
+ nwGUI.theProject.projTree.setSeed(42)
+ assert nwGUI.newProject({"projPath": fncProj})
+ assert nwGUI.saveProject()
+ assert nwGUI.closeProject()
+
+ assert len(nwGUI.theProject.projTree) == 0
+ assert len(nwGUI.theProject.projTree._treeOrder) == 0
+ assert len(nwGUI.theProject.projTree._treeRoots) == 0
+ assert nwGUI.theProject.projTree.trashRoot() is None
+ assert nwGUI.theProject.projPath is None
+ assert nwGUI.theProject.projMeta is None
+ assert nwGUI.theProject.projFile == "nwProject.nwx"
+ assert nwGUI.theProject.projName == ""
+ assert nwGUI.theProject.bookTitle == ""
+ assert len(nwGUI.theProject.bookAuthors) == 0
+ assert not nwGUI.theProject.spellCheck
+
+ # Check the files
+ projFile = os.path.join(fncProj, "nwProject.nwx")
+ testFile = os.path.join(outDir, "guiEditor_Main_Initial_nwProject.nwx")
+ compFile = os.path.join(refDir, "guiEditor_Main_Initial_nwProject.nwx")
+ copyfile(projFile, testFile)
+ assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
+ qtbot.wait(stepDelay)
+
+ # qtbot.stopForInteraction()
+
+ # Re-open project
+ assert nwGUI.openProject(fncProj)
+ qtbot.wait(stepDelay)
+
+ # Check that we loaded the data
+ assert len(nwGUI.theProject.projTree) == 8
+ assert len(nwGUI.theProject.projTree._treeOrder) == 8
+ assert len(nwGUI.theProject.projTree._treeRoots) == 4
+ assert nwGUI.theProject.projTree.trashRoot() is None
+ assert nwGUI.theProject.projPath == fncProj
+ assert nwGUI.theProject.projMeta == os.path.join(fncProj, "meta")
+ assert nwGUI.theProject.projFile == "nwProject.nwx"
+ assert nwGUI.theProject.projName == "New Project"
+ assert nwGUI.theProject.bookTitle == ""
+ assert len(nwGUI.theProject.bookAuthors) == 0
+ assert not nwGUI.theProject.spellCheck
+
+ # Check that tree items have been created
+ assert nwGUI.treeView._getTreeItem("73475cb40a568") is not None
+ assert nwGUI.treeView._getTreeItem("25fc0e7096fc6") is not None
+ assert nwGUI.treeView._getTreeItem("31489056e0916") is not None
+ assert nwGUI.treeView._getTreeItem("98010bd9270f9") is not None
+ assert nwGUI.treeView._getTreeItem("0e17daca5f3e1") is not None
+ assert nwGUI.treeView._getTreeItem("44cb730c42048") is not None
+ assert nwGUI.treeView._getTreeItem("71ee45a3c0db9") is not None
+ assert nwGUI.treeView._getTreeItem("811786ad1ae74") is not None
+
+ nwGUI.mainMenu.aSpellCheck.setChecked(True)
+ assert nwGUI.mainMenu._toggleSpellCheck()
+
+ # Change some settings
+ nwGUI.mainConf.hideHScroll = True
+ nwGUI.mainConf.hideVScroll = True
+ nwGUI.mainConf.scrollPastEnd = True
+ nwGUI.mainConf.autoScrollPos = 80
+ nwGUI.mainConf.autoScroll = True
+
+ # Add a Character File
+ nwGUI.setFocus(1)
+ nwGUI.treeView.clearSelection()
+ nwGUI.treeView._getTreeItem("71ee45a3c0db9").setSelected(True)
+ nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ assert nwGUI.openSelectedItem()
+
+ # Type something into the document
+ nwGUI.setFocus(2)
+ qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay)
+ for c in "# Jane Doe":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "@tag: Jane":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "This is a file about Jane.":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ # Add a Plot File
+ nwGUI.setFocus(1)
+ nwGUI.treeView.clearSelection()
+ nwGUI.treeView._getTreeItem("44cb730c42048").setSelected(True)
+ nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ assert nwGUI.openSelectedItem()
+
+ # Type something into the document
+ nwGUI.setFocus(2)
+ qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay)
+ for c in "# Main Plot":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "@tag: MainPlot":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "This is a file detailing the main plot.":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ # Add a World File
+ nwGUI.setFocus(1)
+ nwGUI.treeView.clearSelection()
+ nwGUI.treeView._getTreeItem("811786ad1ae74").setSelected(True)
+ nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ assert nwGUI.openSelectedItem()
+
+ # Add Some Text
+ nwGUI.docEditor.replaceText("Hello World!")
+ assert nwGUI.docEditor.getText() == "Hello World!"
+ nwGUI.docEditor.replaceText("")
+
+ # Type something into the document
+ nwGUI.setFocus(2)
+ qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay)
+ for c in "# Main Location":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "@tag: Home":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "This is a file describing Jane's home.":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ # Trigger autosaves before making more changes
+ nwGUI._autoSaveDocument()
+ nwGUI._autoSaveProject()
+
+ # Select the 'New Scene' file
+ nwGUI.setFocus(1)
+ nwGUI.treeView.clearSelection()
+ nwGUI.treeView._getTreeItem("73475cb40a568").setExpanded(True)
+ nwGUI.treeView._getTreeItem("31489056e0916").setExpanded(True)
+ nwGUI.treeView._getTreeItem("0e17daca5f3e1").setSelected(True)
+ assert nwGUI.openSelectedItem()
+
+ # Type something into the document
+ nwGUI.setFocus(2)
+ qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay)
+ for c in "# Novel":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "## Chapter":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "@pov: Jane":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "@plot: MainPlot":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "### Scene":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "% How about a comment?":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "@pov: Jane":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "@plot: MainPlot":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ for c in "@location: Home":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "#### Some Section":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "@char: Jane":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "This is a paragraph of dummy text.":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in (
+ "This is another paragraph of much longer dummy text. "
+ "It is in fact very very dumb dummy text! "
+ ):
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ for c in "We can also try replacing \"quotes\", even single 'quotes' are replaced. ":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ for c in "Isn't that nice? ":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ for c in "We can hyphen-ate, make dashes -- and even longer dashes --- if we want. ":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ for c in "Ellipsis? Not a problem either ... ":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ for c in "How about three hyphens - -":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Left, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Backspace, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Right, delay=keyDelay)
+ for c in "- for long dash? It works too.":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "\"Full line double quoted text.\"":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ for c in "'Full line single quoted text.'":
+ qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+ qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
+
+ qtbot.wait(stepDelay)
+ nwGUI.docEditor.wCounter.run()
+ qtbot.wait(stepDelay)
+
+ # Save the document
+ assert nwGUI.docEditor.docChanged
+ assert nwGUI.saveDocument()
+ assert not nwGUI.docEditor.docChanged
+ qtbot.wait(stepDelay)
+ nwGUI.rebuildIndex()
+ qtbot.wait(stepDelay)
+
+ # Open and view the edited document
+ nwGUI.setFocus(3)
+ assert nwGUI.openDocument("0e17daca5f3e1")
+ assert nwGUI.viewDocument("0e17daca5f3e1")
+ qtbot.wait(stepDelay)
+ assert nwGUI.saveProject()
+ assert nwGUI.closeDocViewer()
+ qtbot.wait(stepDelay)
+
+ # Check a Quick Create and Delete
+ assert nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ newHandle = nwGUI.treeView.getSelectedHandle()
+ assert nwGUI.theProject.projTree["2858dcd1057d3"] is not None
+ assert nwGUI.treeView.deleteItem()
+ assert nwGUI.treeView.setSelectedHandle(newHandle)
+ assert nwGUI.treeView.deleteItem()
+ assert nwGUI.theProject.projTree["2fca346db6561"] is not None # Trash
+ assert nwGUI.saveProject()
+
+ # Check the files
+ projFile = os.path.join(fncProj, "nwProject.nwx")
+ testFile = os.path.join(outDir, "guiEditor_Main_Final_nwProject.nwx")
+ compFile = os.path.join(refDir, "guiEditor_Main_Final_nwProject.nwx")
+ copyfile(projFile, testFile)
+ assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
+
+ projFile = os.path.join(fncProj, "content", "031b4af5197ec.nwd")
+ testFile = os.path.join(outDir, "guiEditor_Main_Final_031b4af5197ec.nwd")
+ compFile = os.path.join(refDir, "guiEditor_Main_Final_031b4af5197ec.nwd")
+ copyfile(projFile, testFile)
+ assert cmpFiles(testFile, compFile)
+
+ projFile = os.path.join(fncProj, "content", "1a6562590ef19.nwd")
+ testFile = os.path.join(outDir, "guiEditor_Main_Final_1a6562590ef19.nwd")
+ compFile = os.path.join(refDir, "guiEditor_Main_Final_1a6562590ef19.nwd")
+ copyfile(projFile, testFile)
+ assert cmpFiles(testFile, compFile)
+
+ projFile = os.path.join(fncProj, "content", "0e17daca5f3e1.nwd")
+ testFile = os.path.join(outDir, "guiEditor_Main_Final_0e17daca5f3e1.nwd")
+ compFile = os.path.join(refDir, "guiEditor_Main_Final_0e17daca5f3e1.nwd")
+ copyfile(projFile, testFile)
+ assert cmpFiles(testFile, compFile)
+
+ projFile = os.path.join(fncProj, "content", "41cfc0d1f2d12.nwd")
+ testFile = os.path.join(outDir, "guiEditor_Main_Final_41cfc0d1f2d12.nwd")
+ compFile = os.path.join(refDir, "guiEditor_Main_Final_41cfc0d1f2d12.nwd")
+ copyfile(projFile, testFile)
+ assert cmpFiles(testFile, compFile)
+
+ # qtbot.stopForInteraction()
+
+# END Test testGuiEditor_Main
+
+@pytest.mark.gui
+def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
+ """Test the document editor search functionality.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ nwGUI.theProject.projTree.setSeed(42)
+ assert nwGUI.openProject(nwLipsum)
+ assert nwGUI.openDocument("4c4f28287af27")
+ origText = nwGUI.docEditor.getText()
+ qtbot.wait(stepDelay)
+
+ # Select the Word "est"
+ assert nwGUI.docEditor.setCursorPosition(618)
+ nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
+ theCursor = nwGUI.docEditor.textCursor()
+ assert theCursor.selectedText() == "est"
+
+ # Activate Search
+ nwGUI.mainMenu.aFind.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.isVisible()
+ assert nwGUI.docEditor.docSearch.getSearchText() == "est"
+
+ # Find Next by Enter
+ monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True)
+ qtbot.keyClick(nwGUI.docEditor.docSearch.searchBox, Qt.Key_Return, delay=keyDelay)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 1272) < 3
+
+ # Find Next by Button
+ qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 1486) < 3
+
+ # Activate Loop Search
+ nwGUI.docEditor.docSearch.toggleLoop.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.toggleLoop.isChecked()
+ assert nwGUI.docEditor.docSearch.doLoop
+
+ # Find Next by Menu Search > Find Next
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
+
+ # Close Search
+ nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
+ assert not nwGUI.docEditor.docSearch.isVisible()
+ assert nwGUI.docEditor.setCursorPosition(15)
+
+ # Toggle Search Again with Header Button
+ qtbot.mouseClick(nwGUI.docEditor.docHeader.searchButton, Qt.LeftButton, delay=keyDelay)
+ assert nwGUI.docEditor.docSearch.setSearchText("")
+ assert nwGUI.docEditor.docSearch.isVisible()
+
+ # Enable RegEx Search
+ nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.toggleRegEx.isChecked()
+ assert nwGUI.docEditor.docSearch.isRegEx
+
+ # Set Invalid RegEx
+ assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus[")
+ qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
+ assert nwGUI.docEditor.getCursorPosition() < 3 # No result
+
+ # Set Valid RegEx
+ assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus")
+ qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 196) < 3
+
+ # Find Next and then Prev
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 297) < 3
+ nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 196) < 3
+
+ # Make RegEx Case Sensitive
+ nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.toggleCase.isChecked()
+ assert nwGUI.docEditor.docSearch.isCaseSense
+
+ # Find Next (One Result)
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 599) < 3
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 599) < 3
+
+ # Trigger Replace
+ nwGUI.mainMenu.aReplace.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.setReplaceText("foo")
+
+ # Disable RegEx Case Sensitive
+ nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger)
+ assert not nwGUI.docEditor.docSearch.toggleCase.isChecked()
+ assert not nwGUI.docEditor.docSearch.isCaseSense
+
+ # Toggle Replace Preserve Case
+ nwGUI.docEditor.docSearch.toggleMatchCap.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.toggleMatchCap.isChecked()
+ assert nwGUI.docEditor.docSearch.doMatchCap
+
+ # Replace "Sus" with "Foo" via Menu
+ nwGUI.mainMenu.aReplaceNext.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[596:607] == "Foopendisse"
+
+ # Find Next to Loop File
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+
+ # Replace "sus" with "foo" via Replace Button
+ qtbot.mouseClick(nwGUI.docEditor.docSearch.replaceButton, Qt.LeftButton, delay=keyDelay)
+ assert nwGUI.docEditor.getText()[193:201] == "foocipit"
+
+ # Revert Last Two Replaces
+ assert nwGUI.docEditor.docAction(nwDocAction.UNDO)
+ assert nwGUI.docEditor.docAction(nwDocAction.UNDO)
+ assert nwGUI.docEditor.getText() == origText
+
+ # Disable RegEx Search
+ nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger)
+ assert not nwGUI.docEditor.docSearch.toggleRegEx.isChecked()
+ assert not nwGUI.docEditor.docSearch.isRegEx
+
+ # Close Search and Select "est" Again
+ nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
+ assert nwGUI.docEditor.setCursorPosition(618)
+ nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
+ theCursor = nwGUI.docEditor.textCursor()
+ assert theCursor.selectedText() == "est"
+
+ # Activate Search Again
+ nwGUI.mainMenu.aFind.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.isVisible()
+ assert nwGUI.docEditor.docSearch.getSearchText() == "est"
+
+ # Enable Full Word Search
+ nwGUI.docEditor.docSearch.toggleWord.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.toggleWord.isChecked()
+ assert nwGUI.docEditor.docSearch.isWholeWord
+
+ # Only One Match
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
+
+ # Enable Next Doc Search
+ nwGUI.docEditor.docSearch.toggleProject.activate(QAction.Trigger)
+ assert nwGUI.docEditor.docSearch.toggleProject.isChecked()
+ assert nwGUI.docEditor.docSearch.doNextFile
+
+ # Next Match
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert nwGUI.docEditor.theHandle == "2426c6f0ca922" # Next document
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
+ nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
+ assert abs(nwGUI.docEditor.getCursorPosition() - 1127) < 3
+
+ # Toggle Replace
+ nwGUI.docEditor._beginReplace()
+
+ # MonkeyPatch the focus cycle. We can't really test this very well, other than
+ # check that the tabs aren't captured when the main editor has focus
+ monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: True)
+ monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False)
+ monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False)
+ assert not nwGUI.docEditor.focusNextPrevChild(True)
+
+ monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: False)
+ monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True)
+ monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False)
+ assert nwGUI.docEditor.focusNextPrevChild(True)
+
+ monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False)
+ monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: True)
+ assert nwGUI.docEditor.focusNextPrevChild(True)
+
+ # qtbot.stopForInteraction()
+
+# END Test testGuiEditor_Search
diff --git a/tests/test_gui_docviewer.py b/tests/test_gui_docviewer.py
new file mode 100644
index 00000000..3af74afa
--- /dev/null
+++ b/tests/test_gui_docviewer.py
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Main GUI Viewer Class Tester
+"""
+
+import pytest
+
+from PyQt5.QtCore import Qt, QUrl
+from PyQt5.QtGui import QTextCursor
+from PyQt5.QtWidgets import qApp, QAction, QMessageBox
+
+from nw.constants import nwDocAction
+
+keyDelay = 2
+typeDelay = 1
+stepDelay = 20
+
+@pytest.mark.gui
+def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
+ """Test the document viewer.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ # Open project
+ nwGUI.theProject.projTree.setSeed(42)
+ assert nwGUI.openProject(nwLipsum)
+
+ # Rebuild the index as it isn't automatically copied
+ assert nwGUI.theIndex.tagIndex == {}
+ assert nwGUI.theIndex.refIndex == {}
+ nwGUI.mainMenu.aRebuildIndex.activate(QAction.Trigger)
+ assert nwGUI.theIndex.tagIndex != {}
+ assert nwGUI.theIndex.refIndex != {}
+
+ # Select a document in the project tree
+ assert nwGUI.treeView.setSelectedHandle("88243afbe5ed8")
+
+ # Middle-click the selected item
+ theItem = nwGUI.treeView._getTreeItem("88243afbe5ed8")
+ theRect = nwGUI.treeView.visualItemRect(theItem)
+ qtbot.mouseClick(nwGUI.treeView.viewport(), Qt.MidButton, pos=theRect.center())
+ assert nwGUI.docViewer.theHandle == "88243afbe5ed8"
+
+ # Reload the text
+ origText = nwGUI.docViewer.toPlainText()
+ nwGUI.docViewer.setPlainText("Oops, all gone!")
+ nwGUI.docViewer.docHeader._refreshDocument()
+ assert nwGUI.docViewer.toPlainText() == origText
+
+ # Cursor line
+ assert not nwGUI.docViewer.setCursorLine("not a number")
+ assert nwGUI.docViewer.setCursorLine(3)
+ theCursor = nwGUI.docViewer.textCursor()
+ assert theCursor.position() == 40
+
+ # Cursor position
+ assert not nwGUI.docViewer.setCursorPosition("not a number")
+ assert nwGUI.docViewer.setCursorPosition(100)
+
+ # Select word
+ nwGUI.docViewer._makeSelection(QTextCursor.WordUnderCursor)
+
+ qClip = qApp.clipboard()
+ qClip.clear()
+
+ # Cut
+ assert nwGUI.docViewer.docAction(nwDocAction.CUT)
+ assert qClip.text() == "laoreet"
+ qClip.clear()
+
+ # Copy
+ assert nwGUI.docViewer.docAction(nwDocAction.COPY)
+ assert qClip.text() == "laoreet"
+ qClip.clear()
+
+ # Select Paragraph
+ assert nwGUI.docViewer.docAction(nwDocAction.SEL_PARA)
+ theCursor = nwGUI.docViewer.textCursor()
+ assert theCursor.selectedText() == (
+ "Synopsis: Aenean ut placerat velit. Etiam laoreet ullamcorper risus, "
+ "eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et "
+ "mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. "
+ "Etiam finibus nisi vel mi molestie consectetur."
+ )
+
+ # Select All
+ assert nwGUI.docViewer.docAction(nwDocAction.SEL_ALL)
+ theCursor = nwGUI.docViewer.textCursor()
+ assert len(theCursor.selectedText()) == 3061
+
+ # Other actions
+ assert not nwGUI.docViewer.docAction(nwDocAction.NO_ACTION)
+
+ # Close document
+ nwGUI.docViewer.docHeader._closeDocument()
+ assert nwGUI.docViewer.theHandle is None
+
+ # Action on no document
+ assert not nwGUI.docViewer.docAction(nwDocAction.COPY)
+
+ # Open again via menu
+ assert nwGUI.treeView.setSelectedHandle("88243afbe5ed8")
+ nwGUI.mainMenu.aViewDoc.activate(QAction.Trigger)
+
+ # Select "Bod" link
+ assert nwGUI.docViewer.setCursorPosition(27)
+ nwGUI.docViewer._makeSelection(QTextCursor.WordUnderCursor)
+ theRect = nwGUI.docViewer.cursorRect()
+ # qtbot.mouseClick(nwGUI.docViewer.viewport(), Qt.LeftButton, pos=theRect.center(), delay=100)
+ nwGUI.docViewer._linkClicked(QUrl("#char=Bod"))
+ assert nwGUI.docViewer.theHandle == "4c4f28287af27"
+
+ # Click mouse nav buttons
+ qtbot.mouseClick(nwGUI.docViewer.viewport(), Qt.BackButton, pos=theRect.center(), delay=100)
+ assert nwGUI.docViewer.theHandle == "88243afbe5ed8"
+ qtbot.mouseClick(nwGUI.docViewer.viewport(), Qt.ForwardButton, pos=theRect.center(), delay=100)
+ assert nwGUI.docViewer.theHandle == "4c4f28287af27"
+
+ # Scroll bar default on empty document
+ nwGUI.docViewer.clear()
+ assert nwGUI.docViewer.getScrollPosition() == 0
+ nwGUI.docViewer.reloadText()
+
+ # Change document title
+ nwItem = nwGUI.theProject.projTree["4c4f28287af27"]
+ nwItem.setName("Test Title")
+ assert nwItem.itemName == "Test Title"
+ nwGUI.docViewer.updateDocInfo("4c4f28287af27")
+ assert nwGUI.docViewer.docHeader.theTitle.text() == "Characters › Test Title"
+
+ # Ttile without full path
+ nwGUI.mainConf.showFullPath = False
+ nwGUI.docViewer.updateDocInfo("4c4f28287af27")
+ assert nwGUI.docViewer.docHeader.theTitle.text() == "Test Title"
+ nwGUI.mainConf.showFullPath = True
+
+ # Document footer show/hide references
+ viewState = nwGUI.viewMeta.isVisible()
+ nwGUI.docViewer.docFooter._doShowHide()
+ assert nwGUI.viewMeta.isVisible() is not viewState
+ nwGUI.docViewer.docFooter._doShowHide()
+ assert nwGUI.viewMeta.isVisible() is viewState
+
+ # Document footer sticky
+ viewState = nwGUI.docViewer.stickyRef
+ nwGUI.docViewer.docFooter._doToggleSticky(not viewState)
+ assert nwGUI.docViewer.stickyRef is not viewState
+ nwGUI.docViewer.docFooter._doToggleSticky(viewState)
+ assert nwGUI.docViewer.stickyRef is viewState
+
+ # Document footer show/hide synopsis
+ assert nwGUI.viewDocument("f96ec11c6a3da")
+ assert len(nwGUI.docViewer.toPlainText()) == 4315
+ nwGUI.docViewer.docFooter._doToggleSynopsis(False)
+ assert len(nwGUI.docViewer.toPlainText()) == 4099
+
+ # Document footer show/hide comments
+ assert nwGUI.viewDocument("846352075de7d")
+ assert len(nwGUI.docViewer.toPlainText()) == 675
+ nwGUI.docViewer.docFooter._doToggleComments(False)
+ assert len(nwGUI.docViewer.toPlainText()) == 635
+
+ # qtbot.stopForInteraction()
+
+# END Test testGuiViewer_Main
diff --git a/tests/test_gui_main.py b/tests/test_gui_main.py
deleted file mode 100644
index b56c525b..00000000
--- a/tests/test_gui_main.py
+++ /dev/null
@@ -1,1526 +0,0 @@
-# -*- coding: utf-8 -*-
-"""novelWriter Main GUI Class Tester
-"""
-
-import nw
-import pytest
-import os
-
-from shutil import copyfile
-from tools import cmpFiles
-
-from PyQt5.QtCore import Qt, QUrl, QPoint, QItemSelectionModel
-from PyQt5.QtGui import QTextCursor, QColor, QPixmap, QIcon, QTextBlock
-from PyQt5.QtWidgets import (
- qApp, QAction, QTreeWidgetItem, QStyle, QFileDialog, QMessageBox
-)
-
-from nw.constants import (
- nwItemType, nwItemClass, nwUnicode, nwOutline, nwDocAction, nwDocInsert,
- nwKeyWords
-)
-
-keyDelay = 2
-typeDelay = 1
-stepDelay = 20
-
-@pytest.mark.gui
-def testDocEditor(qtbot, yesToAll, fncDir, nwTempGUI, refDir, tmpDir):
-
- nwGUI = nw.main(["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(stepDelay)
-
- # Create new, save, close project
- nwGUI.theProject.projTree.setSeed(42)
- assert nwGUI.newProject({"projPath": fncDir})
- assert nwGUI.saveProject()
- assert nwGUI.closeProject()
-
- assert len(nwGUI.theProject.projTree) == 0
- assert len(nwGUI.theProject.projTree._treeOrder) == 0
- assert len(nwGUI.theProject.projTree._treeRoots) == 0
- assert nwGUI.theProject.projTree.trashRoot() is None
- assert nwGUI.theProject.projPath is None
- assert nwGUI.theProject.projMeta is None
- assert nwGUI.theProject.projFile == "nwProject.nwx"
- assert nwGUI.theProject.projName == ""
- assert nwGUI.theProject.bookTitle == ""
- assert len(nwGUI.theProject.bookAuthors) == 0
- assert not nwGUI.theProject.spellCheck
-
- # Check the files
- projFile = os.path.join(fncDir, "nwProject.nwx")
- testFile = os.path.join(nwTempGUI, "0_nwProject.nwx")
- refFile = os.path.join(refDir, "gui", "0_nwProject.nwx")
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, refFile, [2, 6, 7, 8])
- qtbot.wait(stepDelay)
-
- # qtbot.stopForInteraction()
-
- # Re-open project
- assert nwGUI.openProject(fncDir)
- qtbot.wait(stepDelay)
-
- # Check that we loaded the data
- assert len(nwGUI.theProject.projTree) == 8
- assert len(nwGUI.theProject.projTree._treeOrder) == 8
- assert len(nwGUI.theProject.projTree._treeRoots) == 4
- assert nwGUI.theProject.projTree.trashRoot() is None
- assert nwGUI.theProject.projPath == fncDir
- assert nwGUI.theProject.projMeta == os.path.join(fncDir, "meta")
- assert nwGUI.theProject.projFile == "nwProject.nwx"
- assert nwGUI.theProject.projName == "New Project"
- assert nwGUI.theProject.bookTitle == ""
- assert len(nwGUI.theProject.bookAuthors) == 0
- assert not nwGUI.theProject.spellCheck
-
- # Check that tree items have been created
- assert nwGUI.treeView._getTreeItem("73475cb40a568") is not None
- assert nwGUI.treeView._getTreeItem("25fc0e7096fc6") is not None
- assert nwGUI.treeView._getTreeItem("31489056e0916") is not None
- assert nwGUI.treeView._getTreeItem("98010bd9270f9") is not None
- assert nwGUI.treeView._getTreeItem("0e17daca5f3e1") is not None
- assert nwGUI.treeView._getTreeItem("44cb730c42048") is not None
- assert nwGUI.treeView._getTreeItem("71ee45a3c0db9") is not None
- assert nwGUI.treeView._getTreeItem("811786ad1ae74") is not None
-
- nwGUI.mainMenu.aSpellCheck.setChecked(True)
- assert nwGUI.mainMenu._toggleSpellCheck()
-
- # Change some settings
- nwGUI.mainConf.hideHScroll = True
- nwGUI.mainConf.hideVScroll = True
- nwGUI.mainConf.scrollPastEnd = True
- nwGUI.mainConf.autoScrollPos = 80
- nwGUI.mainConf.autoScroll = True
-
- # Add a Character File
- nwGUI.setFocus(1)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("71ee45a3c0db9").setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
- assert nwGUI.openSelectedItem()
-
- # Type something into the document
- nwGUI.setFocus(2)
- qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay)
- for c in "# Jane Doe":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "@tag: Jane":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "This is a file about Jane.":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- # Add a Plot File
- nwGUI.setFocus(1)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("44cb730c42048").setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
- assert nwGUI.openSelectedItem()
-
- # Type something into the document
- nwGUI.setFocus(2)
- qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay)
- for c in "# Main Plot":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "@tag: MainPlot":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "This is a file detailing the main plot.":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- # Add a World File
- nwGUI.setFocus(1)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("811786ad1ae74").setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
- assert nwGUI.openSelectedItem()
-
- # Add Some Text
- nwGUI.docEditor.replaceText("Hello World!")
- assert nwGUI.docEditor.getText() == "Hello World!"
- nwGUI.docEditor.replaceText("")
-
- # Type something into the document
- nwGUI.setFocus(2)
- qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay)
- for c in "# Main Location":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "@tag: Home":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "This is a file describing Jane's home.":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- # Trigger autosaves before making more changes
- nwGUI._autoSaveDocument()
- nwGUI._autoSaveProject()
-
- # Select the 'New Scene' file
- nwGUI.setFocus(1)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("73475cb40a568").setExpanded(True)
- nwGUI.treeView._getTreeItem("31489056e0916").setExpanded(True)
- nwGUI.treeView._getTreeItem("0e17daca5f3e1").setSelected(True)
- assert nwGUI.openSelectedItem()
-
- # Type something into the document
- nwGUI.setFocus(2)
- qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay)
- for c in "# Novel":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "## Chapter":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "@pov: Jane":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "@plot: MainPlot":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "### Scene":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "% How about a comment?":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "@pov: Jane":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "@plot: MainPlot":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- for c in "@location: Home":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "#### Some Section":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "@char: Jane":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "This is a paragraph of dummy text.":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in (
- "This is another paragraph of much longer dummy text. "
- "It is in fact very very dumb dummy text! "
- ):
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- for c in "We can also try replacing \"quotes\", even single 'quotes' are replaced. ":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- for c in "Isn't that nice? ":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- for c in "We can hyphen-ate, make dashes -- and even longer dashes --- if we want. ":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- for c in "Ellipsis? Not a problem either ... ":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- for c in "How about three hyphens - -":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Left, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Backspace, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Right, delay=keyDelay)
- for c in "- for long dash? It works too.":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "\"Full line double quoted text.\"":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- for c in "'Full line single quoted text.'":
- qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
- qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
-
- qtbot.wait(stepDelay)
- nwGUI.docEditor.wCounter.run()
- qtbot.wait(stepDelay)
-
- # Save the document
- assert nwGUI.docEditor.docChanged
- assert nwGUI.saveDocument()
- assert not nwGUI.docEditor.docChanged
- qtbot.wait(stepDelay)
- nwGUI.rebuildIndex()
- qtbot.wait(stepDelay)
-
- # Open and view the edited document
- nwGUI.setFocus(3)
- assert nwGUI.openDocument("0e17daca5f3e1")
- assert nwGUI.viewDocument("0e17daca5f3e1")
- qtbot.wait(stepDelay)
- assert nwGUI.saveProject()
- assert nwGUI.closeDocViewer()
- qtbot.wait(stepDelay)
-
- # Check a Quick Create and Delete
- assert nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
- newHandle = nwGUI.treeView.getSelectedHandle()
- assert nwGUI.theProject.projTree["2858dcd1057d3"] is not None
- assert nwGUI.treeView.deleteItem()
- assert nwGUI.treeView.setSelectedHandle(newHandle)
- assert nwGUI.treeView.deleteItem()
- assert nwGUI.theProject.projTree["2fca346db6561"] is not None # Trash
- assert nwGUI.saveProject()
-
- # Check the files
- projFile = os.path.join(fncDir, "nwProject.nwx")
- testFile = os.path.join(nwTempGUI, "1_nwProject.nwx")
- refFile = os.path.join(refDir, "gui", "1_nwProject.nwx")
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, refFile, [2, 6, 7, 8])
-
- projFile = os.path.join(fncDir, "content", "031b4af5197ec.nwd")
- testFile = os.path.join(nwTempGUI, "1_031b4af5197ec.nwd")
- refFile = os.path.join(refDir, "gui", "1_031b4af5197ec.nwd")
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, refFile)
-
- projFile = os.path.join(fncDir, "content", "1a6562590ef19.nwd")
- testFile = os.path.join(nwTempGUI, "1_1a6562590ef19.nwd")
- refFile = os.path.join(refDir, "gui", "1_1a6562590ef19.nwd")
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, refFile)
-
- projFile = os.path.join(fncDir, "content", "0e17daca5f3e1.nwd")
- testFile = os.path.join(nwTempGUI, "1_0e17daca5f3e1.nwd")
- refFile = os.path.join(refDir, "gui", "1_0e17daca5f3e1.nwd")
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, refFile)
-
- projFile = os.path.join(fncDir, "content", "41cfc0d1f2d12.nwd")
- testFile = os.path.join(nwTempGUI, "1_41cfc0d1f2d12.nwd")
- refFile = os.path.join(refDir, "gui", "1_41cfc0d1f2d12.nwd")
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, refFile)
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
-
-@pytest.mark.gui
-def testDocViewer(qtbot, yesToAll, nwLipsum, tmpDir):
-
- nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % tmpDir])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(stepDelay)
-
- # Open project
- nwGUI.theProject.projTree.setSeed(42)
- assert nwGUI.openProject(nwLipsum)
-
- # Rebuild the index as it isn't automatically copied
- assert nwGUI.theIndex.tagIndex == {}
- assert nwGUI.theIndex.refIndex == {}
- nwGUI.mainMenu.aRebuildIndex.activate(QAction.Trigger)
- assert nwGUI.theIndex.tagIndex != {}
- assert nwGUI.theIndex.refIndex != {}
-
- # Select a document in the project tree
- assert nwGUI.treeView.setSelectedHandle("88243afbe5ed8")
-
- # Middle-click the selected item
- theItem = nwGUI.treeView._getTreeItem("88243afbe5ed8")
- theRect = nwGUI.treeView.visualItemRect(theItem)
- qtbot.mouseClick(nwGUI.treeView.viewport(), Qt.MidButton, pos=theRect.center())
- assert nwGUI.docViewer.theHandle == "88243afbe5ed8"
-
- # Reload the text
- origText = nwGUI.docViewer.toPlainText()
- nwGUI.docViewer.setPlainText("Oops, all gone!")
- nwGUI.docViewer.docHeader._refreshDocument()
- assert nwGUI.docViewer.toPlainText() == origText
-
- # Cursor line
- assert not nwGUI.docViewer.setCursorLine("not a number")
- assert nwGUI.docViewer.setCursorLine(3)
- theCursor = nwGUI.docViewer.textCursor()
- assert theCursor.position() == 40
-
- # Cursor position
- assert not nwGUI.docViewer.setCursorPosition("not a number")
- assert nwGUI.docViewer.setCursorPosition(100)
-
- # Select word
- nwGUI.docViewer._makeSelection(QTextCursor.WordUnderCursor)
-
- qClip = qApp.clipboard()
- qClip.clear()
-
- # Cut
- assert nwGUI.docViewer.docAction(nwDocAction.CUT)
- assert qClip.text() == "laoreet"
- qClip.clear()
-
- # Copy
- assert nwGUI.docViewer.docAction(nwDocAction.COPY)
- assert qClip.text() == "laoreet"
- qClip.clear()
-
- # Select Paragraph
- assert nwGUI.docViewer.docAction(nwDocAction.SEL_PARA)
- theCursor = nwGUI.docViewer.textCursor()
- assert theCursor.selectedText() == (
- "Synopsis: Aenean ut placerat velit. Etiam laoreet ullamcorper risus, "
- "eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et "
- "mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. "
- "Etiam finibus nisi vel mi molestie consectetur."
- )
-
- # Select All
- assert nwGUI.docViewer.docAction(nwDocAction.SEL_ALL)
- theCursor = nwGUI.docViewer.textCursor()
- assert len(theCursor.selectedText()) == 3061
-
- # Other actions
- assert not nwGUI.docViewer.docAction(nwDocAction.NO_ACTION)
-
- # Close document
- nwGUI.docViewer.docHeader._closeDocument()
- assert nwGUI.docViewer.theHandle is None
-
- # Action on no document
- assert not nwGUI.docViewer.docAction(nwDocAction.COPY)
-
- # Open again via menu
- assert nwGUI.treeView.setSelectedHandle("88243afbe5ed8")
- nwGUI.mainMenu.aViewDoc.activate(QAction.Trigger)
-
- # Select "Bod" link
- assert nwGUI.docViewer.setCursorPosition(27)
- nwGUI.docViewer._makeSelection(QTextCursor.WordUnderCursor)
- theRect = nwGUI.docViewer.cursorRect()
- # qtbot.mouseClick(nwGUI.docViewer.viewport(), Qt.LeftButton, pos=theRect.center(), delay=100)
- nwGUI.docViewer._linkClicked(QUrl("#char=Bod"))
- assert nwGUI.docViewer.theHandle == "4c4f28287af27"
-
- # Click mouse nav buttons
- qtbot.mouseClick(nwGUI.docViewer.viewport(), Qt.BackButton, pos=theRect.center(), delay=100)
- assert nwGUI.docViewer.theHandle == "88243afbe5ed8"
- qtbot.mouseClick(nwGUI.docViewer.viewport(), Qt.ForwardButton, pos=theRect.center(), delay=100)
- assert nwGUI.docViewer.theHandle == "4c4f28287af27"
-
- # Scroll bar default on empty document
- nwGUI.docViewer.clear()
- assert nwGUI.docViewer.getScrollPosition() == 0
- nwGUI.docViewer.reloadText()
-
- # Change document title
- nwItem = nwGUI.theProject.projTree["4c4f28287af27"]
- nwItem.setName("Test Title")
- assert nwItem.itemName == "Test Title"
- nwGUI.docViewer.updateDocInfo("4c4f28287af27")
- assert nwGUI.docViewer.docHeader.theTitle.text() == "Characters › Test Title"
-
- # Ttile without full path
- nwGUI.mainConf.showFullPath = False
- nwGUI.docViewer.updateDocInfo("4c4f28287af27")
- assert nwGUI.docViewer.docHeader.theTitle.text() == "Test Title"
- nwGUI.mainConf.showFullPath = True
-
- # Document footer show/hide references
- viewState = nwGUI.viewMeta.isVisible()
- nwGUI.docViewer.docFooter._doShowHide()
- assert nwGUI.viewMeta.isVisible() is not viewState
- nwGUI.docViewer.docFooter._doShowHide()
- assert nwGUI.viewMeta.isVisible() is viewState
-
- # Document footer sticky
- viewState = nwGUI.docViewer.stickyRef
- nwGUI.docViewer.docFooter._doToggleSticky(not viewState)
- assert nwGUI.docViewer.stickyRef is not viewState
- nwGUI.docViewer.docFooter._doToggleSticky(viewState)
- assert nwGUI.docViewer.stickyRef is viewState
-
- # Document footer show/hide synopsis
- assert nwGUI.viewDocument("f96ec11c6a3da")
- assert len(nwGUI.docViewer.toPlainText()) == 4315
- nwGUI.docViewer.docFooter._doToggleSynopsis(False)
- assert len(nwGUI.docViewer.toPlainText()) == 4099
-
- # Document footer show/hide comments
- assert nwGUI.viewDocument("846352075de7d")
- assert len(nwGUI.docViewer.toPlainText()) == 675
- nwGUI.docViewer.docFooter._doToggleComments(False)
- assert len(nwGUI.docViewer.toPlainText()) == 635
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
-
-@pytest.mark.gui
-def testProjectTree(qtbot, yesToAll, nwMinimal, tmpDir):
-
- nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(stepDelay)
-
- nwGUI.theProject.projTree.setSeed(42)
- nwTree = nwGUI.treeView
-
- # No location selected for new item
- assert not nwTree.newTreeItem(nwItemType.FILE, None)
- assert not nwTree.newTreeItem(nwItemType.FOLDER, None)
-
- # Select a location
- chItem = nwTree._getTreeItem("a6d311a93600a")
- nwTree.setCurrentItem(chItem, QItemSelectionModel.Current)
- chItem.setExpanded(True)
-
- # Create new item with no class set
- assert nwTree.newTreeItem(nwItemType.FILE, None)
- assert nwTree.newTreeItem(nwItemType.FOLDER, None)
-
- # Add roots
- assert not nwTree.newTreeItem(nwItemType.ROOT, None) # Defaults to NOVEL
- assert not nwTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) # Duplicate
- assert nwTree.newTreeItem(nwItemType.ROOT, nwItemClass.CUSTOM) # Valid
-
- # Check that we have the correct tree order
- assert nwTree.getTreeFromHandle("a6d311a93600a") == [
- "a6d311a93600a", "f5ab3e30151e1", "8c659a11cd429", "73475cb40a568", "44cb730c42048"
- ]
-
- # Move second item up twice (should give same result)
- nwTree.setSelectedHandle("8c659a11cd429")
- nwGUI.mainMenu.aMoveUp.activate(QAction.Trigger)
- assert nwTree.getTreeFromHandle("a6d311a93600a") == [
- "a6d311a93600a", "8c659a11cd429", "f5ab3e30151e1", "73475cb40a568", "44cb730c42048"
- ]
- nwGUI.mainMenu.aMoveUp.activate(QAction.Trigger)
- assert nwTree.getTreeFromHandle("a6d311a93600a") == [
- "a6d311a93600a", "8c659a11cd429", "f5ab3e30151e1", "73475cb40a568", "44cb730c42048"
- ]
-
- # Move it back down four times (last to should be the same)
- nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
- assert nwTree.getTreeFromHandle("a6d311a93600a") == [
- "a6d311a93600a", "f5ab3e30151e1", "8c659a11cd429", "73475cb40a568", "44cb730c42048"
- ]
- nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
- assert nwTree.getTreeFromHandle("a6d311a93600a") == [
- "a6d311a93600a", "f5ab3e30151e1", "73475cb40a568", "8c659a11cd429", "44cb730c42048"
- ]
- nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
- assert nwTree.getTreeFromHandle("a6d311a93600a") == [
- "a6d311a93600a", "f5ab3e30151e1", "73475cb40a568", "44cb730c42048", "8c659a11cd429"
- ]
- nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
- assert nwTree.getTreeFromHandle("a6d311a93600a") == [
- "a6d311a93600a", "f5ab3e30151e1", "73475cb40a568", "44cb730c42048", "8c659a11cd429"
- ]
-
- # Move a root item (top level items are different) twice
- nwTree.flushTreeOrder()
- assert nwGUI.theProject.projTree._treeOrder.index("9d5247ab588e0") == 9
- nwTree.setSelectedHandle("9d5247ab588e0")
-
- nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
- nwTree.flushTreeOrder()
- assert nwGUI.theProject.projTree._treeOrder.index("9d5247ab588e0") == 10
-
- nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
- nwTree.flushTreeOrder()
- assert nwGUI.theProject.projTree._treeOrder.index("9d5247ab588e0") == 10
-
- # Add some content to the new file
- nwGUI.openDocument("73475cb40a568")
- nwGUI.docEditor.setText("# Hello World\n")
- nwGUI.saveDocument()
- assert os.path.isfile(os.path.join(nwMinimal, "content", "73475cb40a568.nwd"))
-
- # Delete the items we added earlier
- nwTree.clearSelection()
- assert not nwTree.emptyTrash() # No folder yet
- assert not nwTree.deleteItem(None)
- assert not nwTree.deleteItem("1111111111111")
- assert nwTree.deleteItem("73475cb40a568") # New File
- assert nwTree.deleteItem("44cb730c42048") # New Folder
- assert nwTree.deleteItem("71ee45a3c0db9") # Custom Root
- assert "73475cb40a568" in nwGUI.theProject.projTree._treeOrder
- assert "44cb730c42048" not in nwGUI.theProject.projTree._treeOrder
- assert "71ee45a3c0db9" not in nwGUI.theProject.projTree._treeOrder
-
- # The file is in trash, empty it
- assert os.path.isfile(os.path.join(nwMinimal, "content", "73475cb40a568.nwd"))
- assert nwTree.emptyTrash()
- assert not nwTree.emptyTrash() # Already empty
- assert not os.path.isfile(os.path.join(nwMinimal, "content", "73475cb40a568.nwd"))
- assert "73475cb40a568" not in nwGUI.theProject.projTree._treeOrder
-
- # Close the project
- nwGUI.closeProject()
-
- # Add an orphaned file
- orphFile = os.path.join(nwMinimal, "content", "1234567890abc.nwd")
- with open(orphFile, mode="w+", encoding="utf8") as outFile:
- outFile.write("# Hello World\n")
-
- # Open the project again
- nwGUI.openProject(nwMinimal)
-
- # Check that the orphaned file was found and added to the tree
- assert nwTree.orphRoot is not None
- nwTree.flushTreeOrder()
- assert "1234567890abc" not in nwGUI.theProject.projTree._treeOrder
- orItem = nwTree._getTreeItem("1234567890abc")
- assert orItem.text(nwTree.C_NAME) == "Orphaned File 1"
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
-
-@pytest.mark.gui
-def testEditFormatMenu(qtbot, yesToAll, nwLipsum, tmpDir):
-
- nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % tmpDir])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(stepDelay)
-
- # Test Document Action with No Project
- assert not nwGUI.docEditor.docAction(nwDocAction.COPY)
-
- nwGUI.theProject.projTree.setSeed(42)
- assert nwGUI.openProject(nwLipsum)
- qtbot.wait(stepDelay)
-
- # Split By Chapter
- assert nwGUI.openDocument("4c4f28287af27")
- assert nwGUI.docEditor.setCursorPosition(30)
-
- cleanText = nwGUI.docEditor.getText()[27:74]
-
- # Bold
- nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
- fmtStr = "**Pellentesque** nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:78] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Italic
- nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
- fmtStr = "_Pellentesque_ nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:76] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Strikethrough
- nwGUI.mainMenu.aFmtStrike.activate(QAction.Trigger)
- fmtStr = "~~Pellentesque~~ nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:78] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtStrike.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Should get us back to plain
- nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Double Quotes
- nwGUI.mainMenu.aFmtDQuote.activate(QAction.Trigger)
- fmtStr = "“Pellentesque” nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:76] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Single Quotes
- nwGUI.mainMenu.aFmtSQuote.activate(QAction.Trigger)
- fmtStr = "‘Pellentesque’ nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:76] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Block Formats
- assert nwGUI.docEditor.setCursorPosition(30)
- nwGUI.mainMenu.aFmtHead1.activate(QAction.Trigger)
- fmtStr = "# Pellentesque nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:76] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtHead2.activate(QAction.Trigger)
- fmtStr = "## Pellentesque nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:77] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtHead3.activate(QAction.Trigger)
- fmtStr = "### Pellentesque nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:78] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtHead4.activate(QAction.Trigger)
- fmtStr = "#### Pellentesque nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:79] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtComment.activate(QAction.Trigger)
- fmtStr = "% Pellentesque nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:76] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Check comment with no space before text
- assert nwGUI.docEditor.setCursorPosition(27)
- assert nwGUI.docEditor.insertText("%")
- fmtStr = "%Pellentesque nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:75] == fmtStr
- qtbot.wait(stepDelay)
-
- nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Undo/Redo
- nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
- fmtStr = "%Pellentesque nec erat ut nulla posuere commodo."
- assert nwGUI.docEditor.getText()[27:75] == fmtStr
- qtbot.wait(stepDelay)
- nwGUI.mainMenu.aEditRedo.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
- # Cut, Copy and Paste
- assert nwGUI.docEditor.setCursorPosition(27)
- nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
-
- nwGUI.mainMenu.aEditCut.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:77] == (
- " nec erat ut nulla posuere commodo. Curabitur nisi"
- )
-
- nwGUI.mainMenu.aEditPaste.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:77] == (
- "Pellentesque nec erat ut nulla posuere commodo. Cu"
- )
-
- assert nwGUI.docEditor.setCursorPosition(27)
- nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
-
- nwGUI.mainMenu.aEditCopy.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:77] == (
- "Pellentesque nec erat ut nulla posuere commodo. Cu"
- )
-
- assert nwGUI.docEditor.setCursorPosition(27)
- nwGUI.mainMenu.aEditPaste.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[27:77] == (
- "PellentesquePellentesque nec erat ut nulla posuere"
- )
- nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
-
- # Select Paragraph/All
- assert nwGUI.docEditor.setCursorPosition(30)
- nwGUI.mainMenu.aSelectPar.activate(QAction.Trigger)
- theCursor = nwGUI.docEditor.textCursor()
- assert theCursor.selectedText() == (
- "Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
- "imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
- "placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
- "Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. "
- "Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, "
- "rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin "
- "nunc lacus, imperdiet nec posuere ac, interdum non lectus."
- )
-
- assert nwGUI.docEditor.setCursorPosition(30)
- nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
- theCursor = nwGUI.docEditor.textCursor()
- assert len(theCursor.selectedText()) == 1883
-
- # Clear the Text
- nwGUI.docEditor.clear()
- assert nwGUI.docEditor.isEmpty()
-
- # Replace Quotes
- nwGUI.docEditor.setText((
- "### New Text\n\n"
- "Text with 'single' quotes and 'tricky stuff's'.\n\n"
- "Also text with \"double\" quotes which are \"less tricky\".\n\n"
- ))
-
- nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
- nwGUI.mainMenu.aFmtReplSng.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == (
- "### New Text\n\n"
- "Text with ‘single’ quotes and ‘tricky stuff’s’.\n\n"
- "Also text with \"double\" quotes which are \"less tricky\".\n\n"
- )
-
- nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
- nwGUI.mainMenu.aFmtReplDbl.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == (
- "### New Text\n\n"
- "Text with ‘single’ quotes and ‘tricky stuff’s’.\n\n"
- "Also text with “double” quotes which are “less tricky”.\n\n"
- )
-
- # Test Invalid Document Action
- assert not nwGUI.docEditor.docAction(nwDocAction.NO_ACTION)
-
- # Test Invalid Formats
- nwGUI.docEditor.setText((
- "### New Text\n\n"
- "@tag: Bod\n\n"
- "Text with 'single' quotes and 'tricky stuff's'.\n\n"
- "Also text with \"double\" quotes which are \"less tricky\".\n\n"
- ))
-
- # Cannot Format Tag
- assert nwGUI.docEditor.setCursorPosition(17)
- assert not nwGUI.docEditor._formatBlock(nwDocAction.BLOCK_TXT)
-
- # Cannot Format Empty Line
- assert nwGUI.docEditor.setCursorPosition(13)
- assert not nwGUI.docEditor._formatBlock(nwDocAction.BLOCK_TXT)
-
- # Invalid Action
- assert nwGUI.docEditor.setCursorPosition(30)
- assert not nwGUI.docEditor._formatBlock(nwDocAction.NO_ACTION)
-
- # Ensure No Changes
- assert nwGUI.docEditor.getText() == (
- "### New Text\n\n"
- "@tag: Bod\n\n"
- "Text with 'single' quotes and 'tricky stuff's'.\n\n"
- "Also text with \"double\" quotes which are \"less tricky\".\n\n"
- )
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
-
-@pytest.mark.gui
-def testContextMenu(qtbot, yesToAll, nwLipsum, tmpDir):
-
- nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % tmpDir])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(stepDelay)
-
- nwGUI.theProject.projTree.setSeed(42)
- assert nwGUI.openProject(nwLipsum)
- assert nwGUI.openDocument("4c4f28287af27")
- qtbot.wait(stepDelay)
-
- # Editor Context Menu
- theCursor = nwGUI.docEditor.textCursor()
- theCursor.setPosition(100)
- nwGUI.docEditor.setTextCursor(theCursor)
- theRect = nwGUI.docEditor.cursorRect()
-
- nwGUI.docEditor._openContextMenu(theRect.bottomRight())
- qtbot.mouseClick(nwGUI.docEditor, Qt.LeftButton, pos=theRect.topLeft())
-
- nwGUI.docEditor._makePosSelection(QTextCursor.WordUnderCursor, theRect.center())
- theCursor = nwGUI.docEditor.textCursor()
- assert theCursor.selectedText() == "imperdiet"
-
- nwGUI.docEditor._makePosSelection(QTextCursor.BlockUnderCursor, theRect.center())
- theCursor = nwGUI.docEditor.textCursor()
- assert theCursor.selectedText() == (
- "Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
- "imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
- "placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
- "Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. "
- "Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, "
- "rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin "
- "nunc lacus, imperdiet nec posuere ac, interdum non lectus."
- )
-
- # Viewer Context Menu
- assert nwGUI.viewDocument("4c4f28287af27")
-
- theCursor = nwGUI.docViewer.textCursor()
- theCursor.setPosition(100)
- nwGUI.docViewer.setTextCursor(theCursor)
- theRect = nwGUI.docViewer.cursorRect()
-
- nwGUI.docViewer._openContextMenu(theRect.bottomRight())
- qtbot.mouseClick(nwGUI.docViewer, Qt.LeftButton, pos=theRect.topLeft())
-
- nwGUI.docViewer._makePosSelection(QTextCursor.WordUnderCursor, theRect.center())
- theCursor = nwGUI.docViewer.textCursor()
- assert theCursor.selectedText() == "imperdiet"
-
- nwGUI.docEditor._makePosSelection(QTextCursor.BlockUnderCursor, theRect.center())
- theCursor = nwGUI.docEditor.textCursor()
- assert theCursor.selectedText() == (
- "Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
- "imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
- "placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
- "Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. "
- "Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, "
- "rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin "
- "nunc lacus, imperdiet nec posuere ac, interdum non lectus."
- )
-
- # Navigation History
- assert nwGUI.viewDocument("04468803b92e1")
- assert nwGUI.docViewer.theHandle == "04468803b92e1"
- assert nwGUI.docViewer.docHeader.backButton.isEnabled()
- assert not nwGUI.docViewer.docHeader.forwardButton.isEnabled()
-
- qtbot.mouseClick(nwGUI.docViewer.docHeader.backButton, Qt.LeftButton)
- assert nwGUI.docViewer.theHandle == "4c4f28287af27"
- assert not nwGUI.docViewer.docHeader.backButton.isEnabled()
- assert nwGUI.docViewer.docHeader.forwardButton.isEnabled()
-
- qtbot.mouseClick(nwGUI.docViewer.docHeader.forwardButton, Qt.LeftButton)
- assert nwGUI.docViewer.theHandle == "04468803b92e1"
- assert nwGUI.docViewer.docHeader.backButton.isEnabled()
- assert not nwGUI.docViewer.docHeader.forwardButton.isEnabled()
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
-
-@pytest.mark.gui
-def testInsertMenu(qtbot, monkeypatch, fncDir, tmpDir):
- nwGUI = nw.main(["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(stepDelay)
-
- nwGUI.theProject.projTree.setSeed(42)
- assert nwGUI.newProject({"projPath": fncDir})
-
- assert nwGUI.treeView._getTreeItem("0e17daca5f3e1") is not None
-
- nwGUI.setFocus(1)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("0e17daca5f3e1").setSelected(True)
- assert nwGUI.openSelectedItem()
- nwGUI.docEditor.clear()
-
- # Test Faulty Inserts
- assert nwGUI.docEditor.insertText("hello world")
- assert nwGUI.docEditor.getText() == "hello world"
- nwGUI.docEditor.clear()
-
- assert not nwGUI.docEditor.insertText(nwDocInsert.NO_INSERT)
- assert nwGUI.docEditor.isEmpty()
-
- assert not nwGUI.docEditor.insertText(None)
- assert nwGUI.docEditor.isEmpty()
-
- # qtbot.stopForInteraction()
-
- # Check Menu Entries
- nwGUI.mainMenu.aInsENDash.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwUnicode.U_ENDASH
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsEMDash.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwUnicode.U_EMDASH
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsEllipsis.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwUnicode.U_HELLIP
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsQuoteLS.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSingleQuotes[0]
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsQuoteRS.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSingleQuotes[1]
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsQuoteLD.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDoubleQuotes[0]
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsQuoteRD.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDoubleQuotes[1]
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsMSApos.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwUnicode.U_MAPOSS
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsHardBreak.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == " \n"
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsNBSpace.activate(QAction.Trigger)
- if nwGUI.mainConf.verQtValue >= 50900:
- assert nwGUI.docEditor.getText() == nwUnicode.U_NBSP
- else:
- assert nwGUI.docEditor.getText() == " "
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsThinSpace.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == nwUnicode.U_THNSP
- nwGUI.docEditor.clear()
-
- nwGUI.mainMenu.aInsThinNBSpace.activate(QAction.Trigger)
- if nwGUI.mainConf.verQtValue >= 50900:
- assert nwGUI.docEditor.getText() == nwUnicode.U_THNBSP
- else:
- assert nwGUI.docEditor.getText() == " "
- nwGUI.docEditor.clear()
-
- ##
- # Insert Keywords
- ##
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.TAG_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.TAG_KEY
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.POV_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.POV_KEY
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.CHAR_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.CHAR_KEY
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.PLOT_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.PLOT_KEY
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.TIME_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.TIME_KEY
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.WORLD_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.WORLD_KEY
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.OBJECT_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.OBJECT_KEY
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.ENTITY_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.ENTITY_KEY
-
- nwGUI.docEditor.setText("Stuff")
- nwGUI.mainMenu.mInsKWItems[nwKeyWords.CUSTOM_KEY][0].activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.CUSTOM_KEY
-
- # Faulty Keyword Inserts
- assert not nwGUI.docEditor.insertKeyWord("blabla")
- monkeypatch.setattr(QTextBlock, "isValid", lambda *args, **kwards: False)
- assert not nwGUI.docEditor.insertKeyWord(nwKeyWords.TAG_KEY)
- monkeypatch.undo()
-
- nwGUI.docEditor.clear()
-
- ##
- # Insert text from file
- ##
-
- nwGUI.closeDocument()
-
- # First, with no path
- monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args, **kwards: ("", ""))
- assert not nwGUI.importDocument()
-
- # Then with a path, but an invalid one
- monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args, **kwards: (" ", ""))
- assert not nwGUI.importDocument()
-
- # Then a valid path, but bot a file that exists
- theFile = os.path.join(tmpDir, "import.txt")
- monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args, **kwards: (theFile, ""))
- assert not nwGUI.importDocument()
-
- # Create the file and try again, but with no target document open
- with open(theFile, mode="w+", encoding="utf8") as outFile:
- outFile.write("Foo")
- assert not nwGUI.importDocument()
-
- # Open the document from before, and add some text to it
- nwGUI.openDocument("0e17daca5f3e1")
- nwGUI.docEditor.setText("Bar")
- assert nwGUI.docEditor.getText() == "Bar"
-
- # The document isn't empty, so the message box should pop
- monkeypatch.setattr(QMessageBox, "question", lambda *args, **kwargs: QMessageBox.No)
- assert not nwGUI.importDocument()
- assert nwGUI.docEditor.getText() == "Bar"
-
- # Finally, accept the replaced text, this time we use the menu entry to trigger it
- monkeypatch.setattr(QMessageBox, "question", lambda *args, **kwargs: QMessageBox.Yes)
- nwGUI.mainMenu.aImportFile.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText() == "Foo"
-
- ##
- # Reveal file location
- ##
-
- theMessage = ""
-
- def recordMsg(*args):
- nonlocal theMessage
- theMessage = args[3]
- return None
-
- assert not theMessage
- monkeypatch.setattr(QMessageBox, "information", recordMsg)
- nwGUI.mainMenu.aFileDetails.activate(QAction.Trigger)
-
- theBits = theMessage.split("
")
- assert len(theBits) == 3
- assert theBits[0] == "File details for the currently open file"
- assert theBits[1] == "Handle: 0e17daca5f3e1"
- assert theBits[2] == "Location: %s" % os.path.join(fncDir, "content", "0e17daca5f3e1.nwd")
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
-
-@pytest.mark.gui
-def testTextSearch(qtbot, monkeypatch, yesToAll, nwLipsum, tmpDir):
-
- nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % tmpDir])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(stepDelay)
-
- nwGUI.theProject.projTree.setSeed(42)
- assert nwGUI.openProject(nwLipsum)
- assert nwGUI.openDocument("4c4f28287af27")
- origText = nwGUI.docEditor.getText()
- qtbot.wait(stepDelay)
-
- # Select the Word "est"
- assert nwGUI.docEditor.setCursorPosition(618)
- nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
- theCursor = nwGUI.docEditor.textCursor()
- assert theCursor.selectedText() == "est"
-
- # Activate Search
- nwGUI.mainMenu.aFind.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.isVisible()
- assert nwGUI.docEditor.docSearch.getSearchText() == "est"
-
- # Find Next by Enter
- monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True)
- qtbot.keyClick(nwGUI.docEditor.docSearch.searchBox, Qt.Key_Return, delay=keyDelay)
- assert abs(nwGUI.docEditor.getCursorPosition() - 1272) < 3
-
- # Find Next by Button
- qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
- assert abs(nwGUI.docEditor.getCursorPosition() - 1486) < 3
-
- # Activate Loop Search
- nwGUI.docEditor.docSearch.toggleLoop.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.toggleLoop.isChecked()
- assert nwGUI.docEditor.docSearch.doLoop
-
- # Find Next by Menu Search > Find Next
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
-
- # Close Search
- nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
- assert not nwGUI.docEditor.docSearch.isVisible()
- assert nwGUI.docEditor.setCursorPosition(15)
-
- # Toggle Search Again with Header Button
- qtbot.mouseClick(nwGUI.docEditor.docHeader.searchButton, Qt.LeftButton, delay=keyDelay)
- assert nwGUI.docEditor.docSearch.setSearchText("")
- assert nwGUI.docEditor.docSearch.isVisible()
-
- # Enable RegEx Search
- nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.toggleRegEx.isChecked()
- assert nwGUI.docEditor.docSearch.isRegEx
-
- # Set Invalid RegEx
- assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus[")
- qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
- assert nwGUI.docEditor.getCursorPosition() < 3 # No result
-
- # Set Valid RegEx
- assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus")
- qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
- assert abs(nwGUI.docEditor.getCursorPosition() - 196) < 3
-
- # Find Next and then Prev
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 297) < 3
- nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 196) < 3
-
- # Make RegEx Case Sensitive
- nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.toggleCase.isChecked()
- assert nwGUI.docEditor.docSearch.isCaseSense
-
- # Find Next (One Result)
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 599) < 3
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 599) < 3
-
- # Trigger Replace
- nwGUI.mainMenu.aReplace.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.setReplaceText("foo")
-
- # Disable RegEx Case Sensitive
- nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger)
- assert not nwGUI.docEditor.docSearch.toggleCase.isChecked()
- assert not nwGUI.docEditor.docSearch.isCaseSense
-
- # Toggle Replace Preserve Case
- nwGUI.docEditor.docSearch.toggleMatchCap.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.toggleMatchCap.isChecked()
- assert nwGUI.docEditor.docSearch.doMatchCap
-
- # Replace "Sus" with "Foo" via Menu
- nwGUI.mainMenu.aReplaceNext.activate(QAction.Trigger)
- assert nwGUI.docEditor.getText()[596:607] == "Foopendisse"
-
- # Find Next to Loop File
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
-
- # Replace "sus" with "foo" via Replace Button
- qtbot.mouseClick(nwGUI.docEditor.docSearch.replaceButton, Qt.LeftButton, delay=keyDelay)
- assert nwGUI.docEditor.getText()[193:201] == "foocipit"
-
- # Revert Last Two Replaces
- assert nwGUI.docEditor.docAction(nwDocAction.UNDO)
- assert nwGUI.docEditor.docAction(nwDocAction.UNDO)
- assert nwGUI.docEditor.getText() == origText
-
- # Disable RegEx Search
- nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger)
- assert not nwGUI.docEditor.docSearch.toggleRegEx.isChecked()
- assert not nwGUI.docEditor.docSearch.isRegEx
-
- # Close Search and Select "est" Again
- nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
- assert nwGUI.docEditor.setCursorPosition(618)
- nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
- theCursor = nwGUI.docEditor.textCursor()
- assert theCursor.selectedText() == "est"
-
- # Activate Search Again
- nwGUI.mainMenu.aFind.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.isVisible()
- assert nwGUI.docEditor.docSearch.getSearchText() == "est"
-
- # Enable Full Word Search
- nwGUI.docEditor.docSearch.toggleWord.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.toggleWord.isChecked()
- assert nwGUI.docEditor.docSearch.isWholeWord
-
- # Only One Match
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
-
- # Enable Next Doc Search
- nwGUI.docEditor.docSearch.toggleProject.activate(QAction.Trigger)
- assert nwGUI.docEditor.docSearch.toggleProject.isChecked()
- assert nwGUI.docEditor.docSearch.doNextFile
-
- # Next Match
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert nwGUI.docEditor.theHandle == "2426c6f0ca922" # Next document
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
- nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
- assert abs(nwGUI.docEditor.getCursorPosition() - 1127) < 3
-
- # Toggle Replace
- nwGUI.docEditor._beginReplace()
-
- # MonkeyPatch the focus cycle. We can't really test this very well, other than
- # check that the tabs aren't captured when the main editor has focus
- monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: True)
- monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False)
- monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False)
- assert not nwGUI.docEditor.focusNextPrevChild(True)
-
- monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: False)
- monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True)
- monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False)
- assert nwGUI.docEditor.focusNextPrevChild(True)
-
- monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False)
- monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: True)
- assert nwGUI.docEditor.focusNextPrevChild(True)
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
-
-@pytest.mark.gui
-def testOutline(qtbot, yesToAll, nwLipsum, tmpDir):
-
- nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % tmpDir])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(stepDelay)
-
- assert nwGUI.openProject(nwLipsum)
- nwGUI.mainConf.lastPath = nwLipsum
-
- nwGUI.rebuildIndex()
- nwGUI.tabWidget.setCurrentIndex(nwGUI.idxTabProj)
-
- assert nwGUI.projView.topLevelItemCount() > 0
-
- # Context Menu
- nwGUI.projView._headerRightClick(QPoint(1, 1))
- nwGUI.projView.headerMenu.actionMap[nwOutline.CCOUNT].activate(QAction.Trigger)
- nwGUI.projView.headerMenu.close()
- qtbot.mouseClick(nwGUI.projView, Qt.LeftButton)
-
- nwGUI.projView._loadHeaderState()
- assert not nwGUI.projView.colHidden[nwOutline.CCOUNT]
-
- # First Item
- nwGUI.rebuildOutline()
- selItem = nwGUI.projView.topLevelItem(0)
- assert isinstance(selItem, QTreeWidgetItem)
-
- nwGUI.projView.setCurrentItem(selItem)
- assert nwGUI.projMeta.titleLabel.text() == "Title"
- assert nwGUI.projMeta.titleValue.text() == "Lorem Ipsum"
- assert nwGUI.projMeta.fileValue.text() == "Lorem Ipsum"
- assert nwGUI.projMeta.itemValue.text() == "Finished"
-
- assert nwGUI.projMeta.cCValue.text() == "230"
- assert nwGUI.projMeta.wCValue.text() == "40"
- assert nwGUI.projMeta.pCValue.text() == "3"
-
- # Scene One
- actItem = nwGUI.projView.topLevelItem(1)
- chpItem = actItem.child(0)
- selItem = chpItem.child(0)
-
- nwGUI.projView.setCurrentItem(selItem)
- assert nwGUI.projMeta.titleLabel.text() == "Scene"
- assert nwGUI.projMeta.titleValue.text() == "Scene One"
- assert nwGUI.projMeta.fileValue.text() == "Scene One"
- assert nwGUI.projMeta.itemValue.text() == "Finished"
-
- # Click POV Link
- assert nwGUI.projMeta.povKeyValue.text() == "Bod"
- nwGUI.projMeta._tagClicked("#pov=Bod")
- assert nwGUI.docViewer.theHandle == "4c4f28287af27"
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
-
-@pytest.mark.gui
-def testThemes(qtbot, yesToAll, nwMinimal, tmpDir):
-
- nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal])
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(500)
-
- # Change Settings
- assert nw.CONFIG.confPath == nwMinimal
- nw.CONFIG.guiTheme = "default_dark"
- nw.CONFIG.guiSyntax = "tomorrow_night_eighties"
- nw.CONFIG.guiIcons = "typicons_colour_dark"
- nw.CONFIG.guiDark = True
- nw.CONFIG.guiFont = "Cantarell"
- nw.CONFIG.guiFontSize = 11
- nw.CONFIG.confChanged = True
- assert nw.CONFIG.saveConfig()
-
- nwGUI.closeMain()
- nwGUI.close()
- del nwGUI
-
- # Re-open
- assert nw.CONFIG.confPath == nwMinimal
- nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal])
- assert nwGUI.mainConf.confPath == nwMinimal
- qtbot.addWidget(nwGUI)
- nwGUI.show()
- qtbot.waitForWindowShown(nwGUI)
- qtbot.wait(500)
-
- assert nw.CONFIG.guiTheme == "default_dark"
- assert nw.CONFIG.guiSyntax == "tomorrow_night_eighties"
- assert nw.CONFIG.guiIcons == "typicons_colour_dark"
- assert nw.CONFIG.guiDark is True
- assert nw.CONFIG.guiFont == "Cantarell"
- assert nw.CONFIG.guiFontSize == 11
-
- # Check GUI Colours
- thePalette = nwGUI.palette()
- assert thePalette.window().color() == QColor(54, 54, 54)
- assert thePalette.windowText().color() == QColor(174, 174, 174)
- assert thePalette.base().color() == QColor(62, 62, 62)
- assert thePalette.alternateBase().color() == QColor(67, 67, 67)
- assert thePalette.text().color() == QColor(174, 174, 174)
- assert thePalette.toolTipBase().color() == QColor(255, 255, 192)
- assert thePalette.toolTipText().color() == QColor(21, 21, 13)
- assert thePalette.button().color() == QColor(62, 62, 62)
- assert thePalette.buttonText().color() == QColor(174, 174, 174)
- assert thePalette.brightText().color() == QColor(174, 174, 174)
- assert thePalette.highlight().color() == QColor(44, 152, 247)
- assert thePalette.highlightedText().color() == QColor(255, 255, 255)
- assert thePalette.link().color() == QColor(44, 152, 247)
- assert thePalette.linkVisited().color() == QColor(44, 152, 247)
-
- assert nwGUI.theTheme.treeWCount == [197, 200, 198]
- assert nwGUI.theTheme.statNone == [150, 152, 150]
- assert nwGUI.theTheme.statSaved == [39, 135, 78]
- assert nwGUI.theTheme.statUnsaved == [138, 32, 32]
-
- # Check Syntax Colours
- assert nwGUI.theTheme.colBack == [45, 45, 45]
- assert nwGUI.theTheme.colText == [204, 204, 204]
- assert nwGUI.theTheme.colLink == [102, 153, 204]
- assert nwGUI.theTheme.colHead == [102, 153, 204]
- assert nwGUI.theTheme.colHeadH == [102, 153, 204]
- assert nwGUI.theTheme.colEmph == [249, 145, 57]
- assert nwGUI.theTheme.colDialN == [242, 119, 122]
- assert nwGUI.theTheme.colDialD == [153, 204, 153]
- assert nwGUI.theTheme.colDialS == [255, 204, 102]
- assert nwGUI.theTheme.colHidden == [153, 153, 153]
- assert nwGUI.theTheme.colKey == [242, 119, 122]
- assert nwGUI.theTheme.colVal == [204, 153, 204]
- assert nwGUI.theTheme.colSpell == [242, 119, 122]
- assert nwGUI.theTheme.colTagErr == [153, 204, 153]
- assert nwGUI.theTheme.colRepTag == [102, 204, 204]
- assert nwGUI.theTheme.colMod == [249, 145, 57]
-
- # Test Icon class
- theIcons = nwGUI.theTheme.theIcons
- nw.CONFIG.guiIcons = "invalid"
- assert not theIcons.updateTheme()
- nw.CONFIG.guiIcons = "typicons_colour_dark"
- assert theIcons.updateTheme()
-
- # Ask for a non-existent key
- anImg = theIcons.loadDecoration("nonsense", 20, 20)
- assert isinstance(anImg, QPixmap)
- assert anImg.isNull()
-
- # Add a non-existent file and request it
- theIcons.DECO_MAP["nonsense"] = "nofile.jpg"
- anImg = theIcons.loadDecoration("nonsense", 20, 20)
- assert isinstance(anImg, QPixmap)
- assert anImg.isNull()
-
- # Get a real image, with different size parameters
- anImg = theIcons.loadDecoration("wiz-back", 20, None)
- assert isinstance(anImg, QPixmap)
- assert not anImg.isNull()
- assert anImg.width() == 20
- assert anImg.height() >= 56
-
- anImg = theIcons.loadDecoration("wiz-back", None, 70)
- assert isinstance(anImg, QPixmap)
- assert not anImg.isNull()
- assert anImg.height() == 70
- assert anImg.width() >= 24
-
- anImg = theIcons.loadDecoration("wiz-back", 30, 70)
- assert isinstance(anImg, QPixmap)
- assert not anImg.isNull()
- assert anImg.height() == 70
- assert anImg.width() == 30
-
- anImg = theIcons.loadDecoration("wiz-back", None, None)
- assert isinstance(anImg, QPixmap)
- assert not anImg.isNull()
- assert anImg.height() >= 1500
- assert anImg.width() >= 500
-
- # Load icons
- anIcon = theIcons.getIcon("nonsense")
- assert isinstance(anIcon, QIcon)
- assert anIcon.isNull()
-
- anIcon = theIcons.getIcon("novelwriter")
- assert isinstance(anIcon, QIcon)
- assert not anIcon.isNull()
-
- # Add dummy icons and test alternative load paths
- theIcons.ICON_MAP["testicon1"] = (QStyle.SP_DriveHDIcon, None)
- anIcon = theIcons.getIcon("testicon1")
- assert isinstance(anIcon, QIcon)
- assert not anIcon.isNull()
-
- theIcons.ICON_MAP["testicon2"] = (None, "folder")
- anIcon = theIcons.getIcon("testicon2")
- assert isinstance(anIcon, QIcon)
-
- theIcons.ICON_MAP["testicon3"] = (None, None)
- anIcon = theIcons.getIcon("testicon3")
- assert isinstance(anIcon, QIcon)
- assert anIcon.isNull()
-
- # qtbot.stopForInteraction()
- nwGUI.closeMain()
- nwGUI.close()
diff --git a/tests/test_gui_mainmenu.py b/tests/test_gui_mainmenu.py
new file mode 100644
index 00000000..33408505
--- /dev/null
+++ b/tests/test_gui_mainmenu.py
@@ -0,0 +1,533 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Main GUI Main Menu Class Tester
+"""
+
+import pytest
+import os
+
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QTextCursor, QTextBlock
+from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox
+
+from nw.constants import nwUnicode, nwDocAction, nwDocInsert, nwKeyWords
+
+keyDelay = 2
+typeDelay = 1
+stepDelay = 20
+
+@pytest.mark.gui
+def testGuiMenu_EditFormat(qtbot, monkeypatch, nwGUI, nwLipsum):
+ """Test the main menu Edit and Format entries.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ # Test Document Action with No Project
+ assert not nwGUI.docEditor.docAction(nwDocAction.COPY)
+
+ nwGUI.theProject.projTree.setSeed(42)
+ assert nwGUI.openProject(nwLipsum)
+ qtbot.wait(stepDelay)
+
+ # Split By Chapter
+ assert nwGUI.openDocument("4c4f28287af27")
+ assert nwGUI.docEditor.setCursorPosition(30)
+
+ cleanText = nwGUI.docEditor.getText()[27:74]
+
+ # Bold
+ nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
+ fmtStr = "**Pellentesque** nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:78] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Italic
+ nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
+ fmtStr = "_Pellentesque_ nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:76] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Strikethrough
+ nwGUI.mainMenu.aFmtStrike.activate(QAction.Trigger)
+ fmtStr = "~~Pellentesque~~ nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:78] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtStrike.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Should get us back to plain
+ nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Double Quotes
+ nwGUI.mainMenu.aFmtDQuote.activate(QAction.Trigger)
+ fmtStr = "“Pellentesque” nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:76] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Single Quotes
+ nwGUI.mainMenu.aFmtSQuote.activate(QAction.Trigger)
+ fmtStr = "‘Pellentesque’ nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:76] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Block Formats
+ assert nwGUI.docEditor.setCursorPosition(30)
+ nwGUI.mainMenu.aFmtHead1.activate(QAction.Trigger)
+ fmtStr = "# Pellentesque nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:76] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtHead2.activate(QAction.Trigger)
+ fmtStr = "## Pellentesque nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:77] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtHead3.activate(QAction.Trigger)
+ fmtStr = "### Pellentesque nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:78] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtHead4.activate(QAction.Trigger)
+ fmtStr = "#### Pellentesque nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:79] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtComment.activate(QAction.Trigger)
+ fmtStr = "% Pellentesque nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:76] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Check comment with no space before text
+ assert nwGUI.docEditor.setCursorPosition(27)
+ assert nwGUI.docEditor.insertText("%")
+ fmtStr = "%Pellentesque nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:75] == fmtStr
+ qtbot.wait(stepDelay)
+
+ nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Undo/Redo
+ nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
+ fmtStr = "%Pellentesque nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:75] == fmtStr
+ qtbot.wait(stepDelay)
+ nwGUI.mainMenu.aEditRedo.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:74] == cleanText
+ qtbot.wait(stepDelay)
+
+ # Cut, Copy and Paste
+ assert nwGUI.docEditor.setCursorPosition(27)
+ nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
+
+ nwGUI.mainMenu.aEditCut.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:77] == (
+ " nec erat ut nulla posuere commodo. Curabitur nisi"
+ )
+
+ nwGUI.mainMenu.aEditPaste.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:77] == (
+ "Pellentesque nec erat ut nulla posuere commodo. Cu"
+ )
+
+ assert nwGUI.docEditor.setCursorPosition(27)
+ nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
+
+ nwGUI.mainMenu.aEditCopy.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:77] == (
+ "Pellentesque nec erat ut nulla posuere commodo. Cu"
+ )
+
+ assert nwGUI.docEditor.setCursorPosition(27)
+ nwGUI.mainMenu.aEditPaste.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText()[27:77] == (
+ "PellentesquePellentesque nec erat ut nulla posuere"
+ )
+ nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
+
+ # Select Paragraph/All
+ assert nwGUI.docEditor.setCursorPosition(30)
+ nwGUI.mainMenu.aSelectPar.activate(QAction.Trigger)
+ theCursor = nwGUI.docEditor.textCursor()
+ assert theCursor.selectedText() == (
+ "Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
+ "imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
+ "placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
+ "Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. "
+ "Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, "
+ "rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin "
+ "nunc lacus, imperdiet nec posuere ac, interdum non lectus."
+ )
+
+ assert nwGUI.docEditor.setCursorPosition(30)
+ nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
+ theCursor = nwGUI.docEditor.textCursor()
+ assert len(theCursor.selectedText()) == 1883
+
+ # Clear the Text
+ nwGUI.docEditor.clear()
+ assert nwGUI.docEditor.isEmpty()
+
+ # Replace Quotes
+ nwGUI.docEditor.setText((
+ "### New Text\n\n"
+ "Text with 'single' quotes and 'tricky stuff's'.\n\n"
+ "Also text with \"double\" quotes which are \"less tricky\".\n\n"
+ ))
+
+ nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
+ nwGUI.mainMenu.aFmtReplSng.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == (
+ "### New Text\n\n"
+ "Text with ‘single’ quotes and ‘tricky stuff’s’.\n\n"
+ "Also text with \"double\" quotes which are \"less tricky\".\n\n"
+ )
+
+ nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
+ nwGUI.mainMenu.aFmtReplDbl.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == (
+ "### New Text\n\n"
+ "Text with ‘single’ quotes and ‘tricky stuff’s’.\n\n"
+ "Also text with “double” quotes which are “less tricky”.\n\n"
+ )
+
+ # Test Invalid Document Action
+ assert not nwGUI.docEditor.docAction(nwDocAction.NO_ACTION)
+
+ # Test Invalid Formats
+ nwGUI.docEditor.setText((
+ "### New Text\n\n"
+ "@tag: Bod\n\n"
+ "Text with 'single' quotes and 'tricky stuff's'.\n\n"
+ "Also text with \"double\" quotes which are \"less tricky\".\n\n"
+ ))
+
+ # Cannot Format Tag
+ assert nwGUI.docEditor.setCursorPosition(17)
+ assert not nwGUI.docEditor._formatBlock(nwDocAction.BLOCK_TXT)
+
+ # Cannot Format Empty Line
+ assert nwGUI.docEditor.setCursorPosition(13)
+ assert not nwGUI.docEditor._formatBlock(nwDocAction.BLOCK_TXT)
+
+ # Invalid Action
+ assert nwGUI.docEditor.setCursorPosition(30)
+ assert not nwGUI.docEditor._formatBlock(nwDocAction.NO_ACTION)
+
+ # Ensure No Changes
+ assert nwGUI.docEditor.getText() == (
+ "### New Text\n\n"
+ "@tag: Bod\n\n"
+ "Text with 'single' quotes and 'tricky stuff's'.\n\n"
+ "Also text with \"double\" quotes which are \"less tricky\".\n\n"
+ )
+
+ # qtbot.stopForInteraction()
+
+# END Test testGuiMenu_EditFormat
+
+@pytest.mark.gui
+def testGuiMenu_ContextMenus(qtbot, monkeypatch, nwGUI, nwLipsum):
+ """Test the context menus.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ nwGUI.theProject.projTree.setSeed(42)
+ assert nwGUI.openProject(nwLipsum)
+ assert nwGUI.openDocument("4c4f28287af27")
+ qtbot.wait(stepDelay)
+
+ # Editor Context Menu
+ theCursor = nwGUI.docEditor.textCursor()
+ theCursor.setPosition(100)
+ nwGUI.docEditor.setTextCursor(theCursor)
+ theRect = nwGUI.docEditor.cursorRect()
+
+ nwGUI.docEditor._openContextMenu(theRect.bottomRight())
+ qtbot.mouseClick(nwGUI.docEditor, Qt.LeftButton, pos=theRect.topLeft())
+
+ nwGUI.docEditor._makePosSelection(QTextCursor.WordUnderCursor, theRect.center())
+ theCursor = nwGUI.docEditor.textCursor()
+ assert theCursor.selectedText() == "imperdiet"
+
+ nwGUI.docEditor._makePosSelection(QTextCursor.BlockUnderCursor, theRect.center())
+ theCursor = nwGUI.docEditor.textCursor()
+ assert theCursor.selectedText() == (
+ "Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
+ "imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
+ "placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
+ "Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. "
+ "Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, "
+ "rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin "
+ "nunc lacus, imperdiet nec posuere ac, interdum non lectus."
+ )
+
+ # Viewer Context Menu
+ assert nwGUI.viewDocument("4c4f28287af27")
+
+ theCursor = nwGUI.docViewer.textCursor()
+ theCursor.setPosition(100)
+ nwGUI.docViewer.setTextCursor(theCursor)
+ theRect = nwGUI.docViewer.cursorRect()
+
+ nwGUI.docViewer._openContextMenu(theRect.bottomRight())
+ qtbot.mouseClick(nwGUI.docViewer, Qt.LeftButton, pos=theRect.topLeft())
+
+ nwGUI.docViewer._makePosSelection(QTextCursor.WordUnderCursor, theRect.center())
+ theCursor = nwGUI.docViewer.textCursor()
+ assert theCursor.selectedText() == "imperdiet"
+
+ nwGUI.docEditor._makePosSelection(QTextCursor.BlockUnderCursor, theRect.center())
+ theCursor = nwGUI.docEditor.textCursor()
+ assert theCursor.selectedText() == (
+ "Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
+ "imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
+ "placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
+ "Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. "
+ "Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, "
+ "rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin "
+ "nunc lacus, imperdiet nec posuere ac, interdum non lectus."
+ )
+
+ # Navigation History
+ assert nwGUI.viewDocument("04468803b92e1")
+ assert nwGUI.docViewer.theHandle == "04468803b92e1"
+ assert nwGUI.docViewer.docHeader.backButton.isEnabled()
+ assert not nwGUI.docViewer.docHeader.forwardButton.isEnabled()
+
+ qtbot.mouseClick(nwGUI.docViewer.docHeader.backButton, Qt.LeftButton)
+ assert nwGUI.docViewer.theHandle == "4c4f28287af27"
+ assert not nwGUI.docViewer.docHeader.backButton.isEnabled()
+ assert nwGUI.docViewer.docHeader.forwardButton.isEnabled()
+
+ qtbot.mouseClick(nwGUI.docViewer.docHeader.forwardButton, Qt.LeftButton)
+ assert nwGUI.docViewer.theHandle == "04468803b92e1"
+ assert nwGUI.docViewer.docHeader.backButton.isEnabled()
+ assert not nwGUI.docViewer.docHeader.forwardButton.isEnabled()
+
+ # qtbot.stopForInteraction()
+
+# END Test testGuiMenu_ContextMenus
+
+@pytest.mark.gui
+def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
+ """Test the Insert menu.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ nwGUI.theProject.projTree.setSeed(42)
+ assert nwGUI.newProject({"projPath": fncProj})
+
+ assert nwGUI.treeView._getTreeItem("0e17daca5f3e1") is not None
+
+ nwGUI.setFocus(1)
+ nwGUI.treeView.clearSelection()
+ nwGUI.treeView._getTreeItem("0e17daca5f3e1").setSelected(True)
+ assert nwGUI.openSelectedItem()
+ nwGUI.docEditor.clear()
+
+ # Test Faulty Inserts
+ assert nwGUI.docEditor.insertText("hello world")
+ assert nwGUI.docEditor.getText() == "hello world"
+ nwGUI.docEditor.clear()
+
+ assert not nwGUI.docEditor.insertText(nwDocInsert.NO_INSERT)
+ assert nwGUI.docEditor.isEmpty()
+
+ assert not nwGUI.docEditor.insertText(None)
+ assert nwGUI.docEditor.isEmpty()
+
+ # qtbot.stopForInteraction()
+
+ # Check Menu Entries
+ nwGUI.mainMenu.aInsENDash.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwUnicode.U_ENDASH
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsEMDash.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwUnicode.U_EMDASH
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsEllipsis.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwUnicode.U_HELLIP
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsQuoteLS.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSingleQuotes[0]
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsQuoteRS.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSingleQuotes[1]
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsQuoteLD.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDoubleQuotes[0]
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsQuoteRD.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDoubleQuotes[1]
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsMSApos.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwUnicode.U_MAPOSS
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsHardBreak.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == " \n"
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsNBSpace.activate(QAction.Trigger)
+ if nwGUI.mainConf.verQtValue >= 50900:
+ assert nwGUI.docEditor.getText() == nwUnicode.U_NBSP
+ else:
+ assert nwGUI.docEditor.getText() == " "
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsThinSpace.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == nwUnicode.U_THNSP
+ nwGUI.docEditor.clear()
+
+ nwGUI.mainMenu.aInsThinNBSpace.activate(QAction.Trigger)
+ if nwGUI.mainConf.verQtValue >= 50900:
+ assert nwGUI.docEditor.getText() == nwUnicode.U_THNBSP
+ else:
+ assert nwGUI.docEditor.getText() == " "
+ nwGUI.docEditor.clear()
+
+ ##
+ # Insert Keywords
+ ##
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.TAG_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.TAG_KEY
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.POV_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.POV_KEY
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.CHAR_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.CHAR_KEY
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.PLOT_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.PLOT_KEY
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.TIME_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.TIME_KEY
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.WORLD_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.WORLD_KEY
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.OBJECT_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.OBJECT_KEY
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.ENTITY_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.ENTITY_KEY
+
+ nwGUI.docEditor.setText("Stuff")
+ nwGUI.mainMenu.mInsKWItems[nwKeyWords.CUSTOM_KEY][0].activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Stuff\n%s: " % nwKeyWords.CUSTOM_KEY
+
+ # Faulty Keyword Inserts
+ assert not nwGUI.docEditor.insertKeyWord("blabla")
+ monkeypatch.setattr(QTextBlock, "isValid", lambda *args, **kwards: False)
+ assert not nwGUI.docEditor.insertKeyWord(nwKeyWords.TAG_KEY)
+ monkeypatch.undo()
+
+ nwGUI.docEditor.clear()
+
+ ##
+ # Insert text from file
+ ##
+
+ nwGUI.closeDocument()
+
+ # First, with no path
+ monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args, **kwards: ("", ""))
+ assert not nwGUI.importDocument()
+
+ # Then with a path, but an invalid one
+ monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args, **kwards: (" ", ""))
+ assert not nwGUI.importDocument()
+
+ # Then a valid path, but bot a file that exists
+ theFile = os.path.join(fncDir, "import.txt")
+ monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args, **kwards: (theFile, ""))
+ assert not nwGUI.importDocument()
+
+ # Create the file and try again, but with no target document open
+ with open(theFile, mode="w+", encoding="utf8") as outFile:
+ outFile.write("Foo")
+ assert not nwGUI.importDocument()
+
+ # Open the document from before, and add some text to it
+ nwGUI.openDocument("0e17daca5f3e1")
+ nwGUI.docEditor.setText("Bar")
+ assert nwGUI.docEditor.getText() == "Bar"
+
+ # The document isn't empty, so the message box should pop
+ monkeypatch.setattr(QMessageBox, "question", lambda *args, **kwargs: QMessageBox.No)
+ assert not nwGUI.importDocument()
+ assert nwGUI.docEditor.getText() == "Bar"
+
+ # Finally, accept the replaced text, this time we use the menu entry to trigger it
+ monkeypatch.setattr(QMessageBox, "question", lambda *args, **kwargs: QMessageBox.Yes)
+ nwGUI.mainMenu.aImportFile.activate(QAction.Trigger)
+ assert nwGUI.docEditor.getText() == "Foo"
+
+ ##
+ # Reveal file location
+ ##
+
+ theMessage = ""
+
+ def recordMsg(*args):
+ nonlocal theMessage
+ theMessage = args[3]
+ return None
+
+ assert not theMessage
+ monkeypatch.setattr(QMessageBox, "information", recordMsg)
+ nwGUI.mainMenu.aFileDetails.activate(QAction.Trigger)
+
+ theBits = theMessage.split("
")
+ assert len(theBits) == 3
+ assert theBits[0] == "File details for the currently open file"
+ assert theBits[1] == "Handle: 0e17daca5f3e1"
+ assert theBits[2] == "Location: %s" % os.path.join(fncProj, "content", "0e17daca5f3e1.nwd")
+
+ # qtbot.stopForInteraction()
+
+# END Test testGuiMenu_Insert
diff --git a/tests/test_gui_outline.py b/tests/test_gui_outline.py
new file mode 100644
index 00000000..cf93c111
--- /dev/null
+++ b/tests/test_gui_outline.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Main GUI Outline Class Tester
+"""
+
+import pytest
+
+from PyQt5.QtCore import Qt, QPoint
+from PyQt5.QtWidgets import QAction, QTreeWidgetItem, QMessageBox
+
+from nw.constants import nwOutline
+
+keyDelay = 2
+typeDelay = 1
+stepDelay = 20
+
+@pytest.mark.gui
+def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
+ """Test the outline view.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ assert nwGUI.openProject(nwLipsum)
+ nwGUI.mainConf.lastPath = nwLipsum
+
+ nwGUI.rebuildIndex()
+ nwGUI.tabWidget.setCurrentIndex(nwGUI.idxTabProj)
+
+ assert nwGUI.projView.topLevelItemCount() > 0
+
+ # Context Menu
+ nwGUI.projView._headerRightClick(QPoint(1, 1))
+ nwGUI.projView.headerMenu.actionMap[nwOutline.CCOUNT].activate(QAction.Trigger)
+ nwGUI.projView.headerMenu.close()
+ qtbot.mouseClick(nwGUI.projView, Qt.LeftButton)
+
+ nwGUI.projView._loadHeaderState()
+ assert not nwGUI.projView.colHidden[nwOutline.CCOUNT]
+
+ # First Item
+ nwGUI.rebuildOutline()
+ selItem = nwGUI.projView.topLevelItem(0)
+ assert isinstance(selItem, QTreeWidgetItem)
+
+ nwGUI.projView.setCurrentItem(selItem)
+ assert nwGUI.projMeta.titleLabel.text() == "Title"
+ assert nwGUI.projMeta.titleValue.text() == "Lorem Ipsum"
+ assert nwGUI.projMeta.fileValue.text() == "Lorem Ipsum"
+ assert nwGUI.projMeta.itemValue.text() == "Finished"
+
+ assert nwGUI.projMeta.cCValue.text() == "230"
+ assert nwGUI.projMeta.wCValue.text() == "40"
+ assert nwGUI.projMeta.pCValue.text() == "3"
+
+ # Scene One
+ actItem = nwGUI.projView.topLevelItem(1)
+ chpItem = actItem.child(0)
+ selItem = chpItem.child(0)
+
+ nwGUI.projView.setCurrentItem(selItem)
+ assert nwGUI.projMeta.titleLabel.text() == "Scene"
+ assert nwGUI.projMeta.titleValue.text() == "Scene One"
+ assert nwGUI.projMeta.fileValue.text() == "Scene One"
+ assert nwGUI.projMeta.itemValue.text() == "Finished"
+
+ # Click POV Link
+ assert nwGUI.projMeta.povKeyValue.text() == "Bod"
+ nwGUI.projMeta._tagClicked("#pov=Bod")
+ assert nwGUI.docViewer.theHandle == "4c4f28287af27"
+
+ # qtbot.stopForInteraction()
+
+# END Test testGuiOutline_Main
diff --git a/tests/test_gui_projtree.py b/tests/test_gui_projtree.py
new file mode 100644
index 00000000..94726348
--- /dev/null
+++ b/tests/test_gui_projtree.py
@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Main GUI Project Tree Class Tester
+"""
+
+import pytest
+import os
+
+from PyQt5.QtCore import QItemSelectionModel
+from PyQt5.QtWidgets import QAction, QMessageBox
+
+from nw.constants import nwItemType, nwItemClass
+
+keyDelay = 2
+typeDelay = 1
+stepDelay = 20
+
+@pytest.mark.gui
+def testGuiProjTree_Main(qtbot, monkeypatch, nwGUI, nwMinimal):
+ """Test the project tree.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ nwGUI.theProject.projTree.setSeed(42)
+ assert nwGUI.openProject(nwMinimal)
+ nwTree = nwGUI.treeView
+
+ # No location selected for new item
+ assert not nwTree.newTreeItem(nwItemType.FILE, None)
+ assert not nwTree.newTreeItem(nwItemType.FOLDER, None)
+
+ # Select a location
+ chItem = nwTree._getTreeItem("a6d311a93600a")
+ nwTree.setCurrentItem(chItem, QItemSelectionModel.Current)
+ chItem.setExpanded(True)
+
+ # Create new item with no class set
+ assert nwTree.newTreeItem(nwItemType.FILE, None)
+ assert nwTree.newTreeItem(nwItemType.FOLDER, None)
+
+ # Add roots
+ assert not nwTree.newTreeItem(nwItemType.ROOT, None) # Defaults to NOVEL
+ assert not nwTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) # Duplicate
+ assert nwTree.newTreeItem(nwItemType.ROOT, nwItemClass.CUSTOM) # Valid
+
+ # Check that we have the correct tree order
+ assert nwTree.getTreeFromHandle("a6d311a93600a") == [
+ "a6d311a93600a", "f5ab3e30151e1", "8c659a11cd429", "73475cb40a568", "44cb730c42048"
+ ]
+
+ # Move second item up twice (should give same result)
+ nwTree.setSelectedHandle("8c659a11cd429")
+ nwGUI.mainMenu.aMoveUp.activate(QAction.Trigger)
+ assert nwTree.getTreeFromHandle("a6d311a93600a") == [
+ "a6d311a93600a", "8c659a11cd429", "f5ab3e30151e1", "73475cb40a568", "44cb730c42048"
+ ]
+ nwGUI.mainMenu.aMoveUp.activate(QAction.Trigger)
+ assert nwTree.getTreeFromHandle("a6d311a93600a") == [
+ "a6d311a93600a", "8c659a11cd429", "f5ab3e30151e1", "73475cb40a568", "44cb730c42048"
+ ]
+
+ # Move it back down four times (last to should be the same)
+ nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
+ assert nwTree.getTreeFromHandle("a6d311a93600a") == [
+ "a6d311a93600a", "f5ab3e30151e1", "8c659a11cd429", "73475cb40a568", "44cb730c42048"
+ ]
+ nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
+ assert nwTree.getTreeFromHandle("a6d311a93600a") == [
+ "a6d311a93600a", "f5ab3e30151e1", "73475cb40a568", "8c659a11cd429", "44cb730c42048"
+ ]
+ nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
+ assert nwTree.getTreeFromHandle("a6d311a93600a") == [
+ "a6d311a93600a", "f5ab3e30151e1", "73475cb40a568", "44cb730c42048", "8c659a11cd429"
+ ]
+ nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
+ assert nwTree.getTreeFromHandle("a6d311a93600a") == [
+ "a6d311a93600a", "f5ab3e30151e1", "73475cb40a568", "44cb730c42048", "8c659a11cd429"
+ ]
+
+ # Move a root item (top level items are different) twice
+ nwTree.flushTreeOrder()
+ assert nwGUI.theProject.projTree._treeOrder.index("9d5247ab588e0") == 9
+ nwTree.setSelectedHandle("9d5247ab588e0")
+
+ nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
+ nwTree.flushTreeOrder()
+ assert nwGUI.theProject.projTree._treeOrder.index("9d5247ab588e0") == 10
+
+ nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
+ nwTree.flushTreeOrder()
+ assert nwGUI.theProject.projTree._treeOrder.index("9d5247ab588e0") == 10
+
+ # Add some content to the new file
+ nwGUI.openDocument("73475cb40a568")
+ nwGUI.docEditor.setText("# Hello World\n")
+ nwGUI.saveDocument()
+ assert os.path.isfile(os.path.join(nwMinimal, "content", "73475cb40a568.nwd"))
+
+ # Delete the items we added earlier
+ nwTree.clearSelection()
+ assert not nwTree.emptyTrash() # No folder yet
+ assert not nwTree.deleteItem(None)
+ assert not nwTree.deleteItem("1111111111111")
+ assert nwTree.deleteItem("73475cb40a568") # New File
+ assert nwTree.deleteItem("44cb730c42048") # New Folder
+ assert nwTree.deleteItem("71ee45a3c0db9") # Custom Root
+ assert "73475cb40a568" in nwGUI.theProject.projTree._treeOrder
+ assert "44cb730c42048" not in nwGUI.theProject.projTree._treeOrder
+ assert "71ee45a3c0db9" not in nwGUI.theProject.projTree._treeOrder
+
+ # The file is in trash, empty it
+ assert os.path.isfile(os.path.join(nwMinimal, "content", "73475cb40a568.nwd"))
+ assert nwTree.emptyTrash()
+ assert not nwTree.emptyTrash() # Already empty
+ assert not os.path.isfile(os.path.join(nwMinimal, "content", "73475cb40a568.nwd"))
+ assert "73475cb40a568" not in nwGUI.theProject.projTree._treeOrder
+
+ # Close the project
+ nwGUI.closeProject()
+
+ # Add an orphaned file
+ orphFile = os.path.join(nwMinimal, "content", "1234567890abc.nwd")
+ with open(orphFile, mode="w+", encoding="utf8") as outFile:
+ outFile.write("# Hello World\n")
+
+ # Open the project again
+ nwGUI.openProject(nwMinimal)
+
+ # Check that the orphaned file was found and added to the tree
+ assert nwTree.orphRoot is not None
+ nwTree.flushTreeOrder()
+ assert "1234567890abc" not in nwGUI.theProject.projTree._treeOrder
+ orItem = nwTree._getTreeItem("1234567890abc")
+ assert orItem.text(nwTree.C_NAME) == "Orphaned File 1"
+
+ # qtbot.stopForInteraction()
+
+# END Test testGuiProjTree_Main
diff --git a/tests/test_gui_theme.py b/tests/test_gui_theme.py
new file mode 100644
index 00000000..4214af59
--- /dev/null
+++ b/tests/test_gui_theme.py
@@ -0,0 +1,170 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Main GUI Class Tester
+"""
+
+import nw
+import pytest
+
+from PyQt5.QtGui import QColor, QPixmap, QIcon
+from PyQt5.QtWidgets import QStyle, QMessageBox
+
+keyDelay = 2
+typeDelay = 1
+stepDelay = 20
+
+@pytest.mark.gui
+def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir):
+ """Test the theme and icon classes.
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
+
+ nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal])
+ qtbot.addWidget(nwGUI)
+ nwGUI.show()
+ qtbot.waitForWindowShown(nwGUI)
+ qtbot.wait(500)
+
+ # Change Settings
+ assert nw.CONFIG.confPath == nwMinimal
+ nw.CONFIG.guiTheme = "default_dark"
+ nw.CONFIG.guiSyntax = "tomorrow_night_eighties"
+ nw.CONFIG.guiIcons = "typicons_colour_dark"
+ nw.CONFIG.guiDark = True
+ nw.CONFIG.guiFont = "Cantarell"
+ nw.CONFIG.guiFontSize = 11
+ nw.CONFIG.confChanged = True
+ assert nw.CONFIG.saveConfig()
+
+ nwGUI.closeMain()
+ nwGUI.close()
+ del nwGUI
+
+ # Re-open
+ assert nw.CONFIG.confPath == nwMinimal
+ nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal])
+ assert nwGUI.mainConf.confPath == nwMinimal
+ qtbot.addWidget(nwGUI)
+ nwGUI.show()
+ qtbot.waitForWindowShown(nwGUI)
+ qtbot.wait(500)
+
+ assert nw.CONFIG.guiTheme == "default_dark"
+ assert nw.CONFIG.guiSyntax == "tomorrow_night_eighties"
+ assert nw.CONFIG.guiIcons == "typicons_colour_dark"
+ assert nw.CONFIG.guiDark is True
+ assert nw.CONFIG.guiFont == "Cantarell"
+ assert nw.CONFIG.guiFontSize == 11
+
+ # Check GUI Colours
+ thePalette = nwGUI.palette()
+ assert thePalette.window().color() == QColor(54, 54, 54)
+ assert thePalette.windowText().color() == QColor(174, 174, 174)
+ assert thePalette.base().color() == QColor(62, 62, 62)
+ assert thePalette.alternateBase().color() == QColor(67, 67, 67)
+ assert thePalette.text().color() == QColor(174, 174, 174)
+ assert thePalette.toolTipBase().color() == QColor(255, 255, 192)
+ assert thePalette.toolTipText().color() == QColor(21, 21, 13)
+ assert thePalette.button().color() == QColor(62, 62, 62)
+ assert thePalette.buttonText().color() == QColor(174, 174, 174)
+ assert thePalette.brightText().color() == QColor(174, 174, 174)
+ assert thePalette.highlight().color() == QColor(44, 152, 247)
+ assert thePalette.highlightedText().color() == QColor(255, 255, 255)
+ assert thePalette.link().color() == QColor(44, 152, 247)
+ assert thePalette.linkVisited().color() == QColor(44, 152, 247)
+
+ assert nwGUI.theTheme.treeWCount == [197, 200, 198]
+ assert nwGUI.theTheme.statNone == [150, 152, 150]
+ assert nwGUI.theTheme.statSaved == [39, 135, 78]
+ assert nwGUI.theTheme.statUnsaved == [138, 32, 32]
+
+ # Check Syntax Colours
+ assert nwGUI.theTheme.colBack == [45, 45, 45]
+ assert nwGUI.theTheme.colText == [204, 204, 204]
+ assert nwGUI.theTheme.colLink == [102, 153, 204]
+ assert nwGUI.theTheme.colHead == [102, 153, 204]
+ assert nwGUI.theTheme.colHeadH == [102, 153, 204]
+ assert nwGUI.theTheme.colEmph == [249, 145, 57]
+ assert nwGUI.theTheme.colDialN == [242, 119, 122]
+ assert nwGUI.theTheme.colDialD == [153, 204, 153]
+ assert nwGUI.theTheme.colDialS == [255, 204, 102]
+ assert nwGUI.theTheme.colHidden == [153, 153, 153]
+ assert nwGUI.theTheme.colKey == [242, 119, 122]
+ assert nwGUI.theTheme.colVal == [204, 153, 204]
+ assert nwGUI.theTheme.colSpell == [242, 119, 122]
+ assert nwGUI.theTheme.colTagErr == [153, 204, 153]
+ assert nwGUI.theTheme.colRepTag == [102, 204, 204]
+ assert nwGUI.theTheme.colMod == [249, 145, 57]
+
+ # Test Icon class
+ theIcons = nwGUI.theTheme.theIcons
+ nw.CONFIG.guiIcons = "invalid"
+ assert not theIcons.updateTheme()
+ nw.CONFIG.guiIcons = "typicons_colour_dark"
+ assert theIcons.updateTheme()
+
+ # Ask for a non-existent key
+ anImg = theIcons.loadDecoration("nonsense", 20, 20)
+ assert isinstance(anImg, QPixmap)
+ assert anImg.isNull()
+
+ # Add a non-existent file and request it
+ theIcons.DECO_MAP["nonsense"] = "nofile.jpg"
+ anImg = theIcons.loadDecoration("nonsense", 20, 20)
+ assert isinstance(anImg, QPixmap)
+ assert anImg.isNull()
+
+ # Get a real image, with different size parameters
+ anImg = theIcons.loadDecoration("wiz-back", 20, None)
+ assert isinstance(anImg, QPixmap)
+ assert not anImg.isNull()
+ assert anImg.width() == 20
+ assert anImg.height() >= 56
+
+ anImg = theIcons.loadDecoration("wiz-back", None, 70)
+ assert isinstance(anImg, QPixmap)
+ assert not anImg.isNull()
+ assert anImg.height() == 70
+ assert anImg.width() >= 24
+
+ anImg = theIcons.loadDecoration("wiz-back", 30, 70)
+ assert isinstance(anImg, QPixmap)
+ assert not anImg.isNull()
+ assert anImg.height() == 70
+ assert anImg.width() == 30
+
+ anImg = theIcons.loadDecoration("wiz-back", None, None)
+ assert isinstance(anImg, QPixmap)
+ assert not anImg.isNull()
+ assert anImg.height() >= 1500
+ assert anImg.width() >= 500
+
+ # Load icons
+ anIcon = theIcons.getIcon("nonsense")
+ assert isinstance(anIcon, QIcon)
+ assert anIcon.isNull()
+
+ anIcon = theIcons.getIcon("novelwriter")
+ assert isinstance(anIcon, QIcon)
+ assert not anIcon.isNull()
+
+ # Add dummy icons and test alternative load paths
+ theIcons.ICON_MAP["testicon1"] = (QStyle.SP_DriveHDIcon, None)
+ anIcon = theIcons.getIcon("testicon1")
+ assert isinstance(anIcon, QIcon)
+ assert not anIcon.isNull()
+
+ theIcons.ICON_MAP["testicon2"] = (None, "folder")
+ anIcon = theIcons.getIcon("testicon2")
+ assert isinstance(anIcon, QIcon)
+
+ theIcons.ICON_MAP["testicon3"] = (None, None)
+ anIcon = theIcons.getIcon("testicon3")
+ assert isinstance(anIcon, QIcon)
+ assert anIcon.isNull()
+
+ # qtbot.stopForInteraction()
+ nwGUI.closeMain()
+ nwGUI.close()
+
+# END Test testGuiTheme_Main