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:
committed by
GitHub
parent
cf7cd5502c
commit
97aebc5b84
+9
-12
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user