def _addRootFolderEntry(self, itemClass): """Add a menu entry for a root folder of a given class. """ aNew = self.mAddRoot.addAction(trConst(nwLabels.CLASS_NAME[itemClass])) aNew.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[itemClass])) aNew.triggered.connect( lambda: self.projTree.newTreeItem(nwItemType.ROOT, itemClass)) self.mAddRoot.addAction(aNew)
def describeMe(self, hLevel=None): """Return a string description of the item. """ descKey = "none" if self._type == nwItemType.ROOT: descKey = "root" elif self._type == nwItemType.FOLDER: descKey = "folder" elif self._type == nwItemType.FILE: if self._layout == nwItemLayout.DOCUMENT: if hLevel == "H1": descKey = "doc_h1" elif hLevel == "H2": descKey = "doc_h2" elif hLevel == "H3": descKey = "doc_h3" else: descKey = "document" elif self._layout == nwItemLayout.NOTE: descKey = "note" return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, ""))
def clearOutline(self): """Clear the tree and header and set the default values for the columns arrays. """ self.clear() self.setColumnCount(1) self.setHeaderLabel(trConst(nwLabels.OUTLINE_COLS[nwOutline.TITLE])) self._treeOrder = [] self._colWidth = {} self._colHidden = {} self._colIdx = {} self._treeNCols = 0 for hItem in nwOutline: self._treeOrder.append(hItem) self._colWidth[hItem] = self.DEF_WIDTH[hItem] self._colHidden[hItem] = self.DEF_HIDDEN[hItem] self._treeNCols = len(self._treeOrder) return
def __init__(self, theOutline): QMenu.__init__(self, theOutline) self.acceptToggle = True mnuHead = QAction(self.tr("Select Columns"), self) self.addAction(mnuHead) self.addSeparator() self.actionMap = {} for hItem in nwOutline: if hItem == nwOutline.TITLE: continue self.actionMap[hItem] = QAction( trConst(nwLabels.OUTLINE_COLS[hItem]), self) self.actionMap[hItem].setCheckable(True) self.actionMap[hItem].toggled.connect( lambda isChecked, tItem=hItem: self.columnToggled.emit( isChecked, tItem)) self.addAction(self.actionMap[hItem]) return
def _popMetaBox(self, qPos, tHandle, sTitle): """Show the novel meta data box. """ logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle) pIndex = self.theProject.index novIdx = pIndex.getNovelData(tHandle, sTitle) refTags = pIndex.getReferences(tHandle, sTitle) synopText = novIdx.synopsis if synopText: synopLabel = trConst(nwLabels.OUTLINE_COLS[nwOutline.SYNOP]) synopText = f"<p><b>{synopLabel}</b>: {synopText}</p>" refLines = [] refLines = self._appendMetaTag(refTags, nwKeyWords.POV_KEY, refLines) refLines = self._appendMetaTag(refTags, nwKeyWords.FOCUS_KEY, refLines) refLines = self._appendMetaTag(refTags, nwKeyWords.CHAR_KEY, refLines) refLines = self._appendMetaTag(refTags, nwKeyWords.PLOT_KEY, refLines) refLines = self._appendMetaTag(refTags, nwKeyWords.TIME_KEY, refLines) refLines = self._appendMetaTag(refTags, nwKeyWords.WORLD_KEY, refLines) refLines = self._appendMetaTag(refTags, nwKeyWords.OBJECT_KEY, refLines) refLines = self._appendMetaTag(refTags, nwKeyWords.ENTITY_KEY, refLines) refLines = self._appendMetaTag(refTags, nwKeyWords.CUSTOM_KEY, refLines) refText = "" if refLines: refList = "<br>".join(refLines) refText = f"<p>{refList}</p>" ttText = refText + synopText or self.tr("No meta data") if ttText: QToolTip.showText(qPos, ttText) return
def __init__(self, theParent): QScrollArea.__init__(self, theParent) logger.debug("Initialising GuiOutlineDetails ...") self.mainConf = novelwriter.CONFIG self.theParent = theParent self.theProject = theParent.theProject self.theTheme = theParent.theTheme self.theIndex = theParent.theIndex self.optState = theParent.theProject.optState # Sizes minTitle = 30 * self.theTheme.textNWidth maxTitle = 40 * self.theTheme.textNWidth wCount = self.theTheme.getTextWidth("999,999") hSpace = int(self.mainConf.pxInt(10)) vSpace = int(self.mainConf.pxInt(4)) # Details Area self.titleLabel = QLabel("<b>%s</b>" % self.tr("Title")) self.fileLabel = QLabel("<b>%s</b>" % self.tr("Document")) self.itemLabel = QLabel("<b>%s</b>" % self.tr("Status")) self.titleValue = QLabel("") self.fileValue = QLabel("") self.itemValue = QLabel("") self.titleValue.setMinimumWidth(minTitle) self.titleValue.setMaximumWidth(maxTitle) self.fileValue.setMinimumWidth(minTitle) self.fileValue.setMaximumWidth(maxTitle) self.itemValue.setMinimumWidth(minTitle) self.itemValue.setMaximumWidth(maxTitle) # Stats Area self.cCLabel = QLabel("<b>%s</b>" % self.tr("Characters")) self.wCLabel = QLabel("<b>%s</b>" % self.tr("Words")) self.pCLabel = QLabel("<b>%s</b>" % self.tr("Paragraphs")) self.cCValue = QLabel("") self.wCValue = QLabel("") self.pCValue = QLabel("") self.cCValue.setMinimumWidth(wCount) self.wCValue.setMinimumWidth(wCount) self.pCValue.setMinimumWidth(wCount) self.cCValue.setAlignment(Qt.AlignRight) self.wCValue.setAlignment(Qt.AlignRight) self.pCValue.setAlignment(Qt.AlignRight) # Synopsis self.synopLabel = QLabel("<b>%s</b>" % self.tr("Synopsis")) self.synopValue = QLabel("") self.synopLWrap = QHBoxLayout() self.synopValue.setWordWrap(True) self.synopValue.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.synopLWrap.addWidget(self.synopValue, 1) # Tags self.povKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])) self.focKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])) self.chrKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY])) self.pltKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])) self.timKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.TIME_KEY])) self.wldKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY])) self.objKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY])) self.entKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY])) self.cstKeyLabel = QLabel( "<b>%s</b>" % trConst(nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY])) self.povKeyLWrap = QHBoxLayout() self.focKeyLWrap = QHBoxLayout() self.chrKeyLWrap = QHBoxLayout() self.pltKeyLWrap = QHBoxLayout() self.timKeyLWrap = QHBoxLayout() self.wldKeyLWrap = QHBoxLayout() self.objKeyLWrap = QHBoxLayout() self.entKeyLWrap = QHBoxLayout() self.cstKeyLWrap = QHBoxLayout() self.povKeyValue = QLabel("") self.focKeyValue = QLabel("") self.chrKeyValue = QLabel("") self.pltKeyValue = QLabel("") self.timKeyValue = QLabel("") self.wldKeyValue = QLabel("") self.objKeyValue = QLabel("") self.entKeyValue = QLabel("") self.cstKeyValue = QLabel("") self.povKeyValue.setWordWrap(True) self.focKeyValue.setWordWrap(True) self.chrKeyValue.setWordWrap(True) self.pltKeyValue.setWordWrap(True) self.timKeyValue.setWordWrap(True) self.wldKeyValue.setWordWrap(True) self.objKeyValue.setWordWrap(True) self.entKeyValue.setWordWrap(True) self.cstKeyValue.setWordWrap(True) self.povKeyValue.linkActivated.connect(self._tagClicked) self.focKeyValue.linkActivated.connect(self._tagClicked) self.chrKeyValue.linkActivated.connect(self._tagClicked) self.pltKeyValue.linkActivated.connect(self._tagClicked) self.timKeyValue.linkActivated.connect(self._tagClicked) self.wldKeyValue.linkActivated.connect(self._tagClicked) self.objKeyValue.linkActivated.connect(self._tagClicked) self.entKeyValue.linkActivated.connect(self._tagClicked) self.cstKeyValue.linkActivated.connect(self._tagClicked) self.povKeyLWrap.addWidget(self.povKeyValue, 1) self.focKeyLWrap.addWidget(self.focKeyValue, 1) self.chrKeyLWrap.addWidget(self.chrKeyValue, 1) self.pltKeyLWrap.addWidget(self.pltKeyValue, 1) self.timKeyLWrap.addWidget(self.timKeyValue, 1) self.wldKeyLWrap.addWidget(self.wldKeyValue, 1) self.objKeyLWrap.addWidget(self.objKeyValue, 1) self.entKeyLWrap.addWidget(self.entKeyValue, 1) self.cstKeyLWrap.addWidget(self.cstKeyValue, 1) # Selected Item Details self.mainGroup = QGroupBox(self.tr("Title Details"), self) self.mainForm = QGridLayout() self.mainGroup.setLayout(self.mainForm) self.mainForm.addWidget(self.titleLabel, 0, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.titleValue, 0, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.cCLabel, 0, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.cCValue, 0, 3, 1, 1, Qt.AlignTop | Qt.AlignRight) self.mainForm.addWidget(self.fileLabel, 1, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.fileValue, 1, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.wCLabel, 1, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.wCValue, 1, 3, 1, 1, Qt.AlignTop | Qt.AlignRight) self.mainForm.addWidget(self.itemLabel, 2, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.itemValue, 2, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.pCLabel, 2, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addWidget(self.pCValue, 2, 3, 1, 1, Qt.AlignTop | Qt.AlignRight) self.mainForm.addWidget(self.synopLabel, 3, 0, 1, 4, Qt.AlignTop | Qt.AlignLeft) self.mainForm.addLayout(self.synopLWrap, 4, 0, 1, 4, Qt.AlignTop | Qt.AlignLeft) self.mainForm.setColumnStretch(1, 1) self.mainForm.setRowStretch(4, 1) self.mainForm.setHorizontalSpacing(hSpace) self.mainForm.setVerticalSpacing(vSpace) # Selected Item Tags self.tagsGroup = QGroupBox(self.tr("Reference Tags"), self) self.tagsForm = QGridLayout() self.tagsGroup.setLayout(self.tagsForm) self.tagsForm.addWidget(self.povKeyLabel, 0, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.povKeyLWrap, 0, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addWidget(self.focKeyLabel, 1, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.focKeyLWrap, 1, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addWidget(self.chrKeyLabel, 2, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.chrKeyLWrap, 2, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addWidget(self.pltKeyLabel, 3, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.pltKeyLWrap, 3, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addWidget(self.timKeyLabel, 4, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.timKeyLWrap, 4, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addWidget(self.wldKeyLabel, 5, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.wldKeyLWrap, 5, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addWidget(self.objKeyLabel, 6, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.objKeyLWrap, 6, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addWidget(self.entKeyLabel, 7, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.entKeyLWrap, 7, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addWidget(self.cstKeyLabel, 8, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.addLayout(self.cstKeyLWrap, 8, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft) self.tagsForm.setColumnStretch(1, 1) self.tagsForm.setRowStretch(8, 1) self.tagsForm.setHorizontalSpacing(hSpace) self.tagsForm.setVerticalSpacing(vSpace) # Assemble self.outerWidget = QWidget() self.outerBox = QHBoxLayout() self.outerBox.addWidget(self.mainGroup, 0) self.outerBox.addWidget(self.tagsGroup, 1) self.outerWidget.setLayout(self.outerBox) self.setWidget(self.outerWidget) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setWidgetResizable(True) self.initDetails() logger.debug("GuiOutlineDetails initialisation complete") return
def __init__(self, theParent=None, currentQuote='"'): QDialog.__init__(self, parent=theParent) self.mainConf = novelwriter.CONFIG self.outerBox = QVBoxLayout() self.innerBox = QHBoxLayout() self.labelBox = QVBoxLayout() self.selectedQuote = currentQuote qMetrics = QFontMetrics(self.font()) pxW = 7 * qMetrics.boundingRectChar("M").width() pxH = 7 * qMetrics.boundingRectChar("M").height() pxH = 7 * qMetrics.boundingRectChar("M").height() lblFont = self.font() lblFont.setPointSizeF(4 * lblFont.pointSizeF()) # Preview Label self.previewLabel = QLabel(currentQuote) self.previewLabel.setFont(lblFont) self.previewLabel.setFixedSize(QSize(pxW, pxH)) self.previewLabel.setAlignment(Qt.AlignCenter) self.previewLabel.setFrameStyle(QFrame.Box | QFrame.Plain) # Quote Symbols self.listBox = QListWidget() self.listBox.itemSelectionChanged.connect(self._selectedSymbol) minSize = 100 for sKey, sLabel in nwQuotes.SYMBOLS.items(): theText = "[ %s ] %s" % (sKey, trConst(sLabel)) minSize = max(minSize, qMetrics.boundingRect(theText).width()) qtItem = QListWidgetItem(theText) qtItem.setData(Qt.UserRole, sKey) self.listBox.addItem(qtItem) if sKey == currentQuote: self.listBox.setCurrentItem(qtItem) self.listBox.setMinimumWidth(minSize + self.mainConf.pxInt(40)) self.listBox.setMinimumHeight(self.mainConf.pxInt(150)) # Buttons self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonBox.accepted.connect(self._doAccept) self.buttonBox.rejected.connect(self._doReject) # Assemble self.labelBox.addWidget(self.previewLabel, 0, Qt.AlignTop) self.labelBox.addStretch(1) self.innerBox.addLayout(self.labelBox) self.innerBox.addWidget(self.listBox) self.outerBox.addLayout(self.innerBox) self.outerBox.addWidget(self.buttonBox) self.setLayout(self.outerBox) return
def _populateTree(self): """Build the tree based on the project index, and the header based on the defined constants, default values and user selected width, order and hidden state. All columns are populated, even if they are hidden. This ensures that showing and hiding columns is fast and doesn't require a rebuild of the tree. """ self.clear() if self._firstView: theLabels = [] for i, hItem in enumerate(self._treeOrder): theLabels.append(trConst(nwLabels.OUTLINE_COLS[hItem])) self._colIdx[hItem] = i self.setHeaderLabels(theLabels) for hItem in self._treeOrder: self.setColumnWidth(self._colIdx[hItem], self._colWidth[hItem]) self.setColumnHidden(self._colIdx[hItem], self._colHidden[hItem]) # Make sure title column is always visible, # and handle column always hidden self.setColumnHidden(self._colIdx[nwOutline.TITLE], False) headItem = self.headerItem() headItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], Qt.AlignRight) headItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight) headItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight) currTitle = None currChapter = None currScene = None for tKey, tHandle, sTitle, novIdx in self.theIndex.novelStructure( skipExcluded=True): tItem = self._createTreeItem(tHandle, sTitle, novIdx) tLevel = novIdx["level"] if tLevel == "H1": self.addTopLevelItem(tItem) currTitle = tItem currChapter = None currScene = None elif tLevel == "H2": if currTitle is None: self.addTopLevelItem(tItem) else: currTitle.addChild(tItem) currChapter = tItem currScene = None elif tLevel == "H3": if currChapter is None: if currTitle is None: self.addTopLevelItem(tItem) else: currTitle.addChild(tItem) else: currChapter.addChild(tItem) currScene = tItem elif tLevel == "H4": if currScene is None: if currChapter is None: if currTitle is None: self.addTopLevelItem(tItem) else: currTitle.addChild(tItem) else: currChapter.addChild(tItem) else: currScene.addChild(tItem) tItem.setExpanded(True) self._lastBuild = time() return
def _buildInsertMenu(self): """Assemble the Insert menu. """ # Insert self.insertMenu = self.addMenu(self.tr("&Insert")) # Insert > Dashes and Dots self.mInsDashes = self.insertMenu.addMenu(self.tr("Dashes")) # Insert > Short Dash self.aInsENDash = QAction(self.tr("Short Dash"), self) self.aInsENDash.setShortcut("Ctrl+K, -") self.aInsENDash.triggered.connect( lambda: self._docInsert(nwUnicode.U_ENDASH)) self.mInsDashes.addAction(self.aInsENDash) # Insert > Long Dash self.aInsEMDash = QAction(self.tr("Long Dash"), self) self.aInsEMDash.setShortcut("Ctrl+K, _") self.aInsEMDash.triggered.connect( lambda: self._docInsert(nwUnicode.U_EMDASH)) self.mInsDashes.addAction(self.aInsEMDash) # Insert > Long Dash self.aInsHorBar = QAction(self.tr("Horizontal Bar"), self) self.aInsHorBar.setShortcut("Ctrl+K, Ctrl+_") self.aInsHorBar.triggered.connect( lambda: self._docInsert(nwUnicode.U_HBAR)) self.mInsDashes.addAction(self.aInsHorBar) # Insert > Figure Dash self.aInsFigDash = QAction(self.tr("Figure Dash"), self) self.aInsFigDash.setShortcut("Ctrl+K, ~") self.aInsFigDash.triggered.connect( lambda: self._docInsert(nwUnicode.U_FGDASH)) self.mInsDashes.addAction(self.aInsFigDash) # Insert > Quote Marks self.mInsQuotes = self.insertMenu.addMenu(self.tr("Quote Marks")) # Insert > Left Single Quote self.aInsQuoteLS = QAction(self.tr("Left Single Quote"), self) self.aInsQuoteLS.setShortcut("Ctrl+K, 1") self.aInsQuoteLS.triggered.connect( lambda: self._docInsert(nwDocInsert.QUOTE_LS)) self.mInsQuotes.addAction(self.aInsQuoteLS) # Insert > Right Single Quote self.aInsQuoteRS = QAction(self.tr("Right Single Quote"), self) self.aInsQuoteRS.setShortcut("Ctrl+K, 2") self.aInsQuoteRS.triggered.connect( lambda: self._docInsert(nwDocInsert.QUOTE_RS)) self.mInsQuotes.addAction(self.aInsQuoteRS) # Insert > Left Double Quote self.aInsQuoteLD = QAction(self.tr("Left Double Quote"), self) self.aInsQuoteLD.setShortcut("Ctrl+K, 3") self.aInsQuoteLD.triggered.connect( lambda: self._docInsert(nwDocInsert.QUOTE_LD)) self.mInsQuotes.addAction(self.aInsQuoteLD) # Insert > Right Double Quote self.aInsQuoteRD = QAction(self.tr("Right Double Quote"), self) self.aInsQuoteRD.setShortcut("Ctrl+K, 4") self.aInsQuoteRD.triggered.connect( lambda: self._docInsert(nwDocInsert.QUOTE_RD)) self.mInsQuotes.addAction(self.aInsQuoteRD) # Insert > Alternative Apostrophe self.aInsMSApos = QAction(self.tr("Alternative Apostrophe"), self) self.aInsMSApos.setShortcut("Ctrl+K, '") self.aInsMSApos.triggered.connect( lambda: self._docInsert(nwUnicode.U_MAPOSS)) self.mInsQuotes.addAction(self.aInsMSApos) # Insert > Symbols self.mInsPunct = self.insertMenu.addMenu( self.tr("General Punctuation")) # Insert > Ellipsis self.aInsEllipsis = QAction(self.tr("Ellipsis"), self) self.aInsEllipsis.setShortcut("Ctrl+K, .") self.aInsEllipsis.triggered.connect( lambda: self._docInsert(nwUnicode.U_HELLIP)) self.mInsPunct.addAction(self.aInsEllipsis) # Insert > Prime self.aInsPrime = QAction(self.tr("Prime"), self) self.aInsPrime.setShortcut("Ctrl+K, Ctrl+'") self.aInsPrime.triggered.connect( lambda: self._docInsert(nwUnicode.U_PRIME)) self.mInsPunct.addAction(self.aInsPrime) # Insert > Double Prime self.aInsDPrime = QAction(self.tr("Double Prime"), self) self.aInsDPrime.setShortcut("Ctrl+K, Ctrl+\"") self.aInsDPrime.triggered.connect( lambda: self._docInsert(nwUnicode.U_DPRIME)) self.mInsPunct.addAction(self.aInsDPrime) # Insert > White Spaces self.mInsSpace = self.insertMenu.addMenu(self.tr("White Spaces")) # Insert > Non-Breaking Space self.aInsNBSpace = QAction(self.tr("Non-Breaking Space"), self) self.aInsNBSpace.setShortcut("Ctrl+K, Space") self.aInsNBSpace.triggered.connect( lambda: self._docInsert(nwUnicode.U_NBSP)) self.mInsSpace.addAction(self.aInsNBSpace) # Insert > Thin Space self.aInsThinSpace = QAction(self.tr("Thin Space"), self) self.aInsThinSpace.setShortcut("Ctrl+K, Shift+Space") self.aInsThinSpace.triggered.connect( lambda: self._docInsert(nwUnicode.U_THSP)) self.mInsSpace.addAction(self.aInsThinSpace) # Insert > Thin Non-Breaking Space self.aInsThinNBSpace = QAction(self.tr("Thin Non-Breaking Space"), self) self.aInsThinNBSpace.setShortcut("Ctrl+K, Ctrl+Space") self.aInsThinNBSpace.triggered.connect( lambda: self._docInsert(nwUnicode.U_THNBSP)) self.mInsSpace.addAction(self.aInsThinNBSpace) # Insert > Symbols self.mInsSymbol = self.insertMenu.addMenu(self.tr("Other Symbols")) # Insert > List Bullet self.aInsBullet = QAction(self.tr("List Bullet"), self) self.aInsBullet.setShortcut("Ctrl+K, *") self.aInsBullet.triggered.connect( lambda: self._docInsert(nwUnicode.U_BULL)) self.mInsSymbol.addAction(self.aInsBullet) # Insert > Hyphen Bullet self.aInsHyBull = QAction(self.tr("Hyphen Bullet"), self) self.aInsHyBull.setShortcut("Ctrl+K, Ctrl+-") self.aInsHyBull.triggered.connect( lambda: self._docInsert(nwUnicode.U_HYBULL)) self.mInsSymbol.addAction(self.aInsHyBull) # Insert > Flower Mark self.aInsFlower = QAction(self.tr("Flower Mark"), self) self.aInsFlower.setShortcut("Ctrl+K, Ctrl+*") self.aInsFlower.triggered.connect( lambda: self._docInsert(nwUnicode.U_FLOWER)) self.mInsSymbol.addAction(self.aInsFlower) # Insert > Per Mille self.aInsPerMille = QAction(self.tr("Per Mille"), self) self.aInsPerMille.setShortcut("Ctrl+K, %") self.aInsPerMille.triggered.connect( lambda: self._docInsert(nwUnicode.U_PERMIL)) self.mInsSymbol.addAction(self.aInsPerMille) # Insert > Degree Symbol self.aInsDegree = QAction(self.tr("Degree Symbol"), self) self.aInsDegree.setShortcut("Ctrl+K, Ctrl+O") self.aInsDegree.triggered.connect( lambda: self._docInsert(nwUnicode.U_DEGREE)) self.mInsSymbol.addAction(self.aInsDegree) # Insert > Minus Sign self.aInsMinus = QAction(self.tr("Minus Sign"), self) self.aInsMinus.setShortcut("Ctrl+K, Ctrl+M") self.aInsMinus.triggered.connect( lambda: self._docInsert(nwUnicode.U_MINUS)) self.mInsSymbol.addAction(self.aInsMinus) # Insert > Times Sign self.aInsTimes = QAction(self.tr("Times Sign"), self) self.aInsTimes.setShortcut("Ctrl+K, Ctrl+X") self.aInsTimes.triggered.connect( lambda: self._docInsert(nwUnicode.U_TIMES)) self.mInsSymbol.addAction(self.aInsTimes) # Insert > Division self.aInsDivide = QAction(self.tr("Division Sign"), self) self.aInsDivide.setShortcut("Ctrl+K, Ctrl+D") self.aInsDivide.triggered.connect( lambda: self._docInsert(nwUnicode.U_DIVIDE)) self.mInsSymbol.addAction(self.aInsDivide) # Insert > Tags and References self.mInsKeywords = self.insertMenu.addMenu( self.tr("Tags and References")) self.mInsKWItems = {} self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G") self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V") self.mInsKWItems[nwKeyWords.FOCUS_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, F") self.mInsKWItems[nwKeyWords.CHAR_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, C") self.mInsKWItems[nwKeyWords.PLOT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, P") self.mInsKWItems[nwKeyWords.TIME_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, T") self.mInsKWItems[nwKeyWords.WORLD_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, L") self.mInsKWItems[nwKeyWords.OBJECT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, O") self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E") self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X") for n, keyWord in enumerate(self.mInsKWItems): self.mInsKWItems[keyWord][0].setText( trConst(nwLabels.KEY_NAME[keyWord])) self.mInsKWItems[keyWord][0].setShortcut( self.mInsKWItems[keyWord][1]) self.mInsKWItems[keyWord][0].triggered.connect( lambda n, keyWord=keyWord: self._insertKeyWord(keyWord)) self.mInsKeywords.addAction(self.mInsKWItems[keyWord][0]) # Insert > Symbols self.mInsBreaks = self.insertMenu.addMenu( self.tr("Page Break and Space")) # Insert > New Page self.aInsNewPage = QAction(self.tr("Page Break"), self) self.aInsNewPage.triggered.connect( lambda: self._docInsert(nwDocInsert.NEW_PAGE)) self.mInsBreaks.addAction(self.aInsNewPage) # Insert > Vertical Space (Single) self.aInsVSpaceS = QAction(self.tr("Vertical Space (Single)"), self) self.aInsVSpaceS.triggered.connect( lambda: self._docInsert(nwDocInsert.VSPACE_S)) self.mInsBreaks.addAction(self.aInsVSpaceS) # Insert > Vertical Space (Multi) self.aInsVSpaceM = QAction(self.tr("Vertical Space (Multi)"), self) self.aInsVSpaceM.triggered.connect( lambda: self._docInsert(nwDocInsert.VSPACE_M)) self.mInsBreaks.addAction(self.aInsVSpaceM) # Insert > Placeholder Text self.aLipsumText = QAction(self.tr("Placeholder Text"), self) self.aLipsumText.triggered.connect( lambda: self.mainGui.showLoremIpsumDialog()) self.insertMenu.addAction(self.aLipsumText) return
def newTreeItem(self, itemType, itemClass): """Add new item to the tree, with a given itemType and itemClass, and attach it to the selected handle. Also make sure the item is added in a place it can be added, and that other meta data is set correctly to ensure a valid project tree. """ pHandle = self.getSelectedHandle() nHandle = None if not self.theParent.hasProject: logger.error("No project open") return False if not isinstance(itemType, nwItemType): # This would indicate an internal bug logger.error("No itemType provided") return False # The item needs to be assigned an item class, so one must be # provided, or it must be possible to extract it from the parent # item of the new item. if itemClass is None and pHandle is not None: pItem = self.theProject.projTree[pHandle] if pItem is not None: itemClass = pItem.itemClass # If class is still not set, alert the user and exit if itemClass is None: if itemType == nwItemType.FILE: self.theParent.makeAlert( self. tr("Please select a valid location in the tree to add the document." ), nwAlert.ERROR) else: self.theParent.makeAlert( self. tr("Please select a valid location in the tree to add the folder." ), nwAlert.ERROR) return False # Everything is fine, we have what we need, so we proceed logger.verbose( "Adding new item of type '%s' and class '%s' to handle '%s'", itemType.name, itemClass.name, str(pHandle)) if itemType == nwItemType.ROOT: tHandle = self.theProject.newRoot( trConst(nwLabels.CLASS_NAME[itemClass]), itemClass) if tHandle is None: logger.error("No root item added") return False else: # If no parent has been selected, make the new file under # the root NOVEL item. if pHandle is None: pHandle = self.theProject.projTree.findRoot(nwItemClass.NOVEL) # If still nothing, give up if pHandle is None: self.theParent.makeAlert( self.tr( "Did not find anywhere to add the file or folder!"), nwAlert.ERROR) return False # Now check if the selected item is a file, in which case # the new file will be a sibling pItem = self.theProject.projTree[pHandle] if pItem.itemType == nwItemType.FILE: nHandle = pHandle pHandle = pItem.itemParent # If we again have no home, give up if pHandle is None: self.theParent.makeAlert( self.tr( "Did not find anywhere to add the file or folder!"), nwAlert.ERROR) return False if self.theProject.projTree.isTrashRoot(pHandle): self.theParent.makeAlert( self. tr("Cannot add new files or folders to the Trash folder."), nwAlert.ERROR) return False parTree = self.theProject.projTree.getItemPath(pHandle) # If we're still here, add the file or folder if itemType == nwItemType.FILE: tHandle = self.theProject.newFile(self.tr("New File"), itemClass, pHandle) elif itemType == nwItemType.FOLDER: if len(parTree) >= nwConst.MAX_DEPTH - 1: # Folders cannot be deeper than MAX_DEPTH - 1, leaving room # for one more level of files. self.theParent.makeAlert( self.tr("Cannot add new folder to this item. " "Maximum folder depth has been reached."), nwAlert.ERROR) return False tHandle = self.theProject.newFolder(self.tr("New Folder"), itemClass, pHandle) else: logger.error("Failed to add new item") return False # If there is no handle set, return here if tHandle is None: return True # Add the new item to the tree self.revealNewTreeItem(tHandle, nHandle) self.theParent.editItem(tHandle) nwItem = self.theProject.projTree[tHandle] # If this is a folder, return here if nwItem.itemType != nwItemType.FILE: return True # This is a new files, so let's add some content newDoc = NWDoc(self.theProject, tHandle) curTxt = newDoc.readDocument() if curTxt is None: curTxt = "" if curTxt == "": if nwItem.itemLayout == nwItemLayout.DOCUMENT: newText = f"### {nwItem.itemName}\n\n" else: newText = f"# {nwItem.itemName}\n\n" # Save the text and index it newDoc.writeDocument(newText) self.theIndex.scanText(tHandle, newText) # Get Word Counts cC, wC, pC = self.theIndex.getCounts(tHandle) nwItem.setCharCount(cC) nwItem.setWordCount(wC) nwItem.setParaCount(pC) self.propagateCount(tHandle, wC) self.wordCountsChanged.emit() return True
def updateViewBox(self, tHandle): """Populate the details box from a given handle. """ if tHandle is None: self.clearDetails() return nwItem = self.theProject.projTree[tHandle] if nwItem is None: self.clearDetails() return self._itemHandle = tHandle iPx = int(round(0.8 * self.theTheme.baseIconSize)) # Label # ===== theLabel = nwItem.itemName if len(theLabel) > 100: theLabel = theLabel[:96].rstrip() + " ..." if nwItem.itemType == nwItemType.FILE: if nwItem.isExported: self.labelIcon.setPixmap(self._expCheck) else: self.labelIcon.setPixmap(self._expCross) else: self.labelIcon.setPixmap(QPixmap(1, 1)) self.labelData.setText(theLabel) # Status # ====== theStatus, theIcon = nwItem.getImportStatus() self.statusIcon.setPixmap(theIcon.pixmap(iPx, iPx)) self.statusData.setText(theStatus) # Class # ===== classIcon = self.theTheme.getIcon( nwLabels.CLASS_ICON[nwItem.itemClass]) self.classIcon.setPixmap(classIcon.pixmap(iPx, iPx)) self.classData.setText(trConst(nwLabels.CLASS_NAME[nwItem.itemClass])) # Layout # ====== hLevel = self.theParent.theIndex.getHandleHeaderLevel(tHandle) usageIcon = self.theTheme.getItemIcon(nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel) self.usageIcon.setPixmap(usageIcon.pixmap(iPx, iPx)) self.usageData.setText(nwItem.describeMe(hLevel)) # Counts # ====== if nwItem.itemType == nwItemType.FILE: self.cCountData.setText(f"{nwItem.charCount:n}") self.wCountData.setText(f"{nwItem.wordCount:n}") self.pCountData.setText(f"{nwItem.paraCount:n}") else: self.cCountData.setText("–") self.wCountData.setText("–") self.pCountData.setText("–") return
def __init__(self, theParent, tHandle): QDialog.__init__(self, theParent) logger.debug("Initialising GuiItemEditor ...") self.setObjectName("GuiItemEditor") self.mainConf = novelwriter.CONFIG self.theParent = theParent self.theProject = theParent.theProject ## # Build GUI ## self.theItem = self.theProject.projTree[tHandle] if self.theItem is None: self.close() return self.setWindowTitle(self.tr("Item Settings")) mVd = self.mainConf.pxInt(220) mSp = self.mainConf.pxInt(16) vSp = self.mainConf.pxInt(4) # Item Label self.editName = QLineEdit() self.editName.setMinimumWidth(mVd) self.editName.setMaxLength(200) # Item Status self.editStatus = QComboBox() self.editStatus.setMinimumWidth(mVd) if self.theItem.itemClass in nwLists.CLS_NOVEL: for sLabel, _, _, sIcon in self.theProject.statusItems: self.editStatus.addItem(sIcon, sLabel, sLabel) else: for sLabel, _, _, sIcon in self.theProject.importItems: self.editStatus.addItem(sIcon, sLabel, sLabel) # Item Layout self.editLayout = QComboBox() self.editLayout.setMinimumWidth(mVd) validLayouts = [] if self.theItem.itemType == nwItemType.FILE: if self.theItem.itemClass in nwLists.CLS_NOVEL: validLayouts.append(nwItemLayout.DOCUMENT) validLayouts.append(nwItemLayout.NOTE) else: validLayouts.append(nwItemLayout.NO_LAYOUT) self.editLayout.setEnabled(False) for itemLayout in nwItemLayout: if itemLayout in validLayouts: self.editLayout.addItem( trConst(nwLabels.LAYOUT_NAME[itemLayout]), itemLayout) # Export Switch self.textExport = QLabel(self.tr("Include when building project")) self.editExport = QSwitch() if self.theItem.itemType == nwItemType.FILE: self.editExport.setEnabled(True) self.editExport.setChecked(self.theItem.isExported) else: self.editExport.setEnabled(False) self.editExport.setChecked(False) # Buttons self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonBox.accepted.connect(self._doSave) self.buttonBox.rejected.connect(self._doClose) # Set Current Values self.editName.setText(self.theItem.itemName) self.editName.selectAll() currStatus, _ = self.theItem.getImportStatus() statusIdx = self.editStatus.findData(currStatus) if statusIdx != -1: self.editStatus.setCurrentIndex(statusIdx) layoutIdx = self.editLayout.findData(self.theItem.itemLayout) if layoutIdx != -1: self.editLayout.setCurrentIndex(layoutIdx) ## # Assemble ## nameLabel = QLabel(self.tr("Label")) statusLabel = QLabel(self.tr("Status")) layoutLabel = QLabel(self.tr("Layout")) self.mainForm = QGridLayout() self.mainForm.setVerticalSpacing(vSp) self.mainForm.setHorizontalSpacing(mSp) self.mainForm.addWidget(nameLabel, 0, 0, 1, 1) self.mainForm.addWidget(self.editName, 0, 1, 1, 2) self.mainForm.addWidget(statusLabel, 1, 0, 1, 1) self.mainForm.addWidget(self.editStatus, 1, 1, 1, 2) self.mainForm.addWidget(layoutLabel, 2, 0, 1, 1) self.mainForm.addWidget(self.editLayout, 2, 1, 1, 2) self.mainForm.addWidget(self.textExport, 3, 0, 1, 2) self.mainForm.addWidget(self.editExport, 3, 2, 1, 1) self.mainForm.setColumnStretch(0, 0) self.mainForm.setColumnStretch(1, 1) self.mainForm.setColumnStretch(2, 0) self.outerBox = QVBoxLayout() self.outerBox.setSpacing(mSp) self.outerBox.addLayout(self.mainForm) self.outerBox.addStretch(1) self.outerBox.addWidget(self.buttonBox) self.setLayout(self.outerBox) self.rejected.connect(self._doClose) logger.debug("GuiItemEditor initialisation complete") return
def __init__(self, theWizard): QWizardPage.__init__(self) self.mainConf = novelwriter.CONFIG self.theWizard = theWizard self.setTitle(self.tr("Custom Project Options")) self.theText = QLabel( self. tr("Select which additional root folders to make, and how to populate " "the Novel folder. If you don't want to add chapters or scenes, set " "the values to 0. You can add scenes without chapters.")) self.theText.setWordWrap(True) vS = self.mainConf.pxInt(12) # Root Folders self.rootGroup = QGroupBox(self.tr("Additional Root Folders")) self.rootForm = QGridLayout() self.rootGroup.setLayout(self.rootForm) self.lblPlot = QLabel( self.tr("{0} folder").format( trConst(nwLabels.CLASS_NAME[nwItemClass.PLOT]))) self.lblChar = QLabel( self.tr("{0} folder").format( trConst(nwLabels.CLASS_NAME[nwItemClass.CHARACTER]))) self.lblWorld = QLabel( self.tr("{0} folder").format( trConst(nwLabels.CLASS_NAME[nwItemClass.WORLD]))) self.lblTime = QLabel( self.tr("{0} folder").format( trConst(nwLabels.CLASS_NAME[nwItemClass.TIMELINE]))) self.lblObject = QLabel( self.tr("{0} folder").format( trConst(nwLabels.CLASS_NAME[nwItemClass.OBJECT]))) self.lblEntity = QLabel( self.tr("{0} folder").format( trConst(nwLabels.CLASS_NAME[nwItemClass.ENTITY]))) self.addPlot = QSwitch() self.addChar = QSwitch() self.addWorld = QSwitch() self.addTime = QSwitch() self.addObject = QSwitch() self.addEntity = QSwitch() self.addPlot.setChecked(True) self.addChar.setChecked(True) self.addWorld.setChecked(True) self.rootForm.addWidget(self.lblPlot, 0, 0) self.rootForm.addWidget(self.lblChar, 1, 0) self.rootForm.addWidget(self.lblWorld, 2, 0) self.rootForm.addWidget(self.lblTime, 3, 0) self.rootForm.addWidget(self.lblObject, 4, 0) self.rootForm.addWidget(self.lblEntity, 5, 0) self.rootForm.addWidget(self.addPlot, 0, 1, 1, 1, Qt.AlignRight) self.rootForm.addWidget(self.addChar, 1, 1, 1, 1, Qt.AlignRight) self.rootForm.addWidget(self.addWorld, 2, 1, 1, 1, Qt.AlignRight) self.rootForm.addWidget(self.addTime, 3, 1, 1, 1, Qt.AlignRight) self.rootForm.addWidget(self.addObject, 4, 1, 1, 1, Qt.AlignRight) self.rootForm.addWidget(self.addEntity, 5, 1, 1, 1, Qt.AlignRight) self.rootForm.setRowStretch(6, 1) # Novel Options self.novelGroup = QGroupBox(self.tr("Populate Novel Folder")) self.novelForm = QGridLayout() self.novelGroup.setLayout(self.novelForm) self.numChapters = QSpinBox() self.numChapters.setRange(0, 100) self.numChapters.setValue(5) self.numScenes = QSpinBox() self.numScenes.setRange(0, 200) self.numScenes.setValue(5) self.chFolders = QSwitch() self.chFolders.setChecked(True) self.novelForm.addWidget(QLabel(self.tr("Add chapters")), 0, 0) self.novelForm.addWidget(QLabel(self.tr("Scenes (per chapter)")), 1, 0) self.novelForm.addWidget(QLabel(self.tr("Add chapter folders")), 2, 0) self.novelForm.addWidget(self.numChapters, 0, 1, 1, 1, Qt.AlignRight) self.novelForm.addWidget(self.numScenes, 1, 1, 1, 1, Qt.AlignRight) self.novelForm.addWidget(self.chFolders, 2, 1, 1, 1, Qt.AlignRight) self.novelForm.setRowStretch(3, 1) # Wizard Fields self.registerField("addPlot", self.addPlot) self.registerField("addChar", self.addChar) self.registerField("addWorld", self.addWorld) self.registerField("addTime", self.addTime) self.registerField("addObject", self.addObject) self.registerField("addEntity", self.addEntity) self.registerField("numChapters", self.numChapters) self.registerField("numScenes", self.numScenes) self.registerField("chFolders", self.chFolders) # Assemble self.innerBox = QHBoxLayout() self.innerBox.addWidget(self.rootGroup) self.innerBox.addWidget(self.novelGroup) self.outerBox = QVBoxLayout() self.outerBox.setSpacing(vS) self.outerBox.addWidget(self.theText) self.outerBox.addLayout(self.innerBox) self.outerBox.addStretch(1) self.setLayout(self.outerBox) return
def _openContextMenu(self, clickPos): """The user right clicked an element in the project tree, so we open a context menu in-place. """ tItem = None selItem = self.itemAt(clickPos) if isinstance(selItem, QTreeWidgetItem): tHandle = selItem.data(self.C_NAME, Qt.UserRole) tItem = self.theProject.tree[tHandle] if tItem is None: logger.debug("No item found") return False ctxMenu = QMenu() # Trash Folder # ============ trashHandle = self.theProject.tree.trashRoot() if tItem.itemHandle == trashHandle and trashHandle is not None: # The trash folder only has one option ctxMenu.addAction(self.tr("Empty Trash"), lambda: self.emptyTrash()) ctxMenu.exec_(self.viewport().mapToGlobal(clickPos)) return True # Document Actions # ================ isFile = tItem.itemType == nwItemType.FILE if isFile: ctxMenu.addAction( self.tr("Open Document"), lambda: self.projView.openDocumentRequest.emit( tHandle, nwDocMode.EDIT, -1, "")) ctxMenu.addAction( self.tr("View Document"), lambda: self.projView.openDocumentRequest.emit( tHandle, nwDocMode.VIEW, -1, "")) ctxMenu.addSeparator() # Edit Item Settings # ================== ctxMenu.addAction(self.tr("Change Label"), lambda: self.renameTreeItem(tHandle)) if isFile: ctxMenu.addAction(self.tr("Toggle Exported"), lambda: self._toggleItemExported(tHandle)) if tItem.isNovelLike(): mStatus = ctxMenu.addMenu(self.tr("Change Status")) for n, (key, entry) in enumerate(self.theProject.statusItems.items()): aStatus = mStatus.addAction(entry["icon"], entry["name"]) aStatus.triggered.connect( lambda n, key=key: self._changeItemStatus(tHandle, key)) else: mImport = ctxMenu.addMenu(self.tr("Change Importance")) for n, (key, entry) in enumerate(self.theProject.importItems.items()): aImport = mImport.addAction(entry["icon"], entry["name"]) aImport.triggered.connect( lambda n, key=key: self._changeItemImport(tHandle, key)) if isFile and tItem.documentAllowed(): if tItem.itemLayout == nwItemLayout.NOTE: ctxMenu.addAction( self.tr("Change to {0}").format( trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])), lambda: self._changeItemLayout(tHandle, nwItemLayout. DOCUMENT)) else: ctxMenu.addAction( self.tr("Change to {0}").format( trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE])), lambda: self._changeItemLayout(tHandle, nwItemLayout.NOTE)) ctxMenu.addSeparator() # Delete Item # =========== if tItem.itemClass == nwItemClass.TRASH or tItem.itemType == nwItemType.ROOT: ctxMenu.addAction(self.tr("Delete Permanently"), lambda: self.deleteItem(tHandle)) else: ctxMenu.addAction(self.tr("Move to Trash"), lambda: self.deleteItem(tHandle)) ctxMenu.exec_(self.viewport().mapToGlobal(clickPos)) return True
def __init__(self, projView): QTreeWidget.__init__(self, projView) logger.debug("Initialising GuiProjectToolBar ...") self.mainConf = novelwriter.CONFIG self.projView = projView self.projTree = projView.projTree self.mainGui = projView.mainGui self.theProject = projView.mainGui.theProject self.mainTheme = projView.mainGui.mainTheme iPx = self.mainTheme.baseIconSize mPx = self.mainConf.pxInt(3) self.setContentsMargins(0, 0, 0, 0) self.setAutoFillBackground(True) qPalette = self.palette() qPalette.setBrush(QPalette.Window, qPalette.base()) self.setPalette(qPalette) fadeCol = qPalette.text().color() buttonStyle = ( "QToolButton {{padding: {0}px; border: none; background: transparent;}} " "QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}" ).format(mPx, fadeCol.red(), fadeCol.green(), fadeCol.blue()) # Widget Label self.viewLabel = QLabel("<b>%s</b>" % self.tr("Project Content")) self.viewLabel.setContentsMargins(0, 0, 0, 0) self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Move Buttons self.tbMoveU = QToolButton(self) self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up")) self.tbMoveU.setIcon(self.mainTheme.getIcon("up")) self.tbMoveU.setIconSize(QSize(iPx, iPx)) self.tbMoveU.setStyleSheet(buttonStyle) self.tbMoveU.clicked.connect(lambda: self.projTree.moveTreeItem(-1)) self.tbMoveD = QToolButton(self) self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down")) self.tbMoveD.setIcon(self.mainTheme.getIcon("down")) self.tbMoveD.setIconSize(QSize(iPx, iPx)) self.tbMoveD.setStyleSheet(buttonStyle) self.tbMoveD.clicked.connect(lambda: self.projTree.moveTreeItem(1)) # Add Item Menu self.mAdd = QMenu() self.aAddEmpty = self.mAdd.addAction( trConst(nwLabels.ITEM_DESCRIPTION["document"])) self.aAddEmpty.setIcon(self.mainTheme.getIcon("proj_document")) self.aAddEmpty.triggered.connect(lambda: self.projTree.newTreeItem( nwItemType.FILE, hLevel=0, isNote=False)) self.aAddChap = self.mAdd.addAction( trConst(nwLabels.ITEM_DESCRIPTION["doc_h2"])) self.aAddChap.setIcon(self.mainTheme.getIcon("proj_chapter")) self.aAddChap.triggered.connect(lambda: self.projTree.newTreeItem( nwItemType.FILE, hLevel=2, isNote=False)) self.aAddScene = self.mAdd.addAction( trConst(nwLabels.ITEM_DESCRIPTION["doc_h3"])) self.aAddScene.setIcon(self.mainTheme.getIcon("proj_scene")) self.aAddScene.triggered.connect(lambda: self.projTree.newTreeItem( nwItemType.FILE, hLevel=3, isNote=False)) self.aAddNote = self.mAdd.addAction( trConst(nwLabels.ITEM_DESCRIPTION["note"])) self.aAddNote.setIcon(self.mainTheme.getIcon("proj_note")) self.aAddNote.triggered.connect(lambda: self.projTree.newTreeItem( nwItemType.FILE, hLevel=1, isNote=True)) self.aAddFolder = self.mAdd.addAction( trConst(nwLabels.ITEM_DESCRIPTION["folder"])) self.aAddFolder.setIcon(self.mainTheme.getIcon("proj_folder")) self.aAddFolder.triggered.connect( lambda: self.projTree.newTreeItem(nwItemType.FOLDER)) self.mAddRoot = self.mAdd.addMenu( trConst(nwLabels.ITEM_DESCRIPTION["root"])) self._addRootFolderEntry(nwItemClass.NOVEL) self._addRootFolderEntry(nwItemClass.ARCHIVE) self.mAddRoot.addSeparator() self._addRootFolderEntry(nwItemClass.PLOT) self._addRootFolderEntry(nwItemClass.CHARACTER) self._addRootFolderEntry(nwItemClass.WORLD) self._addRootFolderEntry(nwItemClass.TIMELINE) self._addRootFolderEntry(nwItemClass.OBJECT) self._addRootFolderEntry(nwItemClass.ENTITY) self._addRootFolderEntry(nwItemClass.CUSTOM) self.tbAdd = QToolButton(self) self.tbAdd.setToolTip("%s [Ctrl+N]" % self.tr("Add Item")) self.tbAdd.setShortcut("Ctrl+N") self.tbAdd.setIcon(self.mainTheme.getIcon("add")) self.tbAdd.setIconSize(QSize(iPx, iPx)) self.tbAdd.setStyleSheet(buttonStyle) self.tbAdd.setMenu(self.mAdd) self.tbAdd.setPopupMode(QToolButton.InstantPopup) # More Options Menu self.mMore = QMenu() self.aMoreUndo = self.mMore.addAction(self.tr("Undo Move")) self.aMoreUndo.triggered.connect(lambda: self.projTree.undoLastMove()) self.aEmptyTrash = self.mMore.addAction(self.tr("Empty Trash")) self.aEmptyTrash.triggered.connect(lambda: self.projTree.emptyTrash()) self.tbMore = QToolButton(self) self.tbMore.setToolTip(self.tr("More Options")) self.tbMore.setIcon(self.mainTheme.getIcon("menu")) self.tbMore.setIconSize(QSize(iPx, iPx)) self.tbMore.setStyleSheet(buttonStyle) self.tbMore.setMenu(self.mMore) self.tbMore.setPopupMode(QToolButton.InstantPopup) # Assemble self.outerBox = QHBoxLayout() self.outerBox.addWidget(self.viewLabel) self.outerBox.addWidget(self.tbMoveU) self.outerBox.addWidget(self.tbMoveD) self.outerBox.addWidget(self.tbAdd) self.outerBox.addWidget(self.tbMore) self.outerBox.setContentsMargins(mPx, mPx, 0, mPx) self.outerBox.setSpacing(0) self.setLayout(self.outerBox) logger.debug("GuiProjectToolBar initialisation complete") return
def __init__(self, novelView): QTreeWidget.__init__(self, novelView) logger.debug("Initialising GuiNovelTree ...") self.mainConf = novelwriter.CONFIG self.novelView = novelView self.mainGui = novelView.mainGui self.mainTheme = novelView.mainGui.mainTheme self.theProject = novelView.mainGui.theProject # Internal Variables self._treeMap = {} self._lastBuild = 0 self._lastCol = NovelTreeColumn.POV self._actHandle = None # Cached Strings self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]) self._focLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY]) self._pltLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY]) # Build GUI # ========= iPx = self.mainTheme.baseIconSize cMg = self.mainConf.pxInt(6) self.setIconSize(QSize(iPx, iPx)) self.setFrameStyle(QFrame.NoFrame) self.setUniformRowHeights(True) self.setAllColumnsShowFocus(True) self.setHeaderHidden(True) self.setIndentation(0) self.setColumnCount(4) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setSelectionMode(QAbstractItemView.SingleSelection) self.setExpandsOnDoubleClick(False) self.setDragEnabled(False) # Lock the column sizes treeHeader = self.header() treeHeader.setStretchLastSection(False) treeHeader.setMinimumSectionSize(iPx + cMg) treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch) treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents) treeHeader.setSectionResizeMode(self.C_EXTRA, QHeaderView.ResizeToContents) treeHeader.setSectionResizeMode(self.C_MORE, QHeaderView.ResizeToContents) # Pre-Generate Tree Formatting fH1 = self.font() fH1.setBold(True) fH1.setUnderline(True) fH2 = self.font() fH2.setBold(True) self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()] self._pIndent = [ self.mainTheme.loadDecoration("deco_doc_h0", pxH=iPx), self.mainTheme.loadDecoration("deco_doc_h1", pxH=iPx), self.mainTheme.loadDecoration("deco_doc_h2", pxH=iPx), self.mainTheme.loadDecoration("deco_doc_h3", pxH=iPx), self.mainTheme.loadDecoration("deco_doc_h4", pxH=iPx), ] self._pMore = self.mainTheme.loadDecoration("deco_doc_more", pxH=iPx) self._pActive = self.mainTheme.loadDecoration("deco_more_on", pxH=iPx) self._pInactive = self.mainTheme.loadDecoration("deco_more_off", pxH=iPx) # Connect signals self.clicked.connect(self._treeItemClicked) self.itemDoubleClicked.connect(self._treeDoubleClick) self.itemSelectionChanged.connect(self._treeSelectionChange) # Set custom settings self.initSettings() logger.debug("GuiNovelTree initialisation complete") return