Convert folder to document or note (#1128)

This commit is contained in:
Veronica Berglyd Olsen
2022-10-01 20:42:43 +02:00
committed by GitHub
2 changed files with 100 additions and 18 deletions
+65 -17
View File
@@ -537,7 +537,7 @@ class GuiProjectTree(QTreeWidget):
if pHandle is not None and pHandle in self._treeMap: if pHandle is not None and pHandle in self._treeMap:
self._treeMap[pHandle].setExpanded(True) self._treeMap[pHandle].setExpanded(True)
self._alertTreeChange(tHandle=tHandle, flush=True) self._alertTreeChange(tHandle, flush=True)
self.clearSelection() self.clearSelection()
trItem.setSelected(True) trItem.setSelected(True)
@@ -577,7 +577,7 @@ class GuiProjectTree(QTreeWidget):
pItem.insertChild(nIndex, cItem) pItem.insertChild(nIndex, cItem)
self._recordLastMove(cItem, pItem, tIndex) self._recordLastMove(cItem, pItem, tIndex)
self._alertTreeChange(tHandle=tHandle, flush=True) self._alertTreeChange(tHandle, flush=True)
self.clearSelection() self.clearSelection()
trItem.setSelected(True) trItem.setSelected(True)
trItem.setExpanded(isExp) trItem.setExpanded(isExp)
@@ -595,7 +595,7 @@ class GuiProjectTree(QTreeWidget):
if dlgOk: if dlgOk:
tItem.setName(newLabel) tItem.setName(newLabel)
self.setTreeItemValues(tHandle) self.setTreeItemValues(tHandle)
self._alertTreeChange(tHandle=tHandle, flush=False) self._alertTreeChange(tHandle, flush=False)
return return
@@ -665,7 +665,7 @@ class GuiProjectTree(QTreeWidget):
self.deleteItem(tHandle, alreadyAsked=True, bulkAction=True) self.deleteItem(tHandle, alreadyAsked=True, bulkAction=True)
if nTrash > 0: if nTrash > 0:
self._alertTreeChange(tHandle=trashHandle, flush=True) self._alertTreeChange(trashHandle, flush=True)
return True return True
@@ -707,7 +707,7 @@ class GuiProjectTree(QTreeWidget):
if trItemS.childCount() == 0: if trItemS.childCount() == 0:
self.takeTopLevelItem(tIndex) self.takeTopLevelItem(tIndex)
self._deleteTreeItem(tHandle) self._deleteTreeItem(tHandle)
self._alertTreeChange(tHandle=tHandle, flush=True) self._alertTreeChange(tHandle, flush=True)
else: else:
self.mainGui.makeAlert(self.tr( self.mainGui.makeAlert(self.tr(
"Cannot delete root folder. It is not empty. " "Cannot delete root folder. It is not empty. "
@@ -723,7 +723,7 @@ class GuiProjectTree(QTreeWidget):
tIndex = trItemP.indexOfChild(trItemS) tIndex = trItemP.indexOfChild(trItemS)
trItemP.takeChild(tIndex) trItemP.takeChild(tIndex)
self._deleteTreeItem(tHandle) self._deleteTreeItem(tHandle)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush) self._alertTreeChange(tHandle, flush=autoFlush)
else: else:
# A populated FOLDER or a FILE requires confirmtation # A populated FOLDER or a FILE requires confirmtation
@@ -759,7 +759,7 @@ class GuiProjectTree(QTreeWidget):
self.mainGui.closeDocument() self.mainGui.closeDocument()
self._deleteTreeItem(dHandle) self._deleteTreeItem(dHandle)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush) self._alertTreeChange(tHandle, flush=autoFlush)
self.projView.wordCountsChanged.emit() self.projView.wordCountsChanged.emit()
else: else:
@@ -778,7 +778,7 @@ class GuiProjectTree(QTreeWidget):
trItemT.addChild(trItemC) trItemT.addChild(trItemC)
self._postItemMove(tHandle, wCount) self._postItemMove(tHandle, wCount)
self._recordLastMove(trItemS, trItemP, tIndex) self._recordLastMove(trItemS, trItemP, tIndex)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush) self._alertTreeChange(tHandle, flush=autoFlush)
return True return True
@@ -904,7 +904,7 @@ class GuiProjectTree(QTreeWidget):
dstItem.insertChild(dstIndex, movItem) dstItem.insertChild(dstIndex, movItem)
self._postItemMove(sHandle, wCount) self._postItemMove(sHandle, wCount)
self._alertTreeChange(tHandle=sHandle, flush=True) self._alertTreeChange(sHandle, flush=True)
self.clearSelection() self.clearSelection()
movItem.setSelected(True) movItem.setSelected(True)
@@ -1077,6 +1077,20 @@ class GuiProjectTree(QTreeWidget):
), ),
lambda: self._changeItemLayout(tHandle, nwItemLayout.NOTE) lambda: self._changeItemLayout(tHandle, nwItemLayout.NOTE)
) )
elif isFolder:
if tItem.documentAllowed():
ctxMenu.addAction(
self.tr("Convert to {0}").format(
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
),
lambda: self._covertFolderToFile(tHandle, nwItemLayout.DOCUMENT)
)
ctxMenu.addAction(
self.tr("Convert to {0}").format(
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE])
),
lambda: self._covertFolderToFile(tHandle, nwItemLayout.NOTE)
)
ctxMenu.addSeparator() ctxMenu.addSeparator()
@@ -1154,7 +1168,7 @@ class GuiProjectTree(QTreeWidget):
QTreeWidget.dropEvent(self, theEvent) QTreeWidget.dropEvent(self, theEvent)
self._postItemMove(sHandle, wCount) self._postItemMove(sHandle, wCount)
self._recordLastMove(sItem, pItem, pIndex) self._recordLastMove(sItem, pItem, pIndex)
self._alertTreeChange(tHandle=sHandle, flush=True) self._alertTreeChange(sHandle, flush=True)
sItem.setExpanded(isExpanded) sItem.setExpanded(isExpanded)
return return
@@ -1236,6 +1250,7 @@ class GuiProjectTree(QTreeWidget):
if tItem is not None: if tItem is not None:
tItem.setExported(not tItem.isExported) tItem.setExported(not tItem.isExported)
self.setTreeItemValues(tItem.itemHandle) self.setTreeItemValues(tItem.itemHandle)
self._alertTreeChange(tHandle, flush=False)
return return
def _changeItemStatus(self, tHandle, tStatus): def _changeItemStatus(self, tHandle, tStatus):
@@ -1245,6 +1260,7 @@ class GuiProjectTree(QTreeWidget):
if tItem is not None: if tItem is not None:
tItem.setStatus(tStatus) tItem.setStatus(tStatus)
self.setTreeItemValues(tItem.itemHandle) self.setTreeItemValues(tItem.itemHandle)
self._alertTreeChange(tHandle, flush=False)
return return
def _changeItemImport(self, tHandle, tImport): def _changeItemImport(self, tHandle, tImport):
@@ -1254,6 +1270,7 @@ class GuiProjectTree(QTreeWidget):
if tItem is not None: if tItem is not None:
tItem.setImport(tImport) tItem.setImport(tImport)
self.setTreeItemValues(tItem.itemHandle) self.setTreeItemValues(tItem.itemHandle)
self._alertTreeChange(tHandle, flush=False)
return return
def _changeItemLayout(self, tHandle, itemLayout): def _changeItemLayout(self, tHandle, itemLayout):
@@ -1263,10 +1280,38 @@ class GuiProjectTree(QTreeWidget):
if tItem is not None: if tItem is not None:
if itemLayout == nwItemLayout.DOCUMENT and tItem.documentAllowed(): if itemLayout == nwItemLayout.DOCUMENT and tItem.documentAllowed():
tItem.setLayout(nwItemLayout.DOCUMENT) tItem.setLayout(nwItemLayout.DOCUMENT)
self.setTreeItemValues(tItem.itemHandle) self.setTreeItemValues(tHandle)
self._alertTreeChange(tHandle, flush=False)
elif itemLayout == nwItemLayout.NOTE: elif itemLayout == nwItemLayout.NOTE:
tItem.setLayout(nwItemLayout.NOTE) tItem.setLayout(nwItemLayout.NOTE)
self.setTreeItemValues(tItem.itemHandle) self.setTreeItemValues(tHandle)
self._alertTreeChange(tHandle, flush=False)
return
def _covertFolderToFile(self, tHandle, itemLayout):
"""Convert a folder to a note or document.
"""
tItem = self.theProject.tree[tHandle]
if tItem is not None and tItem.isFolderType():
msgYes = self.mainGui.askQuestion(
self.tr("Convert Folder"),
self.tr(
"Do you want to convert the folder to a {0}? "
"This action cannot be reversed."
).format(trConst(nwLabels.LAYOUT_NAME[itemLayout]))
)
if msgYes and itemLayout == nwItemLayout.DOCUMENT and tItem.documentAllowed():
tItem.setType(nwItemType.FILE)
tItem.setLayout(nwItemLayout.DOCUMENT)
self.setTreeItemValues(tHandle)
self._alertTreeChange(tHandle, flush=False)
elif msgYes and itemLayout == nwItemLayout.NOTE:
tItem.setType(nwItemType.FILE)
tItem.setLayout(nwItemLayout.NOTE)
self.setTreeItemValues(tHandle)
self._alertTreeChange(tHandle, flush=False)
else:
logger.info("Folder conversion cancelled")
return return
def _scanChildren(self, theList, tItem, tIndex): def _scanChildren(self, theList, tItem, tIndex):
@@ -1351,25 +1396,28 @@ class GuiProjectTree(QTreeWidget):
trItem = self._addTreeItem(self.theProject.tree[trashHandle]) trItem = self._addTreeItem(self.theProject.tree[trashHandle])
if trItem is not None: if trItem is not None:
trItem.setExpanded(True) trItem.setExpanded(True)
self._alertTreeChange(tHandle=trashHandle, flush=True) self._alertTreeChange(trashHandle, flush=True)
return trItem return trItem
def _alertTreeChange(self, tHandle=None, flush=True): def _alertTreeChange(self, tHandle, flush=False):
"""Update information on tree change state, and emit necessary """Update information on tree change state, and emit necessary
signals. signals. A flush is only needed if an item is moved, created or
deleted.
""" """
self._timeChanged = time() self._timeChanged = time()
self.theProject.setProjectChanged(True) self.theProject.setProjectChanged(True)
if flush: if flush:
self.saveTreeOrder() self.saveTreeOrder()
if tHandle is None:
return
tItem = self.theProject.tree[tHandle] tItem = self.theProject.tree[tHandle]
if tItem is None: if tItem is None:
return return
itemType = tItem.itemType if tItem.isRootType():
if itemType == nwItemType.ROOT:
self.projView.rootFolderChanged.emit(tHandle) self.projView.rootFolderChanged.emit(tHandle)
self.projView.treeItemChanged.emit(tHandle) self.projView.treeItemChanged.emit(tHandle)
+35 -1
View File
@@ -458,7 +458,7 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
@pytest.mark.gui @pytest.mark.gui
def testGuiProjTree_ContextMenu(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd): def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
"""Test the building of the project tree context menu. All this does """Test the building of the project tree context menu. All this does
is test that the menu builds. It doesn't open the actual menu, is test that the menu builds. It doesn't open the actual menu,
""" """
@@ -470,6 +470,8 @@ def testGuiProjTree_ContextMenu(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True)) monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
monkeypatch.setattr(QMenu, "exec_", lambda *a: None) monkeypatch.setattr(QMenu, "exec_", lambda *a: None)
nwTree = nwGUI.projView
# Create a project # Create a project
prjDir = os.path.join(fncDir, "project") prjDir = os.path.join(fncDir, "project")
buildTestProject(nwGUI, prjDir) buildTestProject(nwGUI, prjDir)
@@ -544,6 +546,38 @@ def testGuiProjTree_ContextMenu(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
projTree._changeItemLayout(hNovelNote, nwItemLayout.NOTE) projTree._changeItemLayout(hNovelNote, nwItemLayout.NOTE)
assert nwItem.itemLayout == nwItemLayout.NOTE assert nwItem.itemLayout == nwItemLayout.NOTE
# Convert Folders to Documents
# ============================
hNewFolderOne = "0000000000013"
hNewFolderTwo = "0000000000015"
nwTree.setSelectedHandle(hNovelNote)
assert nwTree.projTree.newTreeItem(nwItemType.FOLDER) is True
nwTree.setSelectedHandle(hNewFolderOne)
assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
nwTree.setSelectedHandle(hNovelNote)
assert nwTree.projTree.newTreeItem(nwItemType.FOLDER) is True
nwTree.setSelectedHandle(hNewFolderTwo)
assert nwTree.projTree.newTreeItem(nwItemType.FILE, isNote=True) is True
# Click no on the dialog
with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No)
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
assert nwGUI.theProject.tree[hNewFolderOne].isFolderType()
# Convert the first folder to a document
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
assert nwGUI.theProject.tree[hNewFolderOne].isFileType()
assert nwGUI.theProject.tree[hNewFolderOne].isDocumentLayout()
# Convert the second folder to a note
projTree._covertFolderToFile(hNewFolderTwo, nwItemLayout.NOTE)
assert nwGUI.theProject.tree[hNewFolderTwo].isFileType()
assert nwGUI.theProject.tree[hNewFolderTwo].isNoteLayout()
# qtbot.stop() # qtbot.stop()
# END Test testGuiProjTree_ContextMenu # END Test testGuiProjTree_ContextMenu