Update Project Tree (#847)

* Rename index textCounts to fileMeta and add main header level
* Add new icons for document layouts
* Add function in NWItem to describe the item
* Use the icons and description in the project tree and details panel
* Remove flags column and add status column with optional full text
* Update handling and display of header level in editor
* Fix potential bug in project tree
* Update tests
This commit is contained in:
Veronica Berglyd Olsen
2021-08-15 17:55:57 +02:00
committed by GitHub
parent cf7cd5502c
commit 97aebc5b84
34 changed files with 833 additions and 196 deletions
+9 -12
View File
@@ -51,7 +51,7 @@ from PyQt5.QtWidgets import (
from nw.core import NWDoc, NWSpellSimple, countWords
from nw.enum import nwAlert, nwDocAction, nwDocInsert, nwItemClass
from nw.common import transferCase
from nw.constants import nwConst, trConst, nwKeyWords, nwLabels, nwUnicode
from nw.constants import nwConst, nwKeyWords, nwUnicode
from nw.gui.dochighlight import GuiDocHighlighter
logger = logging.getLogger(__name__)
@@ -461,21 +461,19 @@ class GuiDocEditor(QTextEdit):
self.setDocumentChanged(False)
oldHeader = self.theIndex.getHandleHeaderLevel(tHandle)
self.theIndex.scanText(tHandle, docText)
newHeader = self.theIndex.getHandleHeaderLevel(tHandle)
if self._updateHeaders(checkLevel=True):
self.theParent.requestNovelTreeRefresh()
else:
self.theParent.novelView.updateWordCounts(tHandle)
# hLevel = "H0"
# if self._docHeaders:
# hLevel = self._docHeaders[0][1]
# if self.theProject.projTree.updateItemLayout(tHandle, hLevel):
# self.theParent.treeView.setTreeItemValues(tHandle)
# self._nwDocument.writeDocument(docText)
# self.docFooter.updateInfo()
if oldHeader != newHeader:
self.theParent.treeView.setTreeItemValues(tHandle)
self.theParent.treeMeta.updateViewBox(tHandle)
self.docFooter.updateInfo()
# Update the status bar
self.theParent.setStatus(
@@ -2753,9 +2751,8 @@ class GuiDocEditFooter(QWidget):
theIcon = self.theParent.importIcons[iStatus]
sIcon = theIcon.pixmap(self.sPx, self.sPx)
sClass = trConst(nwLabels.CLASS_NAME[self._theItem.itemClass])
sLayout = trConst(nwLabels.LAYOUT_NAME[self._theItem.itemLayout])
sText = f"{self._theItem.itemStatus} / {sClass} / {sLayout}"
hLevel = self.theParent.theIndex.getHandleHeaderLevel(self._docHandle)
sText = f"{self._theItem.itemStatus} / {self._theItem.describeMe(hLevel)}"
self.statusIcon.setPixmap(sIcon)
self.statusText.setText(sText)
+40 -23
View File
@@ -30,7 +30,7 @@ from PyQt5.QtCore import Qt, pyqtSlot
from PyQt5.QtGui import QFont, QPixmap
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel
from nw.enum import nwItemClass, nwItemType, nwItemLayout
from nw.enum import nwItemClass, nwItemType
from nw.constants import trConst, nwLabels
logger = logging.getLogger(__name__)
@@ -98,8 +98,7 @@ class GuiItemDetails(QWidget):
self.className.setAlignment(Qt.AlignLeft)
self.classFlag = QLabel("")
self.classFlag.setFont(fntValue)
self.classFlag.setAlignment(Qt.AlignRight)
self.classFlag.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
self.classData = QLabel("")
self.classData.setFont(fntValue)
@@ -111,8 +110,7 @@ class GuiItemDetails(QWidget):
self.layoutName.setAlignment(Qt.AlignLeft)
self.layoutFlag = QLabel("")
self.layoutFlag.setFont(fntValue)
self.layoutFlag.setAlignment(Qt.AlignRight)
self.layoutFlag.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
self.layoutData = QLabel("")
self.layoutData.setFont(fntValue)
@@ -229,18 +227,15 @@ class GuiItemDetails(QWidget):
return
self._itemHandle = tHandle
iPx = int(round(0.8*self.theTheme.baseIconSize))
# Label
# =====
theLabel = nwItem.itemName
if len(theLabel) > 100:
theLabel = theLabel[:96].rstrip()+" ..."
itStatus = nwItem.itemStatus
if nwItem.itemClass == nwItemClass.NOVEL:
itStatus = self.theProject.statusItems.checkEntry(itStatus) # Make sure it's valid
flagIcon = self.theParent.statusIcons[itStatus]
else:
itStatus = self.theProject.importItems.checkEntry(itStatus) # Make sure it's valid
flagIcon = self.theParent.importIcons[itStatus]
if nwItem.itemType == nwItemType.FILE:
if nwItem.isExported:
self.labelFlag.setPixmap(self._expCheck)
@@ -249,19 +244,41 @@ class GuiItemDetails(QWidget):
else:
self.labelFlag.setPixmap(QPixmap(1, 1))
iPx = int(round(0.8*self.theTheme.baseIconSize))
self.statusFlag.setPixmap(flagIcon.pixmap(iPx, iPx))
self.classFlag.setText(nwLabels.CLASS_FLAG[nwItem.itemClass]) # NO-I18N
if nwItem.itemLayout == nwItemLayout.NO_LAYOUT:
self.layoutFlag.setText("-")
else:
self.layoutFlag.setText(nwLabels.LAYOUT_FLAG[nwItem.itemLayout]) # NO-I18N
self.labelData.setText(theLabel)
# Status
# ======
itStatus = nwItem.itemStatus
if nwItem.itemClass == nwItemClass.NOVEL:
itStatus = self.theProject.statusItems.checkEntry(itStatus) # Make sure it's valid
flagIcon = self.theParent.statusIcons[itStatus]
else:
itStatus = self.theProject.importItems.checkEntry(itStatus) # Make sure it's valid
flagIcon = self.theParent.importIcons[itStatus]
self.statusFlag.setPixmap(flagIcon.pixmap(iPx, iPx))
self.statusData.setText(nwItem.itemStatus)
# Class
# =====
classIcon = self.theTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
self.classFlag.setPixmap(classIcon.pixmap(iPx, iPx))
self.classData.setText(trConst(nwLabels.CLASS_NAME[nwItem.itemClass]))
self.layoutData.setText(trConst(nwLabels.LAYOUT_NAME[nwItem.itemLayout]))
# Layout
# ======
hLevel = self.theParent.theIndex.getHandleHeaderLevel(tHandle)
layoutIcon = self.theTheme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
)
self.layoutFlag.setPixmap(layoutIcon.pixmap(iPx, iPx))
self.layoutData.setText(nwItem.describeMe(hLevel))
# Counts
# ======
if nwItem.itemType == nwItemType.FILE:
self.cCountData.setText(f"{nwItem.charCount:n}")
+23 -25
View File
@@ -47,7 +47,7 @@ class GuiProjectTree(QTreeWidget):
C_NAME = 0
C_COUNT = 1
C_EXPORT = 2
C_FLAGS = 3
C_STATUS = 3
novelItemChanged = pyqtSignal()
noteItemChanged = pyqtSignal()
@@ -86,10 +86,8 @@ class GuiProjectTree(QTreeWidget):
self.setIndentation(iPx)
self.setColumnCount(4)
self.setHeaderLabels([
self.tr("Label"),
self.tr("Words"),
self.tr("Inc"),
self.tr("Flags")
self.tr("Label"), self.tr("Words"), "",
self.tr("Status") if self.mainConf.fullStatus else ""
])
treeHeadItem = self.headerItem()
@@ -97,7 +95,7 @@ class GuiProjectTree(QTreeWidget):
treeHeadItem.setToolTip(self.C_NAME, self.tr("Item label"))
treeHeadItem.setToolTip(self.C_COUNT, self.tr("Word count"))
treeHeadItem.setToolTip(self.C_EXPORT, self.tr("Include in build"))
treeHeadItem.setToolTip(self.C_FLAGS, self.tr("Status, class, and layout flags"))
treeHeadItem.setToolTip(self.C_STATUS, self.tr("Item status"))
# Let the last column stretch, and set the minimum size to the
# size of the icon as the default Qt font metrics approach fails
@@ -126,7 +124,7 @@ class GuiProjectTree(QTreeWidget):
self.setColumnWidth(colN, colW)
# The last column should just auto-scale
self.resizeColumnToContents(self.C_FLAGS)
self.resizeColumnToContents(self.C_STATUS)
# Set custom settings
self.initTree()
@@ -605,11 +603,11 @@ class GuiProjectTree(QTreeWidget):
"""
trItem = self._getTreeItem(tHandle)
nwItem = self.theProject.projTree[tHandle]
if trItem is None or nwItem is None:
return
expIcon = QIcon()
stFlags = nwLabels.CLASS_FLAG[nwItem.itemClass]
if nwItem.itemType == nwItemType.FILE:
stFlags += "."+nwLabels.LAYOUT_FLAG[nwItem.itemLayout]
if nwItem.isExported:
expIcon = self.theTheme.getIcon("check")
else:
@@ -618,15 +616,25 @@ class GuiProjectTree(QTreeWidget):
iStatus = nwItem.itemStatus
if nwItem.itemClass == nwItemClass.NOVEL:
iStatus = self.theProject.statusItems.checkEntry(iStatus) # Make sure it's valid
flagIcon = self.theParent.statusIcons[iStatus]
statIcon = self.theParent.statusIcons[iStatus]
else:
iStatus = self.theProject.importItems.checkEntry(iStatus) # Make sure it's valid
flagIcon = self.theParent.importIcons[iStatus]
statIcon = self.theParent.importIcons[iStatus]
hLevel = self.theIndex.getHandleHeaderLevel(tHandle)
itemIcon = self.theTheme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
)
trItem.setIcon(self.C_NAME, itemIcon)
trItem.setText(self.C_NAME, nwItem.itemName)
trItem.setIcon(self.C_EXPORT, expIcon)
trItem.setIcon(self.C_FLAGS, flagIcon)
trItem.setText(self.C_FLAGS, stFlags)
trItem.setIcon(self.C_STATUS, statIcon)
if self.mainConf.fullStatus:
trItem.setText(self.C_STATUS, nwItem.itemStatus)
else:
trItem.setToolTip(self.C_STATUS, nwItem.itemStatus)
return
@@ -962,18 +970,17 @@ class GuiProjectTree(QTreeWidget):
"""
tHandle = nwItem.itemHandle
pHandle = nwItem.itemParent
tClass = nwItem.itemClass
newItem = QTreeWidgetItem([""]*4)
newItem.setText(self.C_NAME, "")
newItem.setText(self.C_COUNT, "0")
newItem.setText(self.C_EXPORT, "")
newItem.setText(self.C_FLAGS, "")
newItem.setText(self.C_STATUS, "")
newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft)
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight)
newItem.setTextAlignment(self.C_EXPORT, Qt.AlignLeft)
newItem.setTextAlignment(self.C_FLAGS, Qt.AlignLeft)
newItem.setTextAlignment(self.C_STATUS, Qt.AlignLeft)
newItem.setData(self.C_NAME, Qt.UserRole, tHandle)
newItem.setData(self.C_COUNT, Qt.UserRole, 0)
@@ -1008,15 +1015,6 @@ class GuiProjectTree(QTreeWidget):
self.setTreeItemValues(tHandle)
newItem.setExpanded(nwItem.isExpanded)
if nwItem.itemType == nwItemType.ROOT:
newItem.setIcon(self.C_NAME, self.theTheme.getIcon(nwLabels.CLASS_ICON[tClass]))
elif nwItem.itemType == nwItemType.FOLDER:
newItem.setIcon(self.C_NAME, self.theTheme.getIcon("proj_folder"))
elif nwItem.itemType == nwItemType.FILE:
newItem.setIcon(self.C_NAME, self.theTheme.getIcon("proj_document"))
elif nwItem.itemType == nwItemType.TRASH:
newItem.setIcon(self.C_NAME, self.theTheme.getIcon(nwLabels.CLASS_ICON[tClass]))
self._setTreeChanged(True)
return newItem
+36 -1
View File
@@ -37,8 +37,9 @@ from PyQt5.QtGui import (
QPalette, QColor, QIcon, QFont, QFontMetrics, QFontDatabase, QPixmap
)
from nw.enum import nwAlert
from nw.enum import nwAlert, nwItemLayout, nwItemType
from nw.common import NWConfigParser
from nw.constants import nwLabels
logger = logging.getLogger(__name__)
@@ -126,8 +127,10 @@ class GuiTheme:
self.updateTheme()
self.theIcons.updateTheme()
# Icon Functions
self.getIcon = self.theIcons.getIcon
self.getPixmap = self.theIcons.getPixmap
self.getItemIcon = self.theIcons.getItemIcon
self.loadDecoration = self.theIcons.loadDecoration
# Extract Other Info
@@ -533,6 +536,10 @@ class GuiIcons:
"cls_archive": (QStyle.SP_DriveHDIcon, "drive-harddisk"),
"cls_trash": (QStyle.SP_DriveHDIcon, "drive-harddisk"),
"proj_document": (QStyle.SP_FileIcon, "x-office-document"),
"proj_title": (QStyle.SP_FileIcon, "x-office-document"),
"proj_chapter": (QStyle.SP_FileIcon, "x-office-document"),
"proj_scene": (QStyle.SP_FileIcon, "x-office-document"),
"proj_note": (QStyle.SP_FileIcon, "x-office-document"),
"proj_folder": (QStyle.SP_DirIcon, "folder"),
"proj_nwx": (None, None),
"status_lang": (None, None),
@@ -721,6 +728,34 @@ class GuiIcons:
qIcon = self.getIcon(iconKey)
return qIcon.pixmap(iconSize[0], iconSize[1], QIcon.Normal)
def getItemIcon(self, tType, tClass, tLayout, hLevel="H0"):
"""Get the correct icon for a project item based on type, class
and header level
"""
iconName = None
if tType == nwItemType.ROOT:
iconName = nwLabels.CLASS_ICON[tClass]
elif tType == nwItemType.FOLDER:
iconName = "proj_folder"
elif tType == nwItemType.FILE:
iconName = "proj_document"
if tLayout == nwItemLayout.DOCUMENT:
if hLevel == "H1":
iconName = "proj_title"
elif hLevel == "H2":
iconName = "proj_chapter"
elif hLevel == "H3":
iconName = "proj_scene"
elif tLayout == nwItemLayout.NOTE:
iconName = "proj_note"
elif tType == nwItemType.TRASH:
iconName = nwLabels.CLASS_ICON[tClass]
if iconName is None:
return QIcon()
return self.getIcon(iconName)
def listThemes(self):
"""Scan the icons themes folder and list all themes.
"""