Fix merge conflicts
This commit is contained in:
@@ -23,11 +23,6 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiDocDetails(QFrame):
|
||||
|
||||
C_NAME = 0
|
||||
C_COUNT = 1
|
||||
C_FLAGS = 2
|
||||
C_HANDLE = 3
|
||||
|
||||
def __init__(self, theParent, theProject):
|
||||
QFrame.__init__(self, theParent)
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
from PyQt5.QtGui import (
|
||||
QTextCursor, QTextOption, QKeySequence, QFont, QColor, QPalette,
|
||||
QTextDocument
|
||||
QTextDocument, QCursor
|
||||
)
|
||||
|
||||
from nw.project import NWDoc
|
||||
from nw.gui.tools import GuiDocHighlighter, WordCounter
|
||||
from nw.tools import NWSpellCheck, NWSpellSimple
|
||||
from nw.constants import nwFiles, nwUnicode, nwDocAction, nwAlert
|
||||
from nw.tools import NWSpellSimple
|
||||
from nw.constants import nwUnicode, nwDocAction
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -209,7 +209,7 @@ class GuiDocEditor(QTextEdit):
|
||||
risk overwriting the file if it exists. This can for instance
|
||||
happen of the file contains binary elements or an encoding that
|
||||
novelWriter does not support. If load is successful, or the
|
||||
document is new (empty string) we set up the editor for editing
|
||||
document is new (empty string), we set up the editor for editing
|
||||
the file.
|
||||
"""
|
||||
|
||||
@@ -219,6 +219,7 @@ class GuiDocEditor(QTextEdit):
|
||||
self.clearEditor()
|
||||
return False
|
||||
|
||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
self.hLight.setHandle(tHandle)
|
||||
|
||||
# Check that the document is not too big for full, initial spell
|
||||
@@ -246,6 +247,7 @@ class GuiDocEditor(QTextEdit):
|
||||
self.theParent.noticeBar.showNote("This document is read only.")
|
||||
|
||||
self.hLight.spellCheck = spTemp
|
||||
qApp.restoreOverrideCursor()
|
||||
|
||||
return True
|
||||
|
||||
@@ -277,8 +279,9 @@ class GuiDocEditor(QTextEdit):
|
||||
return True
|
||||
|
||||
def updateDocMargins(self):
|
||||
"""Automatically adjust the margins so the text is centred, but
|
||||
only if Config.textFixedW is enabled or we're in Zen mode.
|
||||
"""Automatically adjust the margins so the text is centred if
|
||||
Config.textFixedW is enabled or we're in Zen mode. Otherwise,
|
||||
just ensure the margins are set correctly.
|
||||
"""
|
||||
|
||||
if self.mainConf.textFixedW or self.theParent.isZenMode:
|
||||
@@ -335,7 +338,7 @@ class GuiDocEditor(QTextEdit):
|
||||
return theText
|
||||
|
||||
def setCursorPosition(self, thePosition):
|
||||
if thePosition > 0:
|
||||
if thePosition >= 0:
|
||||
theCursor = self.textCursor()
|
||||
theCursor.setPosition(thePosition)
|
||||
self.setTextCursor(theCursor)
|
||||
@@ -361,8 +364,8 @@ class GuiDocEditor(QTextEdit):
|
||||
def setSpellCheck(self, theMode):
|
||||
"""This is the master spell check setting function, and this one
|
||||
should call all other setSpellCheck functions in other classes.
|
||||
If the spell check mode is not defined, then toggle the current
|
||||
status saved in the class.
|
||||
If the spell check mode (theMode) is not defined (None), then
|
||||
toggle the current status saved in this class.
|
||||
"""
|
||||
|
||||
if theMode is None:
|
||||
@@ -375,23 +378,29 @@ class GuiDocEditor(QTextEdit):
|
||||
self.theParent.mainMenu.setSpellCheck(theMode)
|
||||
self.theProject.setSpellCheck(theMode)
|
||||
self.hLight.setSpellCheck(theMode)
|
||||
self.reHighlightDocument()
|
||||
if not self.bigDoc:
|
||||
self.spellCheckDocument()
|
||||
|
||||
logger.verbose("Spell check is set to %s" % str(theMode))
|
||||
|
||||
return True
|
||||
|
||||
def reHighlightDocument(self):
|
||||
def spellCheckDocument(self):
|
||||
"""Rerun the highlighter to update spell checking status of the
|
||||
currently loaded text. The fastest way to do this, at least as
|
||||
of Qt 5.13, is to clear the text and put it back.
|
||||
"""
|
||||
|
||||
logger.verbose("Running spell checker")
|
||||
if self.spellCheck:
|
||||
theText = self.getText()
|
||||
self.clear()
|
||||
bfTime = time()
|
||||
self.setPlainText(theText)
|
||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
if self.bigDoc:
|
||||
theText = self.getText()
|
||||
self.setPlainText(theText)
|
||||
else:
|
||||
self.hLight.rehighlight()
|
||||
qApp.restoreOverrideCursor()
|
||||
afTime = time()
|
||||
logger.debug("Document re-highlighted in %.3f milliseconds" % (1000*(afTime-bfTime)))
|
||||
|
||||
|
||||
+120
-19
@@ -16,10 +16,10 @@ import nw
|
||||
from PyQt5.QtCore import Qt, QSize
|
||||
from PyQt5.QtGui import QFont, QColor
|
||||
from PyQt5.QtWidgets import (
|
||||
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication
|
||||
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication, QMessageBox
|
||||
)
|
||||
|
||||
from nw.project import NWItem
|
||||
from nw.project import NWItem, NWDoc
|
||||
from nw.constants import (
|
||||
nwLabels, nwItemType, nwItemClass, nwItemLayout, nwAlert
|
||||
)
|
||||
@@ -171,14 +171,21 @@ class GuiDocTree(QTreeWidget):
|
||||
return False
|
||||
|
||||
# Add the new item to the tree
|
||||
nwItem = self.theProject.getItem(tHandle)
|
||||
trItem = self._addTreeItem(nwItem)
|
||||
self.revealTreeItem(tHandle)
|
||||
self.theParent.editItem()
|
||||
|
||||
return True
|
||||
|
||||
def revealTreeItem(self, tHandle):
|
||||
"""Reveal a newly added project item in the project tree.
|
||||
"""
|
||||
nwItem = self.theProject.getItem(tHandle)
|
||||
trItem = self._addTreeItem(nwItem)
|
||||
pHandle = nwItem.parHandle
|
||||
if pHandle is not None and pHandle in self.theMap.keys():
|
||||
self.theMap[pHandle].setExpanded(True)
|
||||
self.clearSelection()
|
||||
trItem.setSelected(True)
|
||||
self.theParent.editItem()
|
||||
|
||||
return True
|
||||
|
||||
def moveTreeItem(self, nStep):
|
||||
@@ -221,6 +228,16 @@ class GuiDocTree(QTreeWidget):
|
||||
self.theProject.setTreeOrder(theList)
|
||||
return True
|
||||
|
||||
def getTreeFromHandle(self, tHandle):
|
||||
"""Recursively return all the children items starting from a
|
||||
given item handle.
|
||||
"""
|
||||
theList = []
|
||||
theItem = self._getTreeItem(tHandle)
|
||||
if theItem is not None:
|
||||
theList = self._scanChildren(theList, theItem, 0)
|
||||
return theList
|
||||
|
||||
def getColumnSizes(self):
|
||||
retVals = [
|
||||
self.columnWidth(0),
|
||||
@@ -229,7 +246,44 @@ class GuiDocTree(QTreeWidget):
|
||||
]
|
||||
return retVals
|
||||
|
||||
def deleteItem(self, tHandle=None):
|
||||
def emptyTrash(self):
|
||||
"""Permanently delete all documents in the Trash folder. This
|
||||
function only asks for confirmation once, and calls the regular
|
||||
deleteItem function for each document in the Trash folder.
|
||||
"""
|
||||
|
||||
logger.debug("Emptying Trash folder")
|
||||
if self.theProject.trashRoot is None:
|
||||
self.makeAlert("There is no Trash folder.", nwAlert.INFO)
|
||||
return False
|
||||
|
||||
theTrash = self.getTreeFromHandle(self.theProject.trashRoot)
|
||||
if self.theProject.trashRoot in theTrash:
|
||||
theTrash.remove(self.theProject.trashRoot)
|
||||
|
||||
nTrash = len(theTrash)
|
||||
if nTrash == 0:
|
||||
self.makeAlert("The Trash folder is empty.", nwAlert.INFO)
|
||||
return False
|
||||
|
||||
msgBox = QMessageBox()
|
||||
msgRes = msgBox.question(
|
||||
self, "Empty Trash", "Permanently delete %d file%s from Trash?" % (
|
||||
nTrash, "s"*int(nTrash > 1)
|
||||
)
|
||||
)
|
||||
if msgRes != QMessageBox.Yes:
|
||||
return False
|
||||
|
||||
logger.verbose("Deleting %d files from Trash" % nTrash)
|
||||
for tHandle in self.getTreeFromHandle(self.theProject.trashRoot):
|
||||
if tHandle == self.theProject.trashRoot:
|
||||
continue
|
||||
self.deleteItem(tHandle, True)
|
||||
|
||||
return True
|
||||
|
||||
def deleteItem(self, tHandle=None, alreadyAsked=False):
|
||||
"""Delete items from the tree. Note that this does not delete
|
||||
the item from the item tree in the project object. However,
|
||||
since this is only meta data, there isn't really a need to do
|
||||
@@ -246,21 +300,61 @@ class GuiDocTree(QTreeWidget):
|
||||
trItemS = self._getTreeItem(tHandle)
|
||||
nwItemS = self.theProject.getItem(tHandle)
|
||||
|
||||
if nwItemS is None:
|
||||
return False
|
||||
|
||||
if nwItemS.itemType == nwItemType.FILE:
|
||||
logger.debug("User requested file %s moved to trash" % tHandle)
|
||||
trItemP = trItemS.parent()
|
||||
trItemT = self._addTrashRoot()
|
||||
if trItemP is None or trItemT is None:
|
||||
logger.error("Could not move item to trash")
|
||||
logger.error("Could not delete item")
|
||||
return False
|
||||
tIndex = trItemP.indexOfChild(trItemS)
|
||||
trItemC = trItemP.takeChild(tIndex)
|
||||
trItemT.addChild(trItemC)
|
||||
nwItemS.setParent(self.theProject.trashRoot)
|
||||
self.clearSelection()
|
||||
trItemP.setSelected(True)
|
||||
self.theProject.setProjectChanged(True)
|
||||
self.theParent.theIndex.deleteHandle(tHandle)
|
||||
|
||||
pHandle = nwItemS.parHandle
|
||||
if pHandle is not None and pHandle == self.theProject.trashRoot:
|
||||
# If the file is in the trash folder already, as the
|
||||
# user if they want to permanently delete the file.
|
||||
|
||||
doPermanent = False
|
||||
if self.mainConf.showGUI and not alreadyAsked:
|
||||
msgBox = QMessageBox()
|
||||
msgRes = msgBox.question(
|
||||
self, "Delete File", "Permanently delete file '%s'?" % nwItemS.itemName
|
||||
)
|
||||
if msgRes == QMessageBox.Yes:
|
||||
doPermanent = True
|
||||
else:
|
||||
doPermanent = True
|
||||
|
||||
if doPermanent:
|
||||
logger.debug("Permanently deleting file with handle %s" % tHandle)
|
||||
|
||||
tIndex = trItemP.indexOfChild(trItemS)
|
||||
trItemC = trItemP.takeChild(tIndex)
|
||||
|
||||
if self.theParent.docEditor.theHandle == tHandle:
|
||||
self.theParent.closeDocument()
|
||||
|
||||
theDoc = NWDoc(self.theProject, self.theParent)
|
||||
theDoc.deleteDocument(tHandle)
|
||||
self.theProject.deleteItem(tHandle)
|
||||
self.theParent.theIndex.deleteHandle(tHandle)
|
||||
|
||||
else:
|
||||
# The file is not already in the trash folder, so we
|
||||
# move it there.
|
||||
|
||||
if pHandle is None:
|
||||
logger.warning("File has no parent item")
|
||||
|
||||
tIndex = trItemP.indexOfChild(trItemS)
|
||||
trItemC = trItemP.takeChild(tIndex)
|
||||
trItemT.addChild(trItemC)
|
||||
nwItemS.setParent(self.theProject.trashRoot)
|
||||
|
||||
self.theProject.setProjectChanged(True)
|
||||
self.theParent.theIndex.deleteHandle(tHandle)
|
||||
|
||||
elif nwItemS.itemType == nwItemType.FOLDER:
|
||||
logger.debug("User requested folder %s deleted" % tHandle)
|
||||
@@ -271,8 +365,6 @@ class GuiDocTree(QTreeWidget):
|
||||
tIndex = trItemP.indexOfChild(trItemS)
|
||||
if trItemS.childCount() == 0:
|
||||
trItemP.takeChild(tIndex)
|
||||
self.clearSelection()
|
||||
trItemP.setSelected(True)
|
||||
self.theProject.deleteItem(tHandle)
|
||||
else:
|
||||
self.makeAlert(["Cannot delete folder.","It is not empty."], nwAlert.ERROR)
|
||||
@@ -428,6 +520,9 @@ class GuiDocTree(QTreeWidget):
|
||||
return newItem
|
||||
|
||||
def _addTrashRoot(self):
|
||||
"""Adds the trash root folder if it doesn't already exist in the
|
||||
project tree.
|
||||
"""
|
||||
if self.theProject.trashRoot is None:
|
||||
self.theProject.addTrash()
|
||||
trItem = self._addTreeItem(
|
||||
@@ -518,16 +613,22 @@ class GuiDocTree(QTreeWidget):
|
||||
"""
|
||||
sHandle = self.getSelectedHandle()
|
||||
if sHandle is None:
|
||||
logger.error("No handle selected")
|
||||
return
|
||||
|
||||
dIndex = self.indexAt(theEvent.pos())
|
||||
dIndex = self.indexAt(theEvent.pos())
|
||||
if not dIndex.isValid():
|
||||
logger.error("Invalid drop index")
|
||||
return
|
||||
|
||||
dItem = self.itemFromIndex(dIndex)
|
||||
dHandle = dItem.text(self.C_HANDLE)
|
||||
snItem = self.theProject.getItem(sHandle)
|
||||
dnItem = self.theProject.getItem(dHandle)
|
||||
if dnItem is None:
|
||||
self.makeAlert("The item cannot be moved to that location.", nwAlert.ERROR)
|
||||
return
|
||||
|
||||
isSame = snItem.itemClass == dnItem.itemClass
|
||||
isNone = snItem.itemClass == nwItemClass.NO_CLASS
|
||||
isNote = snItem.itemLayout == nwItemLayout.NOTE
|
||||
|
||||
@@ -21,7 +21,6 @@ from PyQt5.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem
|
||||
)
|
||||
|
||||
from nw.tools import OptLastState
|
||||
from nw.constants import nwItemLayout, nwKeyWords, nwLabels, nwFiles
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -75,7 +74,7 @@ class GuiProjectOutline(QWidget):
|
||||
self.theParent = theParent
|
||||
self.theProject = theProject
|
||||
self.theIndex = self.theParent.theIndex
|
||||
self.optState = OutlineLastState(self.theProject,nwFiles.OUTLINE_OPT)
|
||||
self.optState = self.theProject.optState
|
||||
|
||||
self.showWords = True
|
||||
self.showSynopsis = True
|
||||
@@ -111,13 +110,13 @@ class GuiProjectOutline(QWidget):
|
||||
colW.append(self.mainTree.columnWidth(iCol))
|
||||
|
||||
self.treeCols["width"] = colW
|
||||
self.optState.setSetting("headState", self.treeCols)
|
||||
self.optState.setValue("GuiProjectOutline", "headState", self.treeCols)
|
||||
self.optState.saveSettings()
|
||||
return
|
||||
|
||||
def loadHeaderState(self):
|
||||
self.optState.loadSettings()
|
||||
treeCols = self.optState.getSetting("headState")
|
||||
|
||||
treeCols = self.optState.getValue("GuiProjectOutline", "headState", {})
|
||||
|
||||
if "order" not in treeCols.keys(): return
|
||||
if not isinstance(treeCols["order"], list): return
|
||||
@@ -253,15 +252,3 @@ class GuiProjectOutline(QWidget):
|
||||
return
|
||||
|
||||
# END Class GuiProjectOutline
|
||||
|
||||
class OutlineLastState(OptLastState):
|
||||
|
||||
def __init__(self, theProject, theFile):
|
||||
OptLastState.__init__(self, theProject, theFile)
|
||||
self.theState = {
|
||||
"headState" : {},
|
||||
}
|
||||
self.dictOpt = ("headState")
|
||||
return
|
||||
|
||||
# END Class OutlineLastState
|
||||
|
||||
@@ -86,13 +86,13 @@ class GuiSearchBar(QFrame):
|
||||
if not self.isVisible():
|
||||
self.setVisible(True)
|
||||
self.searchBox.setText(theText)
|
||||
self.searchBox.setFocus(True)
|
||||
self.searchBox.setFocus()
|
||||
logger.verbose("Setting search text to '%s'" % theText)
|
||||
return True
|
||||
|
||||
def setReplaceText(self, theText):
|
||||
self._replaceVisible(True)
|
||||
self.replaceBox.setFocus(True)
|
||||
self.replaceBox.setFocus()
|
||||
self.replaceBox.setText(theText)
|
||||
return True
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ from PyQt5.QtWidgets import (
|
||||
QWidget, QLabel, QScrollArea, QFrame, QToolButton, QCheckBox, QGridLayout
|
||||
)
|
||||
|
||||
from nw.constants import nwLabels
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class GuiDocViewDetails(QWidget):
|
||||
|
||||
Reference in New Issue
Block a user