From 0f64c1fa7a692518e5ef2453aa7f4e99c6281514 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Tue, 26 May 2020 18:40:58 +0200 Subject: [PATCH 01/19] Fix the document editor and viewer margins to fit better with the document title header --- nw/gui/elements/doceditor.py | 11 ++++++++--- nw/gui/elements/docviewer.py | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index 906d4c65..082be79c 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -85,7 +85,8 @@ class GuiDocEditor(QTextEdit): # Document Title self.docTitle = GuiDocTitleBar(self, self.theProject) - self.docTitle.setGeometry(0,0,self.docTitle.width(),self.docTitle.height()) + self.docTitle.setGeometry(0, 0, self.docTitle.width(), self.docTitle.height()) + self.setViewportMargins(0, self.docTitle.height(), 0, 0) # Syntax self.hLight = GuiDocHighlighter(self.qDocument, self.theParent) @@ -336,13 +337,17 @@ class GuiDocEditor(QTextEdit): tB = self.lineWidth() tW = self.width() - 2*tB tH = self.docTitle.height() + tT = tM - tH self.docTitle.setGeometry(tB, tB, tW, tH) + self.setViewportMargins(0, tH, 0, 0) docFormat = self.qDocument.rootFrame().frameFormat() docFormat.setLeftMargin(tM) docFormat.setRightMargin(tM) - if docFormat.topMargin() < tH: - docFormat.setTopMargin(tH + 2) + if tT > 0: + docFormat.setTopMargin(tT) + else: + docFormat.setTopMargin(0) # Updating root frame triggers a QTextDocument->contentsChange # signal, which we do not want as it re-runs the syntax diff --git a/nw/gui/elements/docviewer.py b/nw/gui/elements/docviewer.py index 7fdf22e4..3ad0df6f 100644 --- a/nw/gui/elements/docviewer.py +++ b/nw/gui/elements/docviewer.py @@ -59,7 +59,8 @@ class GuiDocViewer(QTextBrowser): # Document Title self.docTitle = GuiDocTitleBar(self, self.theProject) - self.docTitle.setGeometry(0,0,self.docTitle.width(),self.docTitle.height()) + self.docTitle.setGeometry(0, 0, self.docTitle.width(), self.docTitle.height()) + self.setViewportMargins(0, self.docTitle.height(), 0, 0) theOpt = QTextOption() if self.mainConf.doJustify: @@ -218,11 +219,19 @@ class GuiDocViewer(QTextBrowser): tB = self.lineWidth() tW = self.width() - 2*tB tH = self.docTitle.height() + tT = self.mainConf.textMargin - tH self.docTitle.setGeometry(tB, tB, tW, tH) + self.setViewportMargins(0, tH, 0, 0) docFormat = self.qDocument.rootFrame().frameFormat() - if docFormat.topMargin() < tH: - docFormat.setTopMargin(tH + 2) + if tT > 0: + docFormat.setTopMargin(tT) + else: + docFormat.setTopMargin(0) + + self.qDocument.blockSignals(True) + self.qDocument.rootFrame().setFrameFormat(docFormat) + self.qDocument.blockSignals(False) return From 69d0a063f137fabf9d936190272db0f8c9e8703a Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Tue, 26 May 2020 18:53:37 +0200 Subject: [PATCH 02/19] Wrong margin used ... --- nw/gui/elements/doceditor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index 082be79c..f0976786 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -337,7 +337,7 @@ class GuiDocEditor(QTextEdit): tB = self.lineWidth() tW = self.width() - 2*tB tH = self.docTitle.height() - tT = tM - tH + tT = self.mainConf.textMargin - tH self.docTitle.setGeometry(tB, tB, tW, tH) self.setViewportMargins(0, tH, 0, 0) From 52cbaa24cc2d1afc78619bbd33af6973b1708d3a Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Tue, 26 May 2020 22:09:01 +0200 Subject: [PATCH 03/19] Added font family and size selector to the build novel project tool --- nw/gui/build.py | 129 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 40 deletions(-) diff --git a/nw/gui/build.py b/nw/gui/build.py index 093d5975..6f43609a 100644 --- a/nw/gui/build.py +++ b/nw/gui/build.py @@ -38,7 +38,8 @@ from PyQt5.QtGui import ( ) from PyQt5.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QTextBrowser, QPushButton, QLabel, - QLineEdit, QGroupBox, QGridLayout, QProgressBar, QMenu, QAction, QFileDialog + QLineEdit, QGroupBox, QGridLayout, QProgressBar, QMenu, QAction, + QFileDialog, QFontComboBox, QSpinBox ) from nw.gui.additions import QSwitch @@ -119,16 +120,16 @@ class GuiBuildNovel(QDialog): self.fmtSection.setFixedWidth(200) self.fmtSection.setText(self.theProject.titleFormat["section"]) - self.titleForm.addWidget(QLabel("Title"), 0, 0) - self.titleForm.addWidget(self.fmtTitle, 0, 1) - self.titleForm.addWidget(QLabel("Chapter"), 1, 0) - self.titleForm.addWidget(self.fmtChapter, 1, 1) - self.titleForm.addWidget(QLabel("Unnumbered"), 2, 0) - self.titleForm.addWidget(self.fmtUnnumbered, 2, 1) - self.titleForm.addWidget(QLabel("Scene"), 3, 0) - self.titleForm.addWidget(self.fmtScene, 3, 1) - self.titleForm.addWidget(QLabel("Section"), 4, 0) - self.titleForm.addWidget(self.fmtSection, 4, 1) + self.titleForm.addWidget(QLabel("Title"), 0, 0, 1, 1, Qt.AlignLeft) + self.titleForm.addWidget(self.fmtTitle, 0, 1, 1, 1, Qt.AlignRight) + self.titleForm.addWidget(QLabel("Chapter"), 1, 0, 1, 1, Qt.AlignLeft) + self.titleForm.addWidget(self.fmtChapter, 1, 1, 1, 1, Qt.AlignRight) + self.titleForm.addWidget(QLabel("Unnumbered"), 2, 0, 1, 1, Qt.AlignLeft) + self.titleForm.addWidget(self.fmtUnnumbered, 2, 1, 1, 1, Qt.AlignRight) + self.titleForm.addWidget(QLabel("Scene"), 3, 0, 1, 1, Qt.AlignLeft) + self.titleForm.addWidget(self.fmtScene, 3, 1, 1, 1, Qt.AlignRight) + self.titleForm.addWidget(QLabel("Section"), 4, 0, 1, 1, Qt.AlignLeft) + self.titleForm.addWidget(self.fmtSection, 4, 1, 1, 1, Qt.AlignRight) self.titleForm.setColumnStretch(0, 1) self.titleForm.setColumnStretch(1, 0) @@ -139,11 +140,32 @@ class GuiBuildNovel(QDialog): self.textForm = QGridLayout(self) self.textGroup.setLayout(self.textForm) - self.justifyText = QSwitch() - self.justifyText.setChecked(self.optState.getBool("GuiBuildNovel", "justifyText", False)) + self.textFont = QFontComboBox() + self.textFont.setFixedWidth(200) + self.textFont.setCurrentFont( + QFont(self.optState.getString("GuiBuildNovel", "textFont", self.mainConf.textFont)) + ) - self.textForm.addWidget(QLabel("Justify text"), 0, 0) - self.textForm.addWidget(self.justifyText, 0, 1) + self.textSize = QSpinBox(self) + self.textSize.setFixedWidth(60) + self.textSize.setMinimum(5) + self.textSize.setMaximum(48) + self.textSize.setSingleStep(1) + self.textSize.setValue( + self.optState.getInt("GuiBuildNovel", "textSize", self.mainConf.textSize) + ) + + self.justifyText = QSwitch() + self.justifyText.setChecked( + self.optState.getBool("GuiBuildNovel", "justifyText", False) + ) + + self.textForm.addWidget(QLabel("Font family"), 0, 0, 1, 1, Qt.AlignLeft) + self.textForm.addWidget(self.textFont, 0, 1, 1, 1, Qt.AlignRight) + self.textForm.addWidget(QLabel("Font size"), 1, 0, 1, 1, Qt.AlignLeft) + self.textForm.addWidget(self.textSize, 1, 1, 1, 1, Qt.AlignRight) + self.textForm.addWidget(QLabel("Justify text"), 2, 0, 1, 1, Qt.AlignLeft) + self.textForm.addWidget(self.justifyText, 2, 1, 1, 1, Qt.AlignRight) self.textForm.setColumnStretch(0, 1) self.textForm.setColumnStretch(1, 0) @@ -156,17 +178,19 @@ class GuiBuildNovel(QDialog): self.includeSynopsis = QSwitch() self.includeSynopsis.setChecked(self.theProject.titleFormat["withSynopsis"]) + self.includeComments = QSwitch() self.includeComments.setChecked(self.theProject.titleFormat["withComments"]) + self.includeKeywords = QSwitch() self.includeKeywords.setChecked(self.theProject.titleFormat["withKeywords"]) - self.includeForm.addWidget(QLabel("Include synopsis"), 0, 0) - self.includeForm.addWidget(self.includeSynopsis, 0, 1) - self.includeForm.addWidget(QLabel("Include comments"), 1, 0) - self.includeForm.addWidget(self.includeComments, 1, 1) - self.includeForm.addWidget(QLabel("Include keywords"), 2, 0) - self.includeForm.addWidget(self.includeKeywords, 2, 1) + self.includeForm.addWidget(QLabel("Include synopsis"), 0, 0, 1, 1, Qt.AlignLeft) + self.includeForm.addWidget(self.includeSynopsis, 0, 1, 1, 1, Qt.AlignRight) + self.includeForm.addWidget(QLabel("Include comments"), 1, 0, 1, 1, Qt.AlignLeft) + self.includeForm.addWidget(self.includeComments, 1, 1, 1, 1, Qt.AlignRight) + self.includeForm.addWidget(QLabel("Include keywords"), 2, 0, 1, 1, Qt.AlignLeft) + self.includeForm.addWidget(self.includeKeywords, 2, 1, 1, 1, Qt.AlignRight) self.includeForm.setColumnStretch(0, 1) self.includeForm.setColumnStretch(1, 0) @@ -178,22 +202,33 @@ class GuiBuildNovel(QDialog): self.addsGroup.setLayout(self.addsForm) self.novelFiles = QSwitch() - self.novelFiles.setChecked(self.optState.getBool("GuiBuildNovel", "addNovel", True)) + self.novelFiles.setChecked( + self.optState.getBool("GuiBuildNovel", "addNovel", True) + ) + self.noteFiles = QSwitch() - self.noteFiles.setChecked(self.optState.getBool("GuiBuildNovel", "addNotes", False)) - self.ignoreFlag = QSwitch() - self.ignoreFlag.setChecked(self.optState.getBool("GuiBuildNovel", "ignoreFlag", False)) - self.excludeBody = QSwitch() - self.excludeBody.setChecked(self.optState.getBool("GuiBuildNovel", "excludeBody", False)) + self.noteFiles.setChecked( + self.optState.getBool("GuiBuildNovel", "addNotes", False) + ) - self.addsForm.addWidget(QLabel("Include novel files"), 0, 0) - self.addsForm.addWidget(self.novelFiles, 0, 1) - self.addsForm.addWidget(QLabel("Include note files"), 1, 0) - self.addsForm.addWidget(self.noteFiles, 1, 1) - self.addsForm.addWidget(QLabel("Ignore export flag"), 2, 0) - self.addsForm.addWidget(self.ignoreFlag, 2, 1) - self.addsForm.addWidget(QLabel("Exclude body text"), 3, 0) - self.addsForm.addWidget(self.excludeBody, 3, 1) + self.ignoreFlag = QSwitch() + self.ignoreFlag.setChecked( + self.optState.getBool("GuiBuildNovel", "ignoreFlag", False) + ) + + self.excludeBody = QSwitch() + self.excludeBody.setChecked( + self.optState.getBool("GuiBuildNovel", "excludeBody", False) + ) + + self.addsForm.addWidget(QLabel("Include novel files"), 0, 0, 1, 1, Qt.AlignLeft) + self.addsForm.addWidget(self.novelFiles, 0, 1, 1, 1, Qt.AlignRight) + self.addsForm.addWidget(QLabel("Include note files"), 1, 0, 1, 1, Qt.AlignLeft) + self.addsForm.addWidget(self.noteFiles, 1, 1, 1, 1, Qt.AlignRight) + self.addsForm.addWidget(QLabel("Ignore export flag"), 2, 0, 1, 1, Qt.AlignLeft) + self.addsForm.addWidget(self.ignoreFlag, 2, 1, 1, 1, Qt.AlignRight) + self.addsForm.addWidget(QLabel("Exclude body text"), 3, 0, 1, 1, Qt.AlignLeft) + self.addsForm.addWidget(self.excludeBody, 3, 1, 1, 1, Qt.AlignRight) self.addsForm.setColumnStretch(0, 1) self.addsForm.setColumnStretch(1, 0) @@ -294,6 +329,8 @@ class GuiBuildNovel(QDialog): fmtScene = self.fmtScene.text().strip() fmtSection = self.fmtSection.text().strip() justifyText = self.justifyText.isChecked() + textFont = self.textFont.currentFont().family() + textSize = self.textSize.value() incSynopsis = self.includeSynopsis.isChecked() incComments = self.includeComments.isChecked() incKeywords = self.includeKeywords.isChecked() @@ -357,6 +394,7 @@ class GuiBuildNovel(QDialog): self.htmlStyle = makeHtml.getStyleSheet() # Load the preview document with the html data + self.docView.setTextFont(textFont, textSize) self.docView.setJustify(justifyText) self.docView.setStyleSheet(self.htmlStyle) self.docView.setContent(self.htmlText) @@ -610,12 +648,14 @@ class GuiBuildNovel(QDialog): }) # GUI Settings - self.optState.setValue("GuiBuildNovel", "winWidth", self.width()) - self.optState.setValue("GuiBuildNovel", "winHeight", self.height()) + self.optState.setValue("GuiBuildNovel", "winWidth", self.width()) + self.optState.setValue("GuiBuildNovel", "winHeight", self.height()) self.optState.setValue("GuiBuildNovel", "justifyText", self.justifyText.isChecked()) - self.optState.setValue("GuiBuildNovel", "addNovel", self.novelFiles.isChecked()) - self.optState.setValue("GuiBuildNovel", "addNotes", self.noteFiles.isChecked()) - self.optState.setValue("GuiBuildNovel", "ignoreFlag", self.ignoreFlag.isChecked()) + self.optState.setValue("GuiBuildNovel", "textFont", self.textFont.currentFont().family()) + self.optState.setValue("GuiBuildNovel", "textSize", self.textSize.value()) + self.optState.setValue("GuiBuildNovel", "addNovel", self.novelFiles.isChecked()) + self.optState.setValue("GuiBuildNovel", "addNotes", self.noteFiles.isChecked()) + self.optState.setValue("GuiBuildNovel", "ignoreFlag", self.ignoreFlag.isChecked()) self.optState.setValue("GuiBuildNovel", "excludeBody", self.excludeBody.isChecked()) self.optState.saveSettings() @@ -688,6 +728,15 @@ class GuiBuildNovelDocView(QTextBrowser): self.qDocument.setDefaultTextOption(theOpt) return + def setTextFont(self, textFont, textSize): + """Set the text font properties. + """ + theFont = QFont() + theFont.setFamily(textFont) + theFont.setPointSize(textSize) + self.setFont(theFont) + return + def setContent(self, theText): """Set the content, either from text or list of text. """ From d9df2a532e4e2f9e143629688a21430a2b611289 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Tue, 26 May 2020 22:15:18 +0200 Subject: [PATCH 04/19] Renamed the build tool button --- nw/gui/build.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nw/gui/build.py b/nw/gui/build.py index 6f43609a..535ab1ae 100644 --- a/nw/gui/build.py +++ b/nw/gui/build.py @@ -237,8 +237,8 @@ class GuiBuildNovel(QDialog): # ============ self.buildProgress = QProgressBar() - self.genPreview = QPushButton("Generate Preview") - self.genPreview.clicked.connect(self._buildPreview) + self.buildNovel = QPushButton("Build Novel Project") + self.buildNovel.clicked.connect(self._buildPreview) # Action Buttons # ============== @@ -295,7 +295,7 @@ class GuiBuildNovel(QDialog): self.toolsBox.addWidget(self.addsGroup) self.toolsBox.addStretch(1) self.toolsBox.addWidget(self.buildProgress) - self.toolsBox.addWidget(self.genPreview) + self.toolsBox.addWidget(self.buildNovel) self.toolsBox.addSpacing(8) self.toolsBox.addLayout(self.buttonForm) From fecfa66d2f00785f2e82fdc17043bac918089203 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Tue, 26 May 2020 22:25:11 +0200 Subject: [PATCH 05/19] Updated changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd08437b..acd117f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # novelWriter ChangeLog +## Not Yet Released + +**User Interface** + +* Renamed the "Generate Preview" button on the "Build Novel Project" tool to "Build Novel Project". You must actually click this to be able to export or print. Issue #237, PR #238. +* Added font family and font size selectors to the "Build Novel Project" tool. You may want a different print font than used in the editor itself. Issue #230, PR #238. +* A margin of the viewport (outside the document) has been added to the document editor and viewer to make room for the document title bar. Previously, the title bar would sit on top of the document top margin, which would sometimes hide text that would otherwise be visible. PR #236. + + ## Version 0.6.1 [2020-05-25] **Bugfixes** From 088b96fd5582a6a57cc61c9979e7e1a8bec49320 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Tue, 26 May 2020 22:47:48 +0200 Subject: [PATCH 06/19] Fixed some alignemnt issue and the icon for NO_LAYOUT in the details panel under the tree view --- nw/gui/build.py | 2 +- nw/gui/elements/docdetails.py | 45 +++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/nw/gui/build.py b/nw/gui/build.py index 535ab1ae..d52056d8 100644 --- a/nw/gui/build.py +++ b/nw/gui/build.py @@ -205,7 +205,7 @@ class GuiBuildNovel(QDialog): self.novelFiles.setChecked( self.optState.getBool("GuiBuildNovel", "addNovel", True) ) - + self.noteFiles = QSwitch() self.noteFiles.setChecked( self.optState.getBool("GuiBuildNovel", "addNotes", False) diff --git a/nw/gui/elements/docdetails.py b/nw/gui/elements/docdetails.py index 6a12f0b3..e72f6486 100644 --- a/nw/gui/elements/docdetails.py +++ b/nw/gui/elements/docdetails.py @@ -32,7 +32,9 @@ from PyQt5.QtCore import Qt from PyQt5.QtGui import QFont from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel -from nw.constants import nwLabels, nwItemClass, nwItemType, nwUnicode +from nw.constants import ( + nwLabels, nwItemClass, nwItemType, nwItemLayout, nwUnicode +) logger = logging.getLogger(__name__) @@ -143,27 +145,27 @@ class GuiDocDetails(QFrame): self.pCountData.setAlignment(Qt.AlignRight) # Assemble - self.mainBox.addWidget(self.labelName, 0, 0, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.labelFlag, 0, 1, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.labelData, 0, 2, 1, 3, Qt.AlignTop) + self.mainBox.addWidget(self.labelName, 0, 0, 1, 1) + self.mainBox.addWidget(self.labelFlag, 0, 1, 1, 1) + self.mainBox.addWidget(self.labelData, 0, 2, 1, 3) - self.mainBox.addWidget(self.statusName, 1, 0, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.statusFlag, 1, 1, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.statusData, 1, 2, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.cCountName, 1, 3, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.cCountData, 1, 4, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.statusName, 1, 0, 1, 1) + self.mainBox.addWidget(self.statusFlag, 1, 1, 1, 1) + self.mainBox.addWidget(self.statusData, 1, 2, 1, 1) + self.mainBox.addWidget(self.cCountName, 1, 3, 1, 1) + self.mainBox.addWidget(self.cCountData, 1, 4, 1, 1) - self.mainBox.addWidget(self.className, 2, 0, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.classFlag, 2, 1, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.classData, 2, 2, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.wCountName, 2, 3, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.wCountData, 2, 4, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.className, 2, 0, 1, 1) + self.mainBox.addWidget(self.classFlag, 2, 1, 1, 1) + self.mainBox.addWidget(self.classData, 2, 2, 1, 1) + self.mainBox.addWidget(self.wCountName, 2, 3, 1, 1) + self.mainBox.addWidget(self.wCountData, 2, 4, 1, 1) - self.mainBox.addWidget(self.layoutName, 3, 0, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.layoutFlag, 3, 1, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.layoutData, 3, 2, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.pCountName, 3, 3, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.pCountData, 3, 4, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.layoutName, 3, 0, 1, 1) + self.mainBox.addWidget(self.layoutFlag, 3, 1, 1, 1) + self.mainBox.addWidget(self.layoutData, 3, 2, 1, 1) + self.mainBox.addWidget(self.pCountName, 3, 3, 1, 1) + self.mainBox.addWidget(self.pCountData, 3, 4, 1, 1) self.mainBox.setColumnStretch(0,0) self.mainBox.setColumnStretch(1,0) @@ -221,7 +223,10 @@ class GuiDocDetails(QFrame): self.labelFlag.setText(exportFlag) self.statusFlag.setPixmap(flagIcon.pixmap(10, 10)) self.classFlag.setText(nwLabels.CLASS_FLAG[nwItem.itemClass]) - self.layoutFlag.setText(nwLabels.LAYOUT_FLAG[nwItem.itemLayout]) + if nwItem.itemLayout == nwItemLayout.NO_LAYOUT: + self.layoutFlag.setText("-") + else: + self.layoutFlag.setText(nwLabels.LAYOUT_FLAG[nwItem.itemLayout]) self.labelData.setText(theLabel) self.statusData.setText(nwItem.itemStatus) From fed2a0508e57288b43ccf71556d46d5831bacf33 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Tue, 26 May 2020 22:51:23 +0200 Subject: [PATCH 07/19] Updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index acd117f2..6ad56c51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * Renamed the "Generate Preview" button on the "Build Novel Project" tool to "Build Novel Project". You must actually click this to be able to export or print. Issue #237, PR #238. * Added font family and font size selectors to the "Build Novel Project" tool. You may want a different print font than used in the editor itself. Issue #230, PR #238. * A margin of the viewport (outside the document) has been added to the document editor and viewer to make room for the document title bar. Previously, the title bar would sit on top of the document top margin, which would sometimes hide text that would otherwise be visible. PR #236. +* Fixed some alignment issue for the status icon on the project tree details panel. Mentioned in #235, PR #239. +* Removed the `Xo` icon for NO_LAYOUT in the project tree details panel. Mentioned in #235, PR #239. ## Version 0.6.1 [2020-05-25] From f1e717e6a10801442d1cd2926ed4a35acbb0a7d5 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 01:04:10 +0200 Subject: [PATCH 08/19] Check that the backup folder is not inside the project path to be backed up --- nw/core/project.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/nw/core/project.py b/nw/core/project.py index 4516d1aa..63c79659 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -526,25 +526,25 @@ class NWProject(): self.theParent.makeAlert(( "Cannot backup project because no backup path is set. " "Please set a valid backup location in Tools > Preferences." - ), nwAlert.WARN) + ), nwAlert.ERROR) return False if self.projName is None or self.projName == "": self.theParent.makeAlert(( "Cannot backup project because no project name is set. " "Please set a Working Title in Project > Project Settings." - ), nwAlert.WARN) + ), nwAlert.ERROR) return False if not path.isdir(self.mainConf.backupPath): self.theParent.makeAlert(( "Cannot backup project because the backup path does not exist. " "Please set a valid backup location in Tools > Preferences." - ), nwAlert.WARN) + ), nwAlert.ERROR) return False cleanName = self.getFileSafeProjectName() - baseDir = path.join(self.mainConf.backupPath, cleanName) + baseDir = path.abspath(path.join(self.mainConf.backupPath, cleanName)) if not path.isdir(baseDir): try: mkdir(baseDir) @@ -556,16 +556,25 @@ class NWProject(): ) return False + backPath = path.abspath(self.projPath) + if path.commonpath([backPath, baseDir]) == backPath: + self.theParent.makeAlert(( + "Cannot backup project because the backup path is within the " + "project folder to be backed up. Please choose a different " + "backup path in Tools > Preferences." + ), nwAlert.ERROR) + return False + archName = "Backup from %s" % formatTimeStamp(time(), fileSafe=True) baseName = path.join(baseDir, archName) try: self._clearLockFile() - make_archive(baseName, "zip", self.projPath, ".") + make_archive(baseName, "zip", backPath, ".") self._writeLockFile() if doNotify: self.theParent.makeAlert( - "Backup archive file written to: '%s.zip'" % path.join(cleanName, archName), + "Backup archive file written to: %s.zip" % path.join(cleanName, archName), nwAlert.INFO ) else: From e4f2e088bb3ed5e964510e19dc2119e44a54d6bd Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 01:18:37 +0200 Subject: [PATCH 09/19] Need more calls to update document margins due to the document title bar. --- nw/gui/elements/doceditor.py | 3 ++- nw/gui/elements/docviewer.py | 41 ++++++++++++++++++++++-------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index f0976786..45058360 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -228,7 +228,6 @@ class GuiDocEditor(QTextEdit): tHandle = self.theHandle self.clearEditor() self.loadText(tHandle, showStatus=False) - self.updateDocMargins() return def loadText(self, tHandle, tLine=None, showStatus=True): @@ -289,6 +288,7 @@ class GuiDocEditor(QTextEdit): """ self.setPlainText(theText) self.setDocumentChanged(True) + self.updateDocMargins() return def saveText(self): @@ -370,6 +370,7 @@ class GuiDocEditor(QTextEdit): """ if tHandle == self.theHandle: self.docTitle.setTitleFromHandle(self.theHandle) + self.updateDocMargins() return ## diff --git a/nw/gui/elements/docviewer.py b/nw/gui/elements/docviewer.py index 3ad0df6f..3eefed49 100644 --- a/nw/gui/elements/docviewer.py +++ b/nw/gui/elements/docviewer.py @@ -145,6 +145,7 @@ class GuiDocViewer(QTextBrowser): self.theHandle = tHandle self.theProject.setLastViewed(tHandle) self.docTitle.setTitleFromHandle(self.theHandle) + self.updateDocMargins() # Make sure the main GUI knows we changed the content self.theParent.viewMeta.refreshReferences(tHandle) @@ -199,23 +200,11 @@ class GuiDocViewer(QTextBrowser): return False return True - def updateDocTitle(self, tHandle): - """Called when an item label is changed to check if the document - title bar needs updating, + def updateDocMargins(self): + """Automatically adjust the margins so the text is centred if + Config.textFixedW is enabled or we're in Zen mode. Otherwise, + just ensure the margins are set correctly. """ - if tHandle == self.theHandle: - self.docTitle.setTitleFromHandle(self.theHandle) - return - - ## - # Events - ## - - def resizeEvent(self, theEvent): - """Make sure the document title is the same width as the window. - """ - QTextBrowser.resizeEvent(self, theEvent) - tB = self.lineWidth() tW = self.width() - 2*tB tH = self.docTitle.height() @@ -235,6 +224,26 @@ class GuiDocViewer(QTextBrowser): return + def updateDocTitle(self, tHandle): + """Called when an item label is changed to check if the document + title bar needs updating, + """ + if tHandle == self.theHandle: + self.docTitle.setTitleFromHandle(self.theHandle) + self.updateDocMargins() + return + + ## + # Events + ## + + def resizeEvent(self, theEvent): + """Make sure the document title is the same width as the window. + """ + QTextBrowser.resizeEvent(self, theEvent) + self.updateDocMargins() + return + ## # Internal Functions ## From 7c78eff5eac817be95352fbbfbf36e0df4d57735 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 16:35:09 +0200 Subject: [PATCH 10/19] Some more path checks. Should be fine now. --- nw/config.py | 6 +++--- nw/core/project.py | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/nw/config.py b/nw/config.py index fbb384ab..bc40259b 100644 --- a/nw/config.py +++ b/nw/config.py @@ -424,7 +424,7 @@ class Config: ## Backup cnfSec = "Backup" self.backupPath = self._parseLine( - cnfParse, cnfSec, "backuppath", self.CNF_STR, self.backupPath + cnfParse, cnfSec, "backuppath", self.CNF_STR, self.backupPath ) self.backupOnClose = self._parseLine( cnfParse, cnfSec, "backuponclose", self.CNF_BOOL, self.backupOnClose @@ -639,7 +639,7 @@ class Config: if newPath is None: return True if not path.isfile(newPath): - logger.error("Config: File not found. Using default config path instead.") + logger.error("File not found, using default config path instead") return False self.confPath = path.dirname(newPath) self.confFile = path.basename(newPath) @@ -649,7 +649,7 @@ class Config: if newPath is None: return True if not path.isdir(newPath): - logger.error("Config: Path not found. Using default data path instead.") + logger.error("Path not found, using default data path instead") return False self.dataPath = path.abspath(newPath) return True diff --git a/nw/core/project.py b/nw/core/project.py index 63c79659..1b63cc0f 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -556,8 +556,7 @@ class NWProject(): ) return False - backPath = path.abspath(self.projPath) - if path.commonpath([backPath, baseDir]) == backPath: + if path.commonpath([self.projPath, baseDir]) == self.projPath: self.theParent.makeAlert(( "Cannot backup project because the backup path is within the " "project folder to be backed up. Please choose a different " @@ -570,7 +569,7 @@ class NWProject(): try: self._clearLockFile() - make_archive(baseName, "zip", backPath, ".") + make_archive(baseName, "zip", self.projPath, ".") self._writeLockFile() if doNotify: self.theParent.makeAlert( @@ -603,7 +602,7 @@ class NWProject(): else: if projPath.startswith("~"): projPath = path.expanduser(projPath) - self.projPath = projPath + self.projPath = path.abspath(projPath) self.setProjectChanged(True) return True From f7232aac13f8dee38b2275913b71079e938f12a2 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 16:44:40 +0200 Subject: [PATCH 11/19] Updated changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ad56c51..90c0644f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Not Yet Released +**Bugfixes** + +* It was possible to have the backup folder set to the same folder as the project, resulting in an infinite loop when `make_archive` was building the zip file. This crash of paths is now checked before moving to the archive step. Issue #240, PR #241. + **User Interface** * Renamed the "Generate Preview" button on the "Build Novel Project" tool to "Build Novel Project". You must actually click this to be able to export or print. Issue #237, PR #238. From d61abdd95500dbc799b3455d0eb425739133b01b Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 16:47:17 +0200 Subject: [PATCH 12/19] Renamed GuiProjectEditor to GuiProjectSettings --- nw/gui/__init__.py | 4 ++-- nw/gui/dialogs/__init__.py | 4 ++-- nw/gui/dialogs/projecteditor.py | 12 ++++++------ nw/guimain.py | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/nw/gui/__init__.py b/nw/gui/__init__.py index 43cfc5dd..c753cf94 100644 --- a/nw/gui/__init__.py +++ b/nw/gui/__init__.py @@ -13,7 +13,7 @@ from nw.gui.dialogs.configeditor import GuiConfigEditor from nw.gui.dialogs.docmerge import GuiDocMerge from nw.gui.dialogs.docsplit import GuiDocSplit from nw.gui.dialogs.itemeditor import GuiItemEditor -from nw.gui.dialogs.projecteditor import GuiProjectEditor +from nw.gui.dialogs.projecteditor import GuiProjectSettings from nw.gui.dialogs.projectload import GuiProjectLoad from nw.gui.dialogs.sessionlog import GuiSessionLogView @@ -44,7 +44,7 @@ __all__ = [ "GuiDocMerge", "GuiDocSplit", "GuiItemEditor", - "GuiProjectEditor", + "GuiProjectSettings", "GuiProjectLoad", "GuiSessionLogView", "GuiDocDetails", diff --git a/nw/gui/dialogs/__init__.py b/nw/gui/dialogs/__init__.py index c2625ee5..8150fe66 100644 --- a/nw/gui/dialogs/__init__.py +++ b/nw/gui/dialogs/__init__.py @@ -5,7 +5,7 @@ from nw.gui.dialogs.configeditor import GuiConfigEditor from nw.gui.dialogs.docmerge import GuiDocMerge from nw.gui.dialogs.docsplit import GuiDocSplit from nw.gui.dialogs.itemeditor import GuiItemEditor -from nw.gui.dialogs.projecteditor import GuiProjectEditor +from nw.gui.dialogs.projecteditor import GuiProjectSettings from nw.gui.dialogs.projectload import GuiProjectLoad from nw.gui.dialogs.sessionlog import GuiSessionLogView @@ -15,7 +15,7 @@ __all__ = [ "GuiDocMerge", "GuiDocSplit", "GuiItemEditor", - "GuiProjectEditor", + "GuiProjectSettings", "GuiProjectLoad", "GuiSessionLogView", ] diff --git a/nw/gui/dialogs/projecteditor.py b/nw/gui/dialogs/projecteditor.py index 1c494ac0..497471d8 100644 --- a/nw/gui/dialogs/projecteditor.py +++ b/nw/gui/dialogs/projecteditor.py @@ -42,12 +42,12 @@ from nw.gui.additions import QSwitch, PagedDialog logger = logging.getLogger(__name__) -class GuiProjectEditor(PagedDialog): +class GuiProjectSettings(PagedDialog): def __init__(self, theParent, theProject): PagedDialog.__init__(self, theParent) - logger.debug("Initialising ProjectEditor ...") + logger.debug("Initialising GuiProjectSettings ...") self.mainConf = nw.CONFIG self.theParent = theParent @@ -73,12 +73,12 @@ class GuiProjectEditor(PagedDialog): self.show() - logger.debug("ProjectEditor initialisation complete") + logger.debug("GuiProjectSettings initialisation complete") return def _doSave(self): - logger.verbose("ProjectEditor save button clicked") + logger.verbose("GuiProjectSettings save button clicked") projName = self.tabMain.editName.text() bookTitle = self.tabMain.editTitle.text() @@ -106,11 +106,11 @@ class GuiProjectEditor(PagedDialog): return def _doClose(self): - logger.verbose("ProjectEditor close button clicked") + logger.verbose("GuiProjectSettings close button clicked") self.close() return -# END Class GuiProjectEditor +# END Class GuiProjectSettings class GuiProjectEditMain(QWidget): diff --git a/nw/guimain.py b/nw/guimain.py index 9c4d5d3a..234de395 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -42,7 +42,7 @@ from PyQt5.QtWidgets import ( from nw.gui import ( GuiMainMenu, GuiMainStatus, GuiTheme, GuiDocTree, GuiDocEditor, GuiDocViewer, GuiDocDetails, GuiSearchBar, GuiNoticeBar, GuiDocViewDetails, - GuiConfigEditor, GuiProjectEditor, GuiItemEditor, GuiProjectOutline, + GuiConfigEditor, GuiProjectSettings, GuiItemEditor, GuiProjectOutline, GuiSessionLogView, GuiDocMerge, GuiDocSplit, GuiProjectLoad, GuiBuildNovel ) from nw.core import NWProject, NWDoc, NWIndex @@ -749,7 +749,7 @@ class GuiMain(QMainWindow): """Open the project settings dialog. """ if self.hasProject: - dlgProj = GuiProjectEditor(self, self.theProject) + dlgProj = GuiProjectSettings(self, self.theProject) dlgProj.exec_() self._setWindowTitle(self.theProject.projName) return True From fd1940301cd4904b837326e79aa6517a4e182397 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 16:48:16 +0200 Subject: [PATCH 13/19] Also renamed the file --- nw/gui/dialogs/{projecteditor.py => projectsettings.py} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename nw/gui/dialogs/{projecteditor.py => projectsettings.py} (99%) diff --git a/nw/gui/dialogs/projecteditor.py b/nw/gui/dialogs/projectsettings.py similarity index 99% rename from nw/gui/dialogs/projecteditor.py rename to nw/gui/dialogs/projectsettings.py index 497471d8..e5d0e7d5 100644 --- a/nw/gui/dialogs/projecteditor.py +++ b/nw/gui/dialogs/projectsettings.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -"""novelWriter GUI Project Editor +"""novelWriter GUI Project Settings - novelWriter – GUI Project Editor -=================================== - Class holding the project editor + novelWriter – GUI Project Settings +==================================== + Class holding the project settings dialog File History: Created: 2018-09-29 [0.0.1] From 8a98123735fce61ab6ce65b2516315cd7d3fa4ac Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 17:23:02 +0200 Subject: [PATCH 14/19] Some fixes in the QConfigLayout class --- nw/gui/additions/qconfiglayout.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nw/gui/additions/qconfiglayout.py b/nw/gui/additions/qconfiglayout.py index f4eb1ca7..ef753592 100644 --- a/nw/gui/additions/qconfiglayout.py +++ b/nw/gui/additions/qconfiglayout.py @@ -141,19 +141,19 @@ class QConfigLayout(QGridLayout): labelBox.setSpacing(0) thisEntry["help"] = qHelp - self.addLayout(labelBox, self._nextRow, 0, Qt.AlignLeft) + self.addLayout(labelBox, self._nextRow, 0, 1, 1, Qt.AlignLeft | Qt.AlignTop) else: - self.addWidget(qLabel, self._nextRow, 0, Qt.AlignLeft) + self.addWidget(qLabel, self._nextRow, 0, 1, 1, Qt.AlignLeft | Qt.AlignTop) if theUnit is not None: controlBox = QHBoxLayout() controlBox.addWidget(qWidget, 0, Qt.AlignVCenter) controlBox.addWidget(QLabel(theUnit), 0, Qt.AlignVCenter) controlBox.setSpacing(8) - self.addLayout(controlBox, self._nextRow, 1, Qt.AlignRight) + self.addLayout(controlBox, self._nextRow, 1, 1, 1, Qt.AlignRight | Qt.AlignVCenter) else: - self.addWidget(qWidget, self._nextRow, 1, Qt.AlignRight) + self.addWidget(qWidget, self._nextRow, 1, 1, 1, Qt.AlignRight | Qt.AlignVCenter) qLabel.setBuddy(qWidget) From 12aa25cc54a60ed23a8f07b570a89a83f538627d Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 18:09:55 +0200 Subject: [PATCH 15/19] Added details tab to the Project Settings dialog --- nw/core/project.py | 29 +++++- nw/gui/__init__.py | 2 +- nw/gui/additions/qconfiglayout.py | 2 +- nw/gui/dialogs/__init__.py | 2 +- nw/gui/dialogs/projectsettings.py | 158 +++++++++++++++++++++++++----- tests/test_gui.py | 6 +- 6 files changed, 165 insertions(+), 34 deletions(-) diff --git a/nw/core/project.py b/nw/core/project.py index 1b63cc0f..0c303f74 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -68,8 +68,8 @@ class NWProject(): self.projChanged = False # The project has unsaved changes self.projAltered = False # The project has been altered this session self.lockedBy = None # Data on which computer has the project open - self.saveCount = None # Meta data: number of saves - self.autoCount = None # Meta data: number of automatic saves + self.saveCount = 0 # Meta data: number of saves + self.autoCount = 0 # Meta data: number of automatic saves # Class Settings self.projPath = None # The full path to where the currently open project is saved @@ -167,6 +167,7 @@ class NWProject(): """Create a new project by populating the project tree with a few starter items. """ + self.projName = "New Project" hNovel = self.newRoot("Novel", nwItemClass.NOVEL) hChars = self.newRoot("Characters", nwItemClass.CHARACTER) hWorld = self.newRoot("Plot", nwItemClass.PLOT) @@ -1233,6 +1234,30 @@ class NWTree(): self._handleSeed = theSeed return + ## + # Getters + ## + + def countTypes(self): + """Count the number of files, folders and roots in the project. + """ + nRoot = 0 + nFolder = 0 + nFile = 0 + + for tHandle in self._treeOrder: + tItem = self.__getitem__(tHandle) + if tItem is None: + continue + elif tItem.itemType == nwItemType.ROOT: + nRoot += 1 + elif tItem.itemType == nwItemType.FOLDER: + nFolder += 1 + elif tItem.itemType == nwItemType.FILE: + nFile += 1 + + return nRoot, nFolder, nFile + ## # Meta Methods ## diff --git a/nw/gui/__init__.py b/nw/gui/__init__.py index c753cf94..393f501d 100644 --- a/nw/gui/__init__.py +++ b/nw/gui/__init__.py @@ -13,7 +13,7 @@ from nw.gui.dialogs.configeditor import GuiConfigEditor from nw.gui.dialogs.docmerge import GuiDocMerge from nw.gui.dialogs.docsplit import GuiDocSplit from nw.gui.dialogs.itemeditor import GuiItemEditor -from nw.gui.dialogs.projecteditor import GuiProjectSettings +from nw.gui.dialogs.projectsettings import GuiProjectSettings from nw.gui.dialogs.projectload import GuiProjectLoad from nw.gui.dialogs.sessionlog import GuiSessionLogView diff --git a/nw/gui/additions/qconfiglayout.py b/nw/gui/additions/qconfiglayout.py index ef753592..be7571b5 100644 --- a/nw/gui/additions/qconfiglayout.py +++ b/nw/gui/additions/qconfiglayout.py @@ -97,7 +97,7 @@ class QConfigLayout(QGridLayout): qLabel = None raise ValueError("theLabel must be a QLabel") - qLabel.setContentsMargins(0,4,0,4) + qLabel.setContentsMargins(0, 4, 0, 4) self.addWidget(qLabel, self._nextRow, 0, 1, 2, Qt.AlignLeft) self.setRowStretch(self._nextRow, 0) diff --git a/nw/gui/dialogs/__init__.py b/nw/gui/dialogs/__init__.py index 8150fe66..271a7a1d 100644 --- a/nw/gui/dialogs/__init__.py +++ b/nw/gui/dialogs/__init__.py @@ -5,7 +5,7 @@ from nw.gui.dialogs.configeditor import GuiConfigEditor from nw.gui.dialogs.docmerge import GuiDocMerge from nw.gui.dialogs.docsplit import GuiDocSplit from nw.gui.dialogs.itemeditor import GuiItemEditor -from nw.gui.dialogs.projecteditor import GuiProjectSettings +from nw.gui.dialogs.projectsettings import GuiProjectSettings from nw.gui.dialogs.projectload import GuiProjectLoad from nw.gui.dialogs.sessionlog import GuiSessionLogView diff --git a/nw/gui/dialogs/projectsettings.py b/nw/gui/dialogs/projectsettings.py index e5d0e7d5..8d501585 100644 --- a/nw/gui/dialogs/projectsettings.py +++ b/nw/gui/dialogs/projectsettings.py @@ -38,7 +38,7 @@ from PyQt5.QtWidgets import ( ) from nw.constants import nwAlert -from nw.gui.additions import QSwitch, PagedDialog +from nw.gui.additions import QSwitch, PagedDialog, QConfigLayout logger = logging.getLogger(__name__) @@ -57,11 +57,13 @@ class GuiProjectSettings(PagedDialog): self.setWindowTitle("Project Settings") self.tabMain = GuiProjectEditMain(self.theParent, self.theProject) - self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusItems) - self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importItems) + self.tabMeta = GuiProjectEditMeta(self.theParent, self.theProject) + self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject, True) + self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject, False) self.tabReplace = GuiProjectEditReplace(self.theParent, self.theProject) self.addTab(self.tabMain, "Settings") + self.addTab(self.tabMeta, "Details") self.addTab(self.tabStatus, "Status") self.addTab(self.tabImport, "Importance") self.addTab(self.tabReplace,"Auto-Replace") @@ -117,58 +119,155 @@ class GuiProjectEditMain(QWidget): def __init__(self, theParent, theProject): QWidget.__init__(self, theParent) - self.theParent = theParent - self.theProject = theProject - self.mainForm = QGridLayout() - self.backupBox = QHBoxLayout() + self.theParent = theParent + self.theProject = theProject - self.editName = QLineEdit() + # The Form + self.mainForm = QConfigLayout() + self.mainForm.setHelpTextStyle(self.theParent.theTheme.helpText) + self.setLayout(self.mainForm) + + self.mainForm.addGroupLabel("Project Settings") + + self.editName = QLineEdit() self.editName.setMaxLength(200) + self.editName.setFixedWidth(250) self.editName.setText(self.theProject.projName) + self.mainForm.addRow( + "Working title", + self.editName, + "Should be set only once." + ) self.editTitle = QLineEdit() self.editTitle.setMaxLength(200) + self.editTitle.setFixedWidth(250) self.editTitle.setText(self.theProject.bookTitle) + self.mainForm.addRow( + "Novel title", + self.editTitle, + "Change whenever you want!" + ) self.editAuthors = QPlainTextEdit() bookAuthors = "" for bookAuthor in self.theProject.bookAuthors: bookAuthors += bookAuthor+"\n" self.editAuthors.setPlainText(bookAuthors) - self.editAuthors.setMaximumHeight(120) + self.editAuthors.setFixedHeight(100) + self.editAuthors.setFixedWidth(250) + self.mainForm.addRow( + "Author(s)", + self.editAuthors, + "One name per line." + ) self.doBackup = QSwitch(self) self.doBackup.setChecked(not self.theProject.doBackup) - self.backupBox.addStretch(1) - self.backupBox.addWidget(QLabel("Disable backup on close")) - self.backupBox.addWidget(self.doBackup) - - self.mainForm.addWidget(QLabel("Working title"), 0, 0, 1, 1, Qt.AlignTop) - self.mainForm.addWidget(self.editName, 0, 1, 1, 1, Qt.AlignTop) - self.mainForm.addWidget(QLabel("Book title"), 1, 0, 1, 1, Qt.AlignTop) - self.mainForm.addWidget(self.editTitle, 1, 1, 1, 1, Qt.AlignTop) - self.mainForm.addWidget(QLabel("Book authors"), 2, 0, 1, 1, Qt.AlignTop) - self.mainForm.addWidget(self.editAuthors, 2, 1, 1, 1, Qt.AlignTop) - self.mainForm.addLayout(self.backupBox, 3, 0, 1, 2, Qt.AlignTop) - - self.setLayout(self.mainForm) + self.mainForm.addRow( + "No backup on close", + self.doBackup, + "Overrides main preferences." + ) return # END Class GuiProjectEditMain -class GuiProjectEditStatus(QWidget): +class GuiProjectEditMeta(QWidget): - def __init__(self, theParent, theStatus): + def __init__(self, theParent, theProject): QWidget.__init__(self, theParent) self.theParent = theParent - self.theStatus = theStatus + self.theProject = theProject + + # The Form + self.mainForm = QGridLayout() + self.setLayout(self.mainForm) + + self.headLabel = QLabel("Project Details") + + self.nameLabel = QLabel("Working title:") + self.nameLabel.setIndent(8) + self.nameValue = QLabel(self.theProject.projName) + self.nameValue.setWordWrap(True) + + self.pathLabel = QLabel("Project path:") + self.pathLabel.setIndent(8) + self.pathValue = QLabel(self.theProject.projPath) + self.pathValue.setWordWrap(True) + + self.revLabel = QLabel("Revision count:") + self.revLabel.setIndent(8) + self.revValue = QLabel("{:n}".format(self.theProject.saveCount)) + + self.statsLabel = QLabel("Project Stats") + + nR, nD, nF = self.theProject.projTree.countTypes() + + self.nRootLabel = QLabel("Root folders:") + self.nRootLabel.setIndent(8) + self.nRootValue = QLabel("{:n}".format(nR)) + + self.nDirLabel = QLabel("Folders:") + self.nDirLabel.setIndent(8) + self.nDirValue = QLabel("{:n}".format(nD)) + + self.nFileLabel = QLabel("Documents:") + self.nFileLabel.setIndent(8) + self.nFileValue = QLabel("{:n}".format(nF)) + + self.wordsLabel = QLabel("Word count:") + self.wordsLabel.setIndent(8) + self.wordsValue = QLabel("{:n}".format(self.theProject.currWCount)) + + self.mainForm.addWidget(self.headLabel, 0, 0, 1, 2, Qt.AlignTop) + self.mainForm.addWidget(self.nameLabel, 1, 0, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.nameValue, 1, 1, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.pathLabel, 2, 0, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.pathValue, 2, 1, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.revLabel, 3, 0, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.revValue, 3, 1, 1, 1, Qt.AlignTop) + + self.mainForm.addWidget(self.statsLabel, 4, 0, 1, 2, Qt.AlignTop) + self.mainForm.addWidget(self.nRootLabel, 5, 0, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.nRootValue, 5, 1, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.nDirLabel, 6, 0, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.nDirValue, 6, 1, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.nFileLabel, 7, 0, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.nFileValue, 7, 1, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.wordsLabel, 8, 0, 1, 1, Qt.AlignTop) + self.mainForm.addWidget(self.wordsValue, 8, 1, 1, 1, Qt.AlignTop) + + self.mainForm.setVerticalSpacing(6) + self.mainForm.setHorizontalSpacing(12) + self.mainForm.setColumnStretch(0, 0) + self.mainForm.setColumnStretch(1, 1) + self.mainForm.setRowStretch(10, 1) + + return + +# END Class GuiProjectEditMeta + +class GuiProjectEditStatus(QWidget): + + def __init__(self, theParent, theProject, isStatus): + QWidget.__init__(self, theParent) + + self.theParent = theParent + self.theProject = theProject + if isStatus: + self.theStatus = self.theProject.statusItems + else: + self.theStatus = self.theProject.importItems + self.colData = [] self.colCounts = [] self.colChanged = False self.selColour = None + self.outerBox = QVBoxLayout() self.mainBox = QHBoxLayout() self.mainForm = QVBoxLayout() @@ -208,7 +307,13 @@ class GuiProjectEditStatus(QWidget): self.mainBox.addWidget(self.listBox) self.mainBox.addLayout(self.mainForm) - self.setLayout(self.mainBox) + if isStatus: + self.outerBox.addWidget(QLabel("Novel File Status Levels")) + else: + self.outerBox.addWidget(QLabel("Note File Importance Levels")) + self.outerBox.addLayout(self.mainBox) + + self.setLayout(self.outerBox) return @@ -374,6 +479,7 @@ class GuiProjectEditReplace(QWidget): self.bottomBox.addWidget(self.addButton) self.bottomBox.addWidget(self.delButton) + self.outerBox.addWidget(QLabel("Text Replace List for Preview and Export")) self.outerBox.addWidget(self.listBox) self.outerBox.addLayout(self.bottomBox) self.setLayout(self.outerBox) diff --git a/tests/test_gui.py b/tests/test_gui.py index 0d73f3c3..424eb13b 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -8,7 +8,7 @@ from nwtools import * from os import path, unlink from PyQt5.QtCore import Qt -from nw.gui.dialogs.projecteditor import GuiProjectEditor +from nw.gui.dialogs.projecteditor import GuiProjectSettings from nw.gui.dialogs.itemeditor import GuiItemEditor from nw.constants import * @@ -262,7 +262,7 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef, nwTemp): assert nwGUI.newProject(nwTempGUI, True) nwGUI.mainConf.backupPath = nwTempGUI - projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject) + projEdit = GuiProjectSettings(nwGUI, nwGUI.theProject) qtbot.addWidget(projEdit) for c in "Project Name": @@ -314,7 +314,7 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef, nwTemp): projEdit._doSave() # Open again, and check project settings - projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject) + projEdit = GuiProjectSettings(nwGUI, nwGUI.theProject) qtbot.addWidget(projEdit) assert projEdit.tabMain.editName.text() == "Project Name" assert projEdit.tabMain.editTitle.text() == "Project Title" From 3688e1c6db95100db13314fbe7501d7601434fe0 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 18:11:02 +0200 Subject: [PATCH 16/19] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90c0644f..57cda0b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * A margin of the viewport (outside the document) has been added to the document editor and viewer to make room for the document title bar. Previously, the title bar would sit on top of the document top margin, which would sometimes hide text that would otherwise be visible. PR #236. * Fixed some alignment issue for the status icon on the project tree details panel. Mentioned in #235, PR #239. * Removed the `Xo` icon for NO_LAYOUT in the project tree details panel. Mentioned in #235, PR #239. +* Added a Details tab to the Project Settings dialog, which also lists the project path. Issue #242, PR #239. ## Version 0.6.1 [2020-05-25] From 480a03b0c44e3e4403121b6339d31f00b8a6f8fe Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 18:13:50 +0200 Subject: [PATCH 17/19] QActin must have a parent set for Qt < 5.7 --- nw/gui/build.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nw/gui/build.py b/nw/gui/build.py index 535ab1ae..4571a8e1 100644 --- a/nw/gui/build.py +++ b/nw/gui/build.py @@ -254,28 +254,28 @@ class GuiBuildNovel(QDialog): self.saveMenu = QMenu(self) self.btnSave.setMenu(self.saveMenu) - self.saveODT = QAction("Open Document (.odt)") + self.saveODT = QAction("Open Document (.odt)", self) self.saveODT.triggered.connect(lambda: self._saveDocument(self.FMT_ODT)) self.saveMenu.addAction(self.saveODT) - self.savePDF = QAction("Portable Document Format (.pdf)") + self.savePDF = QAction("Portable Document Format (.pdf)", self) self.savePDF.triggered.connect(lambda: self._saveDocument(self.FMT_PDF)) self.saveMenu.addAction(self.savePDF) - self.saveHTM = QAction("%s HTML (.htm)" % nw.__package__) + self.saveHTM = QAction("%s HTML (.htm)" % nw.__package__, self) self.saveHTM.triggered.connect(lambda: self._saveDocument(self.FMT_HTM)) self.saveMenu.addAction(self.saveHTM) if self.mainConf.verQtValue >= 51400: - self.saveMD = QAction("Markdown (.md)") + self.saveMD = QAction("Markdown (.md)", self) self.saveMD.triggered.connect(lambda: self._saveDocument(self.FMT_MD)) self.saveMenu.addAction(self.saveMD) - self.saveNWD = QAction("novelWriter Markdown (.nwd)") + self.saveNWD = QAction("novelWriter Markdown (.nwd)", self) self.saveNWD.triggered.connect(lambda: self._saveDocument(self.FMT_NWD)) self.saveMenu.addAction(self.saveNWD) - self.saveTXT = QAction("Plain Text (.txt)") + self.saveTXT = QAction("Plain Text (.txt)", self) self.saveTXT.triggered.connect(lambda: self._saveDocument(self.FMT_TXT)) self.saveMenu.addAction(self.saveTXT) From fd886597bf66d27e8103014a37d89e858dddbf2a Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 18:21:46 +0200 Subject: [PATCH 18/19] Updated changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acd117f2..8d096f86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,16 @@ ## Not Yet Released +**Bugfixes** + +* Fixed an issue with the Build Novel Project tool on Ubuntu 16.04 LTS where the dialog wouldn't open. PR #246. + **User Interface** * Renamed the "Generate Preview" button on the "Build Novel Project" tool to "Build Novel Project". You must actually click this to be able to export or print. Issue #237, PR #238. * Added font family and font size selectors to the "Build Novel Project" tool. You may want a different print font than used in the editor itself. Issue #230, PR #238. * A margin of the viewport (outside the document) has been added to the document editor and viewer to make room for the document title bar. Previously, the title bar would sit on top of the document top margin, which would sometimes hide text that would otherwise be visible. PR #236. - ## Version 0.6.1 [2020-05-25] **Bugfixes** From 3f84782edb7af14330c88fa6c791a5cae3a4985f Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 May 2020 18:31:23 +0200 Subject: [PATCH 19/19] Fixed tests --- tests/reference/gui/0_nwProject.nwx | 4 ++-- tests/reference/gui/1_nwProject.nwx | 4 ++-- tests/reference/gui/3_nwProject.nwx | 4 ++-- tests/reference/proj/1_nwProject.nwx | 4 ++-- tests/reference/proj/2_nwProject.nwx | 4 ++-- tests/reference/proj/3_nwProject.nwx | 4 ++-- tests/test_gui.py | 7 ++++--- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/reference/gui/0_nwProject.nwx b/tests/reference/gui/0_nwProject.nwx index db1151d3..99ea2a3d 100644 --- a/tests/reference/gui/0_nwProject.nwx +++ b/tests/reference/gui/0_nwProject.nwx @@ -1,7 +1,7 @@ - + - + New Project True diff --git a/tests/reference/gui/1_nwProject.nwx b/tests/reference/gui/1_nwProject.nwx index bf16def6..c9bb4dad 100644 --- a/tests/reference/gui/1_nwProject.nwx +++ b/tests/reference/gui/1_nwProject.nwx @@ -1,7 +1,7 @@ - + - + New Project True diff --git a/tests/reference/gui/3_nwProject.nwx b/tests/reference/gui/3_nwProject.nwx index bee4eb0a..f7db491f 100644 --- a/tests/reference/gui/3_nwProject.nwx +++ b/tests/reference/gui/3_nwProject.nwx @@ -1,7 +1,7 @@ - + - + New Project True diff --git a/tests/reference/proj/1_nwProject.nwx b/tests/reference/proj/1_nwProject.nwx index 0e537470..651ae852 100644 --- a/tests/reference/proj/1_nwProject.nwx +++ b/tests/reference/proj/1_nwProject.nwx @@ -1,7 +1,7 @@ - + - + New Project True diff --git a/tests/reference/proj/2_nwProject.nwx b/tests/reference/proj/2_nwProject.nwx index eb98cc9f..7bd8d7cb 100644 --- a/tests/reference/proj/2_nwProject.nwx +++ b/tests/reference/proj/2_nwProject.nwx @@ -1,7 +1,7 @@ - + - + New Project True diff --git a/tests/reference/proj/3_nwProject.nwx b/tests/reference/proj/3_nwProject.nwx index 5238e40d..94f11ba7 100644 --- a/tests/reference/proj/3_nwProject.nwx +++ b/tests/reference/proj/3_nwProject.nwx @@ -1,7 +1,7 @@ - + - + New Project True diff --git a/tests/test_gui.py b/tests/test_gui.py index 424eb13b..47432f51 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -8,8 +8,8 @@ from nwtools import * from os import path, unlink from PyQt5.QtCore import Qt -from nw.gui.dialogs.projecteditor import GuiProjectSettings -from nw.gui.dialogs.itemeditor import GuiItemEditor +from nw.gui.dialogs.projectsettings import GuiProjectSettings +from nw.gui.dialogs.itemeditor import GuiItemEditor from nw.constants import * @@ -61,7 +61,7 @@ def testMainWindows(qtbot, nwTempGUI, nwRef, nwTemp): assert nwGUI.theProject.projPath == nwTempGUI assert nwGUI.theProject.projMeta == path.join(nwTempGUI,"meta") assert nwGUI.theProject.projFile == "nwProject.nwx" - assert nwGUI.theProject.projName == "" + assert nwGUI.theProject.projName == "New Project" assert nwGUI.theProject.bookTitle == "" assert len(nwGUI.theProject.bookAuthors) == 0 assert nwGUI.theProject.spellCheck == False @@ -265,6 +265,7 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef, nwTemp): projEdit = GuiProjectSettings(nwGUI, nwGUI.theProject) qtbot.addWidget(projEdit) + projEdit.tabMain.editName.setText("") for c in "Project Name": qtbot.keyClick(projEdit.tabMain.editName, c, delay=keyDelay) for c in "Project Title":