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.colIndex = {} self.treeNCols = 0 for i, hItem in enumerate(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, theParent): QMenu.__init__(self, theParent) self.theParent = theParent 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(isChecked, tItem) ) self.addAction(self.actionMap[hItem]) return
def __init__(self, theParent=None, currentQuote="\""): QDialog.__init__(self, parent=theParent) self.mainConf = nw.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 __init__(self, theParent, theProject, tHandle): QDialog.__init__(self, theParent) logger.debug("Initialising GuiItemEditor ...") self.setObjectName("GuiItemEditor") self.mainConf = nw.CONFIG self.theProject = theProject self.theParent = theParent ## # Build GUI ## self.theItem = self.theProject.projTree[tHandle] if self.theItem is None: self._doClose() 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, _, _ in self.theProject.statusItems: self.editStatus.addItem( self.theParent.statusIcons[sLabel], sLabel, sLabel ) else: for sLabel, _, _ in self.theProject.importItems: self.editStatus.addItem( self.theParent.importIcons[sLabel], 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.TITLE) validLayouts.append(nwItemLayout.BOOK) validLayouts.append(nwItemLayout.PAGE) validLayouts.append(nwItemLayout.PARTITION) validLayouts.append(nwItemLayout.UNNUMBERED) validLayouts.append(nwItemLayout.CHAPTER) validLayouts.append(nwItemLayout.SCENE) 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() statusIdx = self.editStatus.findData(self.theItem.itemStatus) 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 _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.setStatusTip(self.tr("Insert short dash (en dash)")) 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.setStatusTip(self.tr("Insert long dash (em dash)")) 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.setStatusTip( self.tr("Insert a horizontal bar (quotation dash)")) 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.setStatusTip( self.tr("Insert figure dash (same width as a number character)")) 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.setStatusTip(self.tr("Insert left single quote")) 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.setStatusTip(self.tr("Insert right single quote")) 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.setStatusTip(self.tr("Insert left double quote")) 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.setStatusTip(self.tr("Insert right double quote")) 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.setStatusTip( self.tr("Insert modifier letter single apostrophe")) 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.setStatusTip(self.tr("Insert ellipsis")) 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.setStatusTip(self.tr("Insert a prime symbol")) 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.setStatusTip(self.tr("Insert a double prime symbol")) self.aInsDPrime.setShortcut("Ctrl+K, Ctrl+\"") self.aInsDPrime.triggered.connect( lambda: self._docInsert(nwUnicode.U_DPRIME)) self.mInsPunct.addAction(self.aInsDPrime) # Insert > Breaks and Spaces self.mInsBreaks = self.insertMenu.addMenu(self.tr("Breaks and Spaces")) # Insert > Hard Line Break self.aInsHardBreak = QAction(self.tr("Hard Line Break"), self) self.aInsHardBreak.setStatusTip(self.tr("Insert a hard line break")) self.aInsHardBreak.setShortcut("Ctrl+K, Return") self.aInsHardBreak.triggered.connect( lambda: self._docInsert(nwDocInsert.HARD_BREAK)) self.mInsBreaks.addAction(self.aInsHardBreak) # Insert > Non-Breaking Space self.aInsNBSpace = QAction(self.tr("Non-Breaking Space"), self) self.aInsNBSpace.setStatusTip(self.tr("Insert a non-breaking space")) self.aInsNBSpace.setShortcut("Ctrl+K, Space") self.aInsNBSpace.triggered.connect( lambda: self._docInsert(nwUnicode.U_NBSP)) self.mInsBreaks.addAction(self.aInsNBSpace) # Insert > Thin Space self.aInsThinSpace = QAction(self.tr("Thin Space"), self) self.aInsThinSpace.setStatusTip(self.tr("Insert a thin space")) self.aInsThinSpace.setShortcut("Ctrl+K, Shift+Space") self.aInsThinSpace.triggered.connect( lambda: self._docInsert(nwUnicode.U_THSP)) self.mInsBreaks.addAction(self.aInsThinSpace) # Insert > Thin Non-Breaking Space self.aInsThinNBSpace = QAction(self.tr("Thin Non-Breaking Space"), self) self.aInsThinNBSpace.setStatusTip( self.tr("Insert a thin non-breaking space")) self.aInsThinNBSpace.setShortcut("Ctrl+K, Ctrl+Space") self.aInsThinNBSpace.triggered.connect( lambda: self._docInsert(nwUnicode.U_THNBSP)) self.mInsBreaks.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.setStatusTip(self.tr("Insert a list bullet")) 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.setStatusTip( self.tr("Insert a hyphen bullet (alternative bullet)")) 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.setStatusTip( self.tr("Insert a flower mark (alternative bullet)")) 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.setStatusTip(self.tr("Insert a per mille symbol")) 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.setStatusTip(self.tr("Insert a degree symbol")) 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.setStatusTip( self.tr("Insert a minus sign (not a hypen or dash)")) 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.setStatusTip( self.tr("Insert a times sign (multiplication cross)")) 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.setStatusTip(self.tr("Insert a division sign")) self.aInsDivide.setShortcut("Ctrl+K, Ctrl+D") self.aInsDivide.triggered.connect( lambda: self._docInsert(nwUnicode.U_DIVIDE)) self.mInsSymbol.addAction(self.aInsDivide) # Insert > Separator self.insertMenu.addSeparator() # 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]) 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.colIndex[hItem] = i self.setHeaderLabels(theLabels) for hItem in self.treeOrder: self.setColumnWidth(self.colIndex[hItem], self.colWidth[hItem]) self.setColumnHidden(self.colIndex[hItem], self.colHidden[hItem]) # Make sure title column is always visible, # and handle column always hidden self.setColumnHidden(self.colIndex[nwOutline.TITLE], False) headItem = self.headerItem() headItem.setTextAlignment(self.colIndex[nwOutline.CCOUNT], Qt.AlignRight) headItem.setTextAlignment(self.colIndex[nwOutline.WCOUNT], Qt.AlignRight) headItem.setTextAlignment(self.colIndex[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) self.treeMap[tKey] = tItem 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 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.theHandle = tHandle 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) else: self.labelFlag.setPixmap(self.expCross) 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) self.statusData.setText(nwItem.itemStatus) self.classData.setText(trConst(nwLabels.CLASS_NAME[nwItem.itemClass])) self.layoutData.setText( trConst(nwLabels.LAYOUT_NAME[nwItem.itemLayout])) 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 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.makeAlert( self. tr("Please select a valid location in the tree to add the document." ), nwAlert.ERROR) else: self.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.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.makeAlert( self.tr( "Did not find anywhere to add the file or folder!"), nwAlert.ERROR) return False if self.theProject.projTree.isTrashRoot(pHandle): self.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.makeAlert( (self.tr("Cannot add new folder to this item."), self.tr("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, self.theParent) curTxt = newDoc.openDocument(tHandle, showStatus=False) if curTxt == "": if nwItem.itemLayout == nwItemLayout.CHAPTER: newText = f"## {nwItem.itemName}\n\n" elif nwItem.itemLayout == nwItemLayout.UNNUMBERED: newText = f"## {nwItem.itemName}\n\n" elif nwItem.itemLayout == nwItemLayout.SCENE: newText = f"### {nwItem.itemName}\n\n" else: newText = f"# {nwItem.itemName}\n\n" # Save the text and index it newDoc.saveDocument(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.projectWordCount() return True
def __init__(self, theParent): QScrollArea.__init__(self, theParent) logger.debug("Initialising GuiOutlineDetails ...") self.mainConf = nw.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, theWizard): QWizardPage.__init__(self) self.mainConf = nw.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