diff --git a/novelwriter/core/options.py b/novelwriter/core/options.py
index e0ce2a2c..bad425b1 100644
--- a/novelwriter/core/options.py
+++ b/novelwriter/core/options.py
@@ -43,13 +43,6 @@ VALID_MAP = {
"hideZeros", "hideNegative", "groupByDay", "showIdleTime", "histMax",
},
"GuiDocSplit": {"spLevel", "intoFolder", "docHierarchy"},
- "GuiBuildNovel": {
- "winWidth", "winHeight", "boxWidth", "docWidth", "hideScene",
- "hideSection", "addNovel", "addNotes", "ignoreFlag", "justifyText",
- "excludeBody", "textFont", "textSize", "lineHeight", "noStyling",
- "incSynopsis", "incComments", "incKeywords", "incBodyText",
- "replaceTabs", "replaceUCode", "rootFilter",
- },
"GuiOutline": {"headerOrder", "columnWidth", "columnHidden"},
"GuiProjectSettings": {
"winWidth", "winHeight", "replaceColW", "statusColW", "importColW",
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index 8870fa37..80b1f8ae 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -829,11 +829,6 @@ class GuiMainMenu(QMenuBar):
self.aBackupProject.triggered.connect(lambda: self.theProject.backupProject(True))
self.toolsMenu.addAction(self.aBackupProject)
- # Tools > Build Novel Project
- self.aBuildProject = QAction(self.tr("Build Novel Project"), self)
- self.aBuildProject.triggered.connect(self.mainGui.showBuildProjectDialog)
- self.toolsMenu.addAction(self.aBuildProject)
-
# Tools > Build Manuscript
self.aBuildManuscript = QAction(self.tr("Build Manuscript"), self)
self.aBuildManuscript.setShortcut("F5")
diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py
index 66370b36..637e11a5 100644
--- a/novelwriter/gui/sidebar.py
+++ b/novelwriter/gui/sidebar.py
@@ -82,8 +82,8 @@ class GuiSideBar(QToolBar):
self.aBuild = QAction(self.tr("Build"), self)
self.aBuild.setFont(lblFont)
- self.aBuild.setToolTip(self.tr("Build Novel Project"))
- self.aBuild.triggered.connect(lambda: self.mainGui.showBuildProjectDialog())
+ self.aBuild.setToolTip(self.tr("Build Manuscript"))
+ self.aBuild.triggered.connect(lambda: self.mainGui.showBuildManuscriptDialog())
self.aDetails = QAction(self.tr("Details"), self)
self.aDetails.setFont(lblFont)
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index f2922b24..2b536b8a 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -55,7 +55,6 @@ from novelwriter.dialogs.wordlist import GuiWordList
from novelwriter.dialogs.preferences import GuiPreferences
from novelwriter.dialogs.projdetails import GuiProjectDetails
from novelwriter.dialogs.projsettings import GuiProjectSettings
-from novelwriter.tools.build import GuiBuildNovel
from novelwriter.tools.lipsum import GuiLipsum
from novelwriter.tools.manuscript import GuiManuscript
from novelwriter.tools.projwizard import GuiProjectWizard
@@ -1010,26 +1009,6 @@ class GuiMain(QMainWindow):
return True
- def showBuildProjectDialog(self):
- """Open the build project dialog.
- """
- if not self.hasProject:
- logger.error("No project open")
- return False
-
- dlgBuild = getGuiItem("GuiBuildNovel")
- if dlgBuild is None:
- dlgBuild = GuiBuildNovel(self)
- assert isinstance(dlgBuild, GuiBuildNovel)
-
- dlgBuild.setModal(False)
- dlgBuild.show()
- dlgBuild.raise_()
- qApp.processEvents()
- dlgBuild.viewCachedDoc()
-
- return True
-
@pyqtSlot()
def showBuildManuscriptDialog(self):
"""Open the build manuscript dialog.
diff --git a/novelwriter/tools/build.py b/novelwriter/tools/build.py
deleted file mode 100644
index c013c7b8..00000000
--- a/novelwriter/tools/build.py
+++ /dev/null
@@ -1,1425 +0,0 @@
-"""
-novelWriter – GUI Build Novel Project
-=====================================
-GUI classes for the build novel project dialog
-
-File History:
-Created: 2020-05-09 [0.5]
-
-This file is a part of novelWriter
-Copyright 2018–2023, Veronica Berglyd Olsen
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-"""
-
-import json
-import logging
-
-from time import time
-from pathlib import Path
-from datetime import datetime
-
-from PyQt5.QtGui import (
- QPalette, QColor, QFont, QCursor, QFontInfo
-)
-from PyQt5.QtCore import Qt, QTimer
-from PyQt5.QtWidgets import (
- qApp, QDialog, QVBoxLayout, QHBoxLayout, QTextBrowser, QPushButton, QLabel,
- QLineEdit, QGroupBox, QGridLayout, QProgressBar, QMenu, QAction,
- QFileDialog, QFontDialog, QSpinBox, QScrollArea, QSplitter, QWidget,
- QSizePolicy, QDoubleSpinBox, QComboBox
-)
-from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
-
-from novelwriter import CONFIG
-from novelwriter.enum import nwAlert, nwItemType, nwItemLayout, nwItemClass
-from novelwriter.error import formatException, logException
-from novelwriter.common import fuzzyTime, makeFileNameSafe
-from novelwriter.constants import nwConst, nwFiles
-from novelwriter.core.tomd import ToMarkdown
-from novelwriter.core.toodt import ToOdt
-from novelwriter.core.tohtml import ToHtml
-from novelwriter.extensions.switch import NSwitch
-
-logger = logging.getLogger(__name__)
-
-
-class GuiBuildNovel(QDialog):
-
- FMT_PDF = 1 # Print to PDF
- FMT_ODT = 2 # Open Document file
- FMT_FODT = 3 # Flat Open Document file
- FMT_HTM = 4 # HTML5
- FMT_NWD = 5 # nW Markdown
- FMT_MD = 6 # Standard Markdown
- FMT_GH = 7 # GitHub Markdown
- FMT_JSON_H = 8 # HTML5 wrapped in JSON
- FMT_JSON_M = 9 # nW Markdown wrapped in JSON
-
- def __init__(self, mainGui):
- super().__init__(parent=mainGui)
-
- logger.debug("Initialising GuiBuildNovel ...")
- self.setObjectName("GuiBuildNovel")
-
- self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
- self.theProject = mainGui.theProject
-
- self.htmlText = [] # List of html documents
- self.htmlStyle = [] # List of html styles
- self.htmlSize = 0 # Size of the html document
- self.buildTime = 0 # The timestamp of the last build
-
- self.setWindowTitle(self.tr("Build Novel Project"))
- self.setMinimumWidth(CONFIG.pxInt(700))
- self.setMinimumHeight(CONFIG.pxInt(600))
-
- pOptions = self.theProject.options
- self.resize(
- CONFIG.pxInt(pOptions.getInt("GuiBuildNovel", "winWidth", 900)),
- CONFIG.pxInt(pOptions.getInt("GuiBuildNovel", "winHeight", 800))
- )
-
- self.docView = GuiBuildNovelDocView(self, self.theProject)
-
- hS = self.mainTheme.fontPixelSize
- wS = 2*hS
-
- # Title Formats
- # =============
-
- self.titleGroup = QGroupBox(self.tr("Title Formats for Novel Files"), self)
- self.titleForm = QGridLayout(self)
- self.titleGroup.setLayout(self.titleForm)
-
- fmtHelp = "
".join([
- "%s" % self.tr("Formatting Codes:"),
- self.tr("{0} for the title as set in the document").format(r"%title%"),
- self.tr("{0} for chapter number (1, 2, 3)").format(r"%ch%"),
- self.tr("{0} for chapter number as a word (one, two)").format(r"%chw%"),
- self.tr("{0} for chapter number in upper case Roman").format(r"%chI%"),
- self.tr("{0} for chapter number in lower case Roman").format(r"%chi%"),
- self.tr("{0} for scene number within chapter").format(r"%sc%"),
- self.tr("{0} for scene number within novel").format(r"%sca%"),
- ])
- fmtScHelp = "
%s" % self.tr(
- "Leave blank to skip this heading, or set to a static text, like "
- "for instance '{0}', to make a separator. The separator will "
- "be centred automatically and only appear between sections of "
- "the same type."
- ).format("* * *")
- xFmt = CONFIG.pxInt(100)
-
- self.fmtTitle = QLineEdit()
- self.fmtTitle.setMaxLength(200)
- self.fmtTitle.setMinimumWidth(xFmt)
- self.fmtTitle.setToolTip(fmtHelp)
- self.fmtTitle.setText(
- self._reFmtCodes(self.theProject.data.getTitleFormat("title"))
- )
-
- self.fmtChapter = QLineEdit()
- self.fmtChapter.setMaxLength(200)
- self.fmtChapter.setMinimumWidth(xFmt)
- self.fmtChapter.setToolTip(fmtHelp)
- self.fmtChapter.setText(
- self._reFmtCodes(self.theProject.data.getTitleFormat("chapter"))
- )
-
- self.fmtUnnumbered = QLineEdit()
- self.fmtUnnumbered.setMaxLength(200)
- self.fmtUnnumbered.setMinimumWidth(xFmt)
- self.fmtUnnumbered.setToolTip(fmtHelp)
- self.fmtUnnumbered.setText(
- self._reFmtCodes(self.theProject.data.getTitleFormat("unnumbered"))
- )
-
- self.fmtScene = QLineEdit()
- self.fmtScene.setMaxLength(200)
- self.fmtScene.setMinimumWidth(xFmt)
- self.fmtScene.setToolTip(fmtHelp + fmtScHelp)
- self.fmtScene.setText(
- self._reFmtCodes(self.theProject.data.getTitleFormat("scene"))
- )
-
- self.fmtSection = QLineEdit()
- self.fmtSection.setMaxLength(200)
- self.fmtSection.setMinimumWidth(xFmt)
- self.fmtSection.setToolTip(fmtHelp + fmtScHelp)
- self.fmtSection.setText(
- self._reFmtCodes(self.theProject.data.getTitleFormat("section"))
- )
-
- self.buildLang = QComboBox()
- self.buildLang.setMinimumWidth(xFmt)
- theLangs = CONFIG.listLanguages(CONFIG.LANG_PROJ)
- self.buildLang.addItem("[%s]" % self.tr("Not Set"), "None")
- for langID, langName in theLangs:
- self.buildLang.addItem(langName, langID)
-
- langIdx = self.buildLang.findData(self.theProject.data.language)
- if langIdx != -1:
- self.buildLang.setCurrentIndex(langIdx)
-
- self.hideScene = NSwitch(width=wS, height=hS)
- self.hideScene.setChecked(
- pOptions.getBool("GuiBuildNovel", "hideScene", False)
- )
-
- self.hideSection = NSwitch(width=wS, height=hS)
- self.hideSection.setChecked(
- pOptions.getBool("GuiBuildNovel", "hideSection", True)
- )
-
- # Wrapper boxes due to QGridView and QLineEdit expand bug
- self.boxTitle = QHBoxLayout()
- self.boxTitle.addWidget(self.fmtTitle)
- self.boxChapter = QHBoxLayout()
- self.boxChapter.addWidget(self.fmtChapter)
- self.boxUnnumb = QHBoxLayout()
- self.boxUnnumb.addWidget(self.fmtUnnumbered)
- self.boxScene = QHBoxLayout()
- self.boxScene.addWidget(self.fmtScene)
- self.boxSection = QHBoxLayout()
- self.boxSection.addWidget(self.fmtSection)
-
- titleLabel = QLabel(self.tr("Title"))
- chapterLabel = QLabel(self.tr("Chapter"))
- unnumbLabel = QLabel(self.tr("Unnumbered"))
- sceneLabel = QLabel(self.tr("Scene"))
- sectionLabel = QLabel(self.tr("Section"))
- langLabel = QLabel(self.tr("Language"))
- hSceneLabel = QLabel(self.tr("Hide scene"))
- hSectionLabel = QLabel(self.tr("Hide section"))
-
- self.titleForm.addWidget(titleLabel, 0, 0, 1, 1, Qt.AlignLeft)
- self.titleForm.addLayout(self.boxTitle, 0, 1, 1, 1, Qt.AlignRight)
- self.titleForm.addWidget(chapterLabel, 1, 0, 1, 1, Qt.AlignLeft)
- self.titleForm.addLayout(self.boxChapter, 1, 1, 1, 1, Qt.AlignRight)
- self.titleForm.addWidget(unnumbLabel, 2, 0, 1, 1, Qt.AlignLeft)
- self.titleForm.addLayout(self.boxUnnumb, 2, 1, 1, 1, Qt.AlignRight)
- self.titleForm.addWidget(sceneLabel, 3, 0, 1, 1, Qt.AlignLeft)
- self.titleForm.addLayout(self.boxScene, 3, 1, 1, 1, Qt.AlignRight)
- self.titleForm.addWidget(sectionLabel, 4, 0, 1, 1, Qt.AlignLeft)
- self.titleForm.addLayout(self.boxSection, 4, 1, 1, 1, Qt.AlignRight)
- self.titleForm.addWidget(langLabel, 5, 0, 1, 1, Qt.AlignLeft)
- self.titleForm.addWidget(self.buildLang, 5, 1, 1, 1, Qt.AlignRight)
- self.titleForm.addWidget(hSceneLabel, 6, 0, 1, 1, Qt.AlignLeft)
- self.titleForm.addWidget(self.hideScene, 6, 1, 1, 1, Qt.AlignRight)
- self.titleForm.addWidget(hSectionLabel, 7, 0, 1, 1, Qt.AlignLeft)
- self.titleForm.addWidget(self.hideSection, 7, 1, 1, 1, Qt.AlignRight)
-
- self.titleForm.setColumnStretch(0, 0)
- self.titleForm.setColumnStretch(1, 1)
-
- # Font Options
- # ============
-
- self.fontGroup = QGroupBox(self.tr("Font Options"), self)
- self.fontForm = QGridLayout(self)
- self.fontGroup.setLayout(self.fontForm)
-
- # Font Family
- self.textFont = QLineEdit()
- self.textFont.setReadOnly(True)
- self.textFont.setMinimumWidth(xFmt)
- self.textFont.setText(
- pOptions.getString("GuiBuildNovel", "textFont", CONFIG.textFont)
- )
- self.fontButton = QPushButton("...")
- self.fontButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
- self.fontButton.clicked.connect(self._selectFont)
-
- self.textSize = QSpinBox(self)
- self.textSize.setFixedWidth(6*self.mainTheme.textNWidth)
- self.textSize.setMinimum(6)
- self.textSize.setMaximum(72)
- self.textSize.setSingleStep(1)
- self.textSize.setValue(
- pOptions.getInt("GuiBuildNovel", "textSize", CONFIG.textSize)
- )
-
- self.lineHeight = QDoubleSpinBox(self)
- self.lineHeight.setFixedWidth(6*self.mainTheme.textNWidth)
- self.lineHeight.setMinimum(0.8)
- self.lineHeight.setMaximum(3.0)
- self.lineHeight.setSingleStep(0.05)
- self.lineHeight.setDecimals(2)
- self.lineHeight.setValue(
- pOptions.getFloat("GuiBuildNovel", "lineHeight", 1.15)
- )
-
- # Wrapper box due to QGridView and QLineEdit expand bug
- self.boxFont = QHBoxLayout()
- self.boxFont.addWidget(self.textFont)
-
- fontFamilyLabel = QLabel(self.tr("Font family"))
- fontSizeLabel = QLabel(self.tr("Font size"))
- lineHeightLabel = QLabel(self.tr("Line height"))
- justifyLabel = QLabel(self.tr("Justify text"))
- stylingLabel = QLabel(self.tr("Disable styling"))
-
- self.fontForm.addWidget(fontFamilyLabel, 0, 0, 1, 1, Qt.AlignLeft)
- self.fontForm.addLayout(self.boxFont, 0, 1, 1, 1, Qt.AlignRight)
- self.fontForm.addWidget(self.fontButton, 0, 2, 1, 1, Qt.AlignRight)
- self.fontForm.addWidget(fontSizeLabel, 1, 0, 1, 1, Qt.AlignLeft)
- self.fontForm.addWidget(self.textSize, 1, 1, 1, 2, Qt.AlignRight)
- self.fontForm.addWidget(lineHeightLabel, 2, 0, 1, 1, Qt.AlignLeft)
- self.fontForm.addWidget(self.lineHeight, 2, 1, 1, 2, Qt.AlignRight)
-
- self.fontForm.setColumnStretch(0, 0)
- self.fontForm.setColumnStretch(1, 1)
- self.fontForm.setColumnStretch(2, 0)
-
- # Styling Options
- # ===============
-
- self.styleGroup = QGroupBox(self.tr("Styling Options"), self)
- self.styleForm = QGridLayout(self)
- self.styleGroup.setLayout(self.styleForm)
-
- self.justifyText = NSwitch(width=wS, height=hS)
- self.justifyText.setChecked(
- pOptions.getBool("GuiBuildNovel", "justifyText", False)
- )
-
- self.noStyling = NSwitch(width=wS, height=hS)
- self.noStyling.setChecked(
- pOptions.getBool("GuiBuildNovel", "noStyling", False)
- )
-
- self.styleForm.addWidget(justifyLabel, 1, 0, 1, 1, Qt.AlignLeft)
- self.styleForm.addWidget(self.justifyText, 1, 1, 1, 2, Qt.AlignRight)
- self.styleForm.addWidget(stylingLabel, 2, 0, 1, 1, Qt.AlignLeft)
- self.styleForm.addWidget(self.noStyling, 2, 1, 1, 2, Qt.AlignRight)
-
- self.styleForm.setColumnStretch(0, 0)
- self.styleForm.setColumnStretch(1, 1)
-
- # Include Options
- # ===============
-
- self.textGroup = QGroupBox(self.tr("Include Options"), self)
- self.textForm = QGridLayout(self)
- self.textGroup.setLayout(self.textForm)
-
- self.includeSynopsis = NSwitch(width=wS, height=hS)
- self.includeSynopsis.setChecked(
- pOptions.getBool("GuiBuildNovel", "incSynopsis", False)
- )
-
- self.includeComments = NSwitch(width=wS, height=hS)
- self.includeComments.setChecked(
- pOptions.getBool("GuiBuildNovel", "incComments", False)
- )
-
- self.includeKeywords = NSwitch(width=wS, height=hS)
- self.includeKeywords.setChecked(
- pOptions.getBool("GuiBuildNovel", "incKeywords", False)
- )
-
- self.includeBody = NSwitch(width=wS, height=hS)
- self.includeBody.setChecked(
- pOptions.getBool("GuiBuildNovel", "incBodyText", True)
- )
-
- synopsisLabel = QLabel(self.tr("Include synopsis"))
- commentsLabel = QLabel(self.tr("Include comments"))
- keywordsLabel = QLabel(self.tr("Include keywords"))
- bodyLabel = QLabel(self.tr("Include body text"))
-
- self.textForm.addWidget(synopsisLabel, 0, 0, 1, 1, Qt.AlignLeft)
- self.textForm.addWidget(self.includeSynopsis, 0, 1, 1, 1, Qt.AlignRight)
- self.textForm.addWidget(commentsLabel, 1, 0, 1, 1, Qt.AlignLeft)
- self.textForm.addWidget(self.includeComments, 1, 1, 1, 1, Qt.AlignRight)
- self.textForm.addWidget(keywordsLabel, 2, 0, 1, 1, Qt.AlignLeft)
- self.textForm.addWidget(self.includeKeywords, 2, 1, 1, 1, Qt.AlignRight)
- self.textForm.addWidget(bodyLabel, 3, 0, 1, 1, Qt.AlignLeft)
- self.textForm.addWidget(self.includeBody, 3, 1, 1, 1, Qt.AlignRight)
-
- self.textForm.setColumnStretch(0, 1)
- self.textForm.setColumnStretch(1, 0)
-
- # Root Filter Options
- # ===================
-
- self.rootGroup = QGroupBox(self.tr("Root Filter Options"), self)
- self.rootForm = QGridLayout(self)
- self.rootGroup.setLayout(self.rootForm)
-
- rootFilter = pOptions.getValue("GuiBuildNovel", "rootFilter", [])
- if not isinstance(rootFilter, list):
- rootFilter = []
-
- iRow = 0
- self.rootSelection = {}
- for tHandle, nwItem in self.theProject.tree.iterRoots(None):
- if not nwItem.isInactiveClass():
- rootLabel = QLabel(nwItem.itemName)
- rootLabel.setWordWrap(True)
-
- rootValue = NSwitch(width=wS, height=hS)
- rootValue.setChecked(tHandle not in rootFilter)
-
- self.rootSelection[tHandle] = rootValue
- self.rootForm.addWidget(rootLabel, iRow, 0, 1, 1, Qt.AlignLeft)
- self.rootForm.addWidget(rootValue, iRow, 1, 1, 1, Qt.AlignRight)
-
- iRow += 1
-
- self.rootForm.setColumnStretch(0, 1)
- self.rootForm.setColumnStretch(1, 0)
-
- # File Filter Options
- # ===================
-
- self.fileGroup = QGroupBox(self.tr("File Filter Options"), self)
- self.fileForm = QGridLayout(self)
- self.fileGroup.setLayout(self.fileForm)
-
- self.novelFiles = NSwitch(width=wS, height=hS)
- self.novelFiles.setChecked(
- pOptions.getBool("GuiBuildNovel", "addNovel", True)
- )
-
- self.noteFiles = NSwitch(width=wS, height=hS)
- self.noteFiles.setChecked(
- pOptions.getBool("GuiBuildNovel", "addNotes", False)
- )
-
- self.ignoreFlag = NSwitch(width=wS, height=hS)
- self.ignoreFlag.setChecked(
- pOptions.getBool("GuiBuildNovel", "ignoreFlag", False)
- )
-
- novelLabel = QLabel(self.tr("Include novel files"))
- notesLabel = QLabel(self.tr("Include note files"))
- activeLabel = QLabel(self.tr("Include inactive files"))
-
- self.fileForm.addWidget(novelLabel, 0, 0, 1, 1, Qt.AlignLeft)
- self.fileForm.addWidget(self.novelFiles, 0, 1, 1, 1, Qt.AlignRight)
- self.fileForm.addWidget(notesLabel, 1, 0, 1, 1, Qt.AlignLeft)
- self.fileForm.addWidget(self.noteFiles, 1, 1, 1, 1, Qt.AlignRight)
- self.fileForm.addWidget(activeLabel, 2, 0, 1, 1, Qt.AlignLeft)
- self.fileForm.addWidget(self.ignoreFlag, 2, 1, 1, 1, Qt.AlignRight)
-
- self.fileForm.setColumnStretch(0, 1)
- self.fileForm.setColumnStretch(1, 0)
-
- # Export Options
- # ==============
-
- self.exportGroup = QGroupBox(self.tr("Export Options"), self)
- self.exportForm = QGridLayout(self)
- self.exportGroup.setLayout(self.exportForm)
-
- self.replaceTabs = NSwitch(width=wS, height=hS)
- self.replaceTabs.setChecked(
- pOptions.getBool("GuiBuildNovel", "replaceTabs", False)
- )
-
- self.replaceUCode = NSwitch(width=wS, height=hS)
- self.replaceUCode.setChecked(
- pOptions.getBool("GuiBuildNovel", "replaceUCode", False)
- )
-
- tabsLabel = QLabel(self.tr("Replace tabs with spaces"))
- uCodeLabel = QLabel(self.tr("Replace Unicode in HTML"))
-
- self.exportForm.addWidget(tabsLabel, 0, 0, 1, 1, Qt.AlignLeft)
- self.exportForm.addWidget(self.replaceTabs, 0, 1, 1, 1, Qt.AlignRight)
- self.exportForm.addWidget(uCodeLabel, 1, 0, 1, 1, Qt.AlignLeft)
- self.exportForm.addWidget(self.replaceUCode, 1, 1, 1, 1, Qt.AlignRight)
-
- self.exportForm.setColumnStretch(0, 1)
- self.exportForm.setColumnStretch(1, 0)
-
- # Build Button
- # ============
-
- self.buildProgress = QProgressBar()
-
- self.buildNovel = QPushButton(self.tr("Build Preview"))
- self.buildNovel.clicked.connect(self._buildPreview)
-
- # Action Buttons
- # ==============
-
- self.buttonBox = QHBoxLayout()
-
- # Printing
-
- self.printMenu = QMenu(self)
- self.btnPrint = QPushButton(self.tr("Print"))
- self.btnPrint.setMenu(self.printMenu)
-
- self.printSend = QAction(self.tr("Print Preview"), self)
- self.printSend.triggered.connect(self._printDocument)
- self.printMenu.addAction(self.printSend)
-
- self.printFile = QAction(self.tr("Print to PDF"), self)
- self.printFile.triggered.connect(lambda: self._saveDocument(self.FMT_PDF))
- self.printMenu.addAction(self.printFile)
-
- # Saving to File
-
- self.saveMenu = QMenu(self)
- self.btnSave = QPushButton(self.tr("Save As"))
- self.btnSave.setMenu(self.saveMenu)
-
- self.saveODT = QAction(self.tr("Open Document (.odt)"), self)
- self.saveODT.triggered.connect(lambda: self._saveDocument(self.FMT_ODT))
- self.saveMenu.addAction(self.saveODT)
-
- self.saveFODT = QAction(self.tr("Flat Open Document (.fodt)"), self)
- self.saveFODT.triggered.connect(lambda: self._saveDocument(self.FMT_FODT))
- self.saveMenu.addAction(self.saveFODT)
-
- self.saveHTM = QAction(self.tr("novelWriter HTML (.htm)"), self)
- self.saveHTM.triggered.connect(lambda: self._saveDocument(self.FMT_HTM))
- self.saveMenu.addAction(self.saveHTM)
-
- self.saveNWD = QAction(self.tr("novelWriter Markdown (.nwd)"), self)
- self.saveNWD.triggered.connect(lambda: self._saveDocument(self.FMT_NWD))
- self.saveMenu.addAction(self.saveNWD)
-
- self.saveMD = QAction(self.tr("Standard Markdown (.md)"), self)
- self.saveMD.triggered.connect(lambda: self._saveDocument(self.FMT_MD))
- self.saveMenu.addAction(self.saveMD)
-
- self.saveGH = QAction(self.tr("GitHub Markdown (.md)"), self)
- self.saveGH.triggered.connect(lambda: self._saveDocument(self.FMT_GH))
- self.saveMenu.addAction(self.saveGH)
-
- self.saveJsonH = QAction(self.tr("JSON + novelWriter HTML (.json)"), self)
- self.saveJsonH.triggered.connect(lambda: self._saveDocument(self.FMT_JSON_H))
- self.saveMenu.addAction(self.saveJsonH)
-
- self.saveJsonM = QAction(self.tr("JSON + novelWriter Markdown (.json)"), self)
- self.saveJsonM.triggered.connect(lambda: self._saveDocument(self.FMT_JSON_M))
- self.saveMenu.addAction(self.saveJsonM)
-
- self.btnClose = QPushButton(self.tr("Close"))
- self.btnClose.clicked.connect(self._doClose)
-
- self.buttonBox.addWidget(self.btnSave)
- self.buttonBox.addWidget(self.btnPrint)
- self.buttonBox.addWidget(self.btnClose)
- self.buttonBox.setSpacing(CONFIG.pxInt(4))
-
- # Assemble GUI
- # ============
-
- # Splitter Position
- boxWidth = CONFIG.pxInt(350)
- boxWidth = pOptions.getInt("GuiBuildNovel", "boxWidth", boxWidth)
- docWidth = max(self.width() - boxWidth, 100)
- docWidth = pOptions.getInt("GuiBuildNovel", "docWidth", docWidth)
-
- # The Tool Box
- self.toolsBox = QVBoxLayout()
- self.toolsBox.addWidget(self.titleGroup)
- self.toolsBox.addWidget(self.fontGroup)
- self.toolsBox.addWidget(self.styleGroup)
- self.toolsBox.addWidget(self.textGroup)
- self.toolsBox.addWidget(self.rootGroup)
- self.toolsBox.addWidget(self.fileGroup)
- self.toolsBox.addWidget(self.exportGroup)
- self.toolsBox.addStretch(1)
-
- # Tool Box Wrapper Widget
- self.toolsWidget = QWidget()
- self.toolsWidget.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
- self.toolsWidget.setLayout(self.toolsBox)
-
- # Tool Box Scroll Area
- self.toolsArea = QScrollArea()
- self.toolsArea.setMinimumWidth(CONFIG.pxInt(250))
- self.toolsArea.setWidgetResizable(True)
- self.toolsArea.setWidget(self.toolsWidget)
-
- if CONFIG.hideVScroll:
- self.toolsArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- else:
- self.toolsArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
-
- if CONFIG.hideHScroll:
- self.toolsArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- else:
- self.toolsArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
-
- # Tools and Buttons Layout
- tSp = CONFIG.pxInt(8)
- self.innerBox = QVBoxLayout()
- self.innerBox.addWidget(self.toolsArea)
- self.innerBox.addSpacing(tSp)
- self.innerBox.addWidget(self.buildProgress)
- self.innerBox.addWidget(self.buildNovel)
- self.innerBox.addSpacing(tSp)
- self.innerBox.addLayout(self.buttonBox)
-
- # Tools and Buttons Wrapper Widget
- self.innerWidget = QWidget()
- self.innerWidget.setLayout(self.innerBox)
-
- # Main Dialog Splitter
- self.mainSplit = QSplitter(Qt.Horizontal)
- self.mainSplit.addWidget(self.innerWidget)
- self.mainSplit.addWidget(self.docView)
- self.mainSplit.setSizes([boxWidth, docWidth])
-
- self.idxSettings = self.mainSplit.indexOf(self.innerWidget)
- self.idxDocument = self.mainSplit.indexOf(self.docView)
-
- self.mainSplit.setCollapsible(self.idxSettings, False)
- self.mainSplit.setCollapsible(self.idxDocument, False)
-
- # Outer Layout
- self.outerBox = QHBoxLayout()
- self.outerBox.addWidget(self.mainSplit)
-
- self.setLayout(self.outerBox)
- self.buildNovel.setFocus()
-
- logger.debug("GuiBuildNovel initialisation complete")
-
- return
-
- def viewCachedDoc(self):
- """Load the previously generated document from cache.
- """
- if self._loadCache():
- textFont = self.textFont.text()
- textSize = self.textSize.value()
- justifyText = self.justifyText.isChecked()
- self.docView.setTextFont(textFont, textSize)
- self.docView.setJustify(justifyText)
- if self.noStyling.isChecked():
- self.docView.clearStyleSheet()
- else:
- self.docView.setStyleSheet(self.htmlStyle)
-
- htmlSize = sum([len(x) for x in self.htmlText])
- if htmlSize < nwConst.MAX_BUILDSIZE:
- qApp.processEvents()
- self.docView.setContent(self.htmlText, self.buildTime)
- else:
- self.docView.setText(
- self.tr("Failed to generate preview. The result is too big.")
- )
-
- else:
- self.htmlText = []
- self.htmlStyle = []
- self.buildTime = 0
- return False
-
- return True
-
- ##
- # Slots and Related
- ##
-
- def _buildPreview(self):
- """Build a preview of the project in the document viewer.
- """
- # Get Settings
- justifyText = self.justifyText.isChecked()
- noStyling = self.noStyling.isChecked()
- textFont = self.textFont.text()
- textSize = self.textSize.value()
- replaceTabs = self.replaceTabs.isChecked()
-
- self.htmlText = []
- self.htmlStyle = []
- self.htmlSize = 0
-
- # Build Preview
- # =============
-
- makeHtml = ToHtml(self.theProject)
- self._doBuild(makeHtml, isPreview=True)
- if replaceTabs:
- makeHtml.replaceTabs()
-
- self.htmlText = makeHtml.fullHTML
- self.htmlStyle = makeHtml.getStyleSheet()
- self.htmlSize = makeHtml.getFullResultSize()
- self.buildTime = int(time())
-
- # Load Preview
- # ============
-
- self.docView.setTextFont(textFont, textSize)
- self.docView.setJustify(justifyText)
- if noStyling:
- self.docView.clearStyleSheet()
- else:
- self.docView.setStyleSheet(self.htmlStyle)
-
- if self.htmlSize < nwConst.MAX_BUILDSIZE:
- self.docView.setContent(self.htmlText, self.buildTime)
- else:
- self.docView.setText(
- "Failed to generate preview. The result is too big."
- )
-
- self._saveCache()
-
- return
-
- def _doBuild(self, bldObj, isPreview=False, doConvert=True):
- """Run the build with a specific build object.
- """
- tStart = int(time())
-
- # Get Settings
- fmtTitle = self.fmtTitle.text()
- fmtChapter = self.fmtChapter.text()
- fmtUnnumbered = self.fmtUnnumbered.text()
- fmtScene = self.fmtScene.text()
- fmtSection = self.fmtSection.text()
- buildLang = self.buildLang.currentData()
- hideScene = self.hideScene.isChecked()
- hideSection = self.hideSection.isChecked()
- textFont = self.textFont.text()
- textSize = self.textSize.value()
- lineHeight = self.lineHeight.value()
- justifyText = self.justifyText.isChecked()
- noStyling = self.noStyling.isChecked()
- incSynopsis = self.includeSynopsis.isChecked()
- incComments = self.includeComments.isChecked()
- incKeywords = self.includeKeywords.isChecked()
- novelFiles = self.novelFiles.isChecked()
- noteFiles = self.noteFiles.isChecked()
- ignoreFlag = self.ignoreFlag.isChecked()
- includeBody = self.includeBody.isChecked()
- replaceUCode = self.replaceUCode.isChecked()
-
- # The language lookup dict is reloaded if needed
- self.theProject.setProjectLang(buildLang)
-
- # Get font information
- fontInfo = QFontInfo(QFont(textFont, textSize))
- textFixed = fontInfo.fixedPitch()
-
- isHtml = isinstance(bldObj, ToHtml)
- isOdt = isinstance(bldObj, ToOdt)
-
- bldObj.setTitleFormat(fmtTitle)
- bldObj.setChapterFormat(fmtChapter)
- bldObj.setUnNumberedFormat(fmtUnnumbered)
- bldObj.setSceneFormat(fmtScene, hideScene)
- bldObj.setSectionFormat(fmtSection, hideSection)
-
- bldObj.setFont(textFont, textSize, textFixed)
- bldObj.setJustify(justifyText)
- bldObj.setLineHeight(lineHeight)
-
- bldObj.setSynopsis(incSynopsis)
- bldObj.setComments(incComments)
- bldObj.setKeywords(incKeywords)
- bldObj.setBodyText(includeBody)
-
- if isHtml:
- bldObj.setStyles(not noStyling)
- bldObj.setReplaceUnicode(replaceUCode)
-
- if isOdt:
- bldObj.setColourHeaders(not noStyling)
- bldObj.setLanguage(buildLang)
- bldObj.initDocument()
-
- # Make sure the project and document is up to date
- self.mainGui.saveDocument()
-
- self.buildProgress.setMaximum(len(self.theProject.tree))
- self.buildProgress.setValue(0)
-
- rootFilter = set(self._generateRootFilter())
- for nItt, tItem in enumerate(self.theProject.tree):
-
- noteRoot = noteFiles
- noteRoot &= tItem.itemType == nwItemType.ROOT
- noteRoot &= tItem.itemClass != nwItemClass.NOVEL
- noteRoot &= tItem.itemClass != nwItemClass.ARCHIVE
-
- try:
- if noteRoot:
- # Add headers for root folders of notes
- bldObj.addRootHeading(tItem.itemHandle)
- if doConvert:
- bldObj.doConvert()
-
- elif self._checkInclude(tItem, noteFiles, novelFiles, ignoreFlag, rootFilter):
- bldObj.setText(tItem.itemHandle)
- bldObj.doPreProcessing()
- bldObj.tokenizeText()
- bldObj.doHeaders()
- if doConvert:
- bldObj.doConvert()
-
- except Exception:
- logger.error("Failed to build document '%s'", tItem.itemHandle)
- logException()
- if isPreview:
- self.docView.setText((
- "Failed to generate preview. "
- "Document with title '%s' could not be parsed."
- ) % tItem.itemName)
-
- return False
-
- # Update progress bar, also for skipped items
- self.buildProgress.setValue(nItt+1)
-
- if isOdt:
- bldObj.closeDocument()
-
- tEnd = int(time())
- logger.debug("Built project in %.3f ms", 1000*(tEnd - tStart))
-
- if bldObj.errData:
- self.mainGui.makeAlert([
- self.tr("There were problems when building the project:")
- ] + bldObj.errData, nwAlert.ERROR)
-
- return
-
- def _checkInclude(self, theItem, noteFiles, novelFiles, ignoreFlag, rootFilter):
- """This function checks whether a file should be included in the
- export or not. For standard note and novel files, this is
- controlled by the options selected by the user. For other files
- classified as non-exportable, a few checks must be made, and the
- following are not:
- * Items that are not actual files.
- * Items that have been orphaned which are tagged as NO_LAYOUT
- and NO_CLASS.
- * Items that appear in the TRASH folder or have parent set to
- None (orphaned files).
- """
- if theItem is None:
- return False
-
- if not (theItem.isActive or ignoreFlag):
- return False
-
- if theItem.itemRoot in rootFilter:
- return False
-
- isNone = not theItem.isFileType()
- isNone |= theItem.itemLayout == nwItemLayout.NO_LAYOUT
- isNone |= theItem.isInactiveClass()
- isNone |= theItem.itemParent is None
- isNote = theItem.isNoteLayout()
- isNovel = not isNone and not isNote
-
- if isNone:
- return False
- if isNote and not noteFiles:
- return False
- if isNovel and not novelFiles:
- return False
-
- return True
-
- def _saveDocument(self, theFmt):
- """Save the document to various formats.
- """
- replaceTabs = self.replaceTabs.isChecked()
-
- fileExt = ""
- textFmt = ""
-
- # Settings
- # ========
-
- if theFmt == self.FMT_ODT:
- fileExt = "odt"
- textFmt = self.tr("Open Document")
-
- elif theFmt == self.FMT_FODT:
- fileExt = "fodt"
- textFmt = self.tr("Flat Open Document")
-
- elif theFmt == self.FMT_HTM:
- fileExt = "htm"
- textFmt = self.tr("Plain HTML")
-
- elif theFmt == self.FMT_NWD:
- fileExt = "nwd"
- textFmt = self.tr("novelWriter Markdown")
-
- elif theFmt == self.FMT_MD:
- fileExt = "md"
- textFmt = self.tr("Standard Markdown")
-
- elif theFmt == self.FMT_GH:
- fileExt = "md"
- textFmt = self.tr("GitHub Markdown")
-
- elif theFmt == self.FMT_JSON_H:
- fileExt = "json"
- textFmt = self.tr("JSON + novelWriter HTML")
-
- elif theFmt == self.FMT_JSON_M:
- fileExt = "json"
- textFmt = self.tr("JSON + novelWriter Markdown")
-
- elif theFmt == self.FMT_PDF:
- fileExt = "pdf"
- textFmt = self.tr("PDF")
-
- else:
- return False
-
- # Generate File Name
- # ==================
-
- cleanName = makeFileNameSafe(self.theProject.data.name)
- fileName = "%s.%s" % (cleanName, fileExt)
- savePath = CONFIG.lastPath() / fileName
- savePath, _ = QFileDialog.getSaveFileName(
- self, self.tr("Save Document As"), str(savePath)
- )
- if not savePath:
- return False
-
- CONFIG.setLastPath(savePath)
-
- # Build and Write
- # ===============
-
- errMsg = ""
- wSuccess = False
-
- if theFmt == self.FMT_ODT:
- makeOdt = ToOdt(self.theProject, isFlat=False)
- self._doBuild(makeOdt)
- try:
- makeOdt.saveOpenDocText(savePath)
- wSuccess = True
- except Exception as exc:
- errMsg = formatException(exc)
-
- elif theFmt == self.FMT_FODT:
- makeOdt = ToOdt(self.theProject, isFlat=True)
- self._doBuild(makeOdt)
- try:
- makeOdt.saveFlatXML(savePath)
- wSuccess = True
- except Exception as exc:
- errMsg = formatException(exc)
-
- elif theFmt == self.FMT_HTM:
- makeHtml = ToHtml(self.theProject)
- self._doBuild(makeHtml)
- if replaceTabs:
- makeHtml.replaceTabs()
-
- try:
- makeHtml.saveHTML5(savePath)
- wSuccess = True
- except Exception as exc:
- errMsg = formatException(exc)
-
- elif theFmt == self.FMT_NWD:
- makeNwd = ToMarkdown(self.theProject)
- makeNwd.setKeepMarkdown(True)
- self._doBuild(makeNwd, doConvert=False)
- if replaceTabs:
- makeNwd.replaceTabs(spaceChar=" ")
-
- try:
- makeNwd.saveRawMarkdown(savePath)
- wSuccess = True
- except Exception as exc:
- errMsg = formatException(exc)
-
- elif theFmt in (self.FMT_MD, self.FMT_GH):
- makeMd = ToMarkdown(self.theProject)
- if theFmt == self.FMT_GH:
- makeMd.setGitHubMarkdown()
- else:
- makeMd.setStandardMarkdown()
-
- self._doBuild(makeMd)
- if replaceTabs:
- makeMd.replaceTabs(nSpaces=4, spaceChar=" ")
-
- try:
- makeMd.saveMarkdown(savePath)
- wSuccess = True
- except Exception as exc:
- errMsg = formatException(exc)
-
- elif theFmt == self.FMT_JSON_H or theFmt == self.FMT_JSON_M:
- jsonData = {
- "meta": {
- "projectName": self.theProject.data.name,
- "novelTitle": self.theProject.data.title,
- "novelAuthor": self.theProject.data.author,
- "buildTime": self.buildTime,
- }
- }
-
- if theFmt == self.FMT_JSON_H:
- makeHtml = ToHtml(self.theProject)
- self._doBuild(makeHtml)
- if replaceTabs:
- makeHtml.replaceTabs()
-
- theBody = []
- for htmlPage in makeHtml.fullHTML:
- theBody.append(htmlPage.rstrip("\n").split("\n"))
- jsonData["text"] = {
- "css": self.htmlStyle,
- "html": theBody,
- }
-
- elif theFmt == self.FMT_JSON_M:
- makeMd = ToHtml(self.theProject)
- makeMd.setKeepMarkdown(True)
- self._doBuild(makeMd, doConvert=False)
- if replaceTabs:
- makeMd.replaceTabs(spaceChar=" ")
-
- theBody = []
- for nwdPage in makeMd.theMarkdown:
- theBody.append(nwdPage.split("\n"))
- jsonData["text"] = {
- "nwd": theBody,
- }
-
- try:
- with open(savePath, mode="w", encoding="utf-8") as outFile:
- outFile.write(json.dumps(jsonData, indent=2))
- wSuccess = True
- except Exception as exc:
- errMsg = formatException(exc)
-
- elif theFmt == self.FMT_PDF:
- try:
- thePrinter = QPrinter()
- thePrinter.setOutputFormat(QPrinter.PdfFormat)
- thePrinter.setOrientation(QPrinter.Portrait)
- thePrinter.setDuplex(QPrinter.DuplexLongSide)
- thePrinter.setFontEmbeddingEnabled(True)
- thePrinter.setColorMode(QPrinter.Color)
- thePrinter.setOutputFileName(savePath)
- self.docView.document().print(thePrinter)
- wSuccess = True
-
- except Exception as exc:
- errMsg = formatException(exc)
-
- else:
- # If the if statements above and here match, it should not
- # be possible to reach this else statement.
- return False # pragma: no cover
-
- # Report to User
- # ==============
-
- if wSuccess:
- self.mainGui.makeAlert([
- self.tr("{0} file successfully written to:").format(textFmt), savePath
- ], nwAlert.INFO)
- else:
- self.mainGui.makeAlert(self.tr(
- "Failed to write {0} file. {1}"
- ).format(textFmt, errMsg), nwAlert.ERROR)
-
- return wSuccess
-
- def _printDocument(self):
- """Open the print preview dialog.
- """
- thePreview = QPrintPreviewDialog(self)
- thePreview.paintRequested.connect(self._doPrintPreview)
- thePreview.exec_()
- return
-
- def _doPrintPreview(self, thePrinter):
- """Connect the print preview painter to the document viewer.
- """
- qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
- thePrinter.setOrientation(QPrinter.Portrait)
- self.docView.document().print(thePrinter)
- qApp.restoreOverrideCursor()
- return
-
- def _selectFont(self):
- """Open the QFontDialog and set a font for the font style.
- """
- currFont = QFont()
- currFont.setFamily(self.textFont.text())
- currFont.setPointSize(self.textSize.value())
- theFont, theStatus = QFontDialog.getFont(currFont, self)
- if theStatus:
- self.textFont.setText(theFont.family())
- self.textSize.setValue(theFont.pointSize())
-
- self.raise_() # Move the dialog to front (fixes a bug on macOS)
-
- return
-
- def _generateRootFilter(self):
- """Return a list of all root folders that are filtered out.
- """
- return [h for h, s in self.rootSelection.items() if not s.isChecked()]
-
- def _loadCache(self):
- """Save the current data to cache.
- """
- buildCache = self.theProject.storage.getCacheFile(nwFiles.BUILD_CACHE)
- if not isinstance(buildCache, Path):
- return False
-
- dataCount = 0
- if buildCache.exists():
- logger.debug("Loading build cache")
- try:
- with open(buildCache, mode="r", encoding="utf-8") as inFile:
- theJson = inFile.read()
- theData = json.loads(theJson)
- except Exception:
- logger.error("Failed to load build cache")
- logException()
- return False
-
- if "buildTime" in theData.keys():
- self.buildTime = theData["buildTime"]
- if "htmlStyle" in theData.keys():
- self.htmlStyle = theData["htmlStyle"]
- dataCount += 1
- if "htmlText" in theData.keys():
- self.htmlText = theData["htmlText"]
- dataCount += 1
-
- return dataCount == 2
-
- def _saveCache(self):
- """Save the current data to cache.
- """
- buildCache = self.theProject.storage.getCacheFile(nwFiles.BUILD_CACHE)
- if not isinstance(buildCache, Path):
- return False
-
- logger.debug("Saving build cache")
- try:
- with open(buildCache, mode="w+", encoding="utf-8") as outFile:
- outFile.write(json.dumps({
- "buildTime": self.buildTime,
- "htmlStyle": self.htmlStyle,
- "htmlText": self.htmlText,
- }, indent=2))
- except Exception:
- logger.error("Failed to save build cache")
- logException()
- return False
-
- return True
-
- def _doClose(self):
- """Close button was clicked.
- """
- self.close()
- return
-
- ##
- # Events
- ##
-
- def closeEvent(self, theEvent):
- """Capture the user closing the window so we can save settings.
- """
- self._saveSettings()
- self.docView.clear()
- theEvent.accept()
- return
-
- ##
- # Internal Functions
- ##
-
- def _saveSettings(self):
- """Save the various user settings.
- """
- logger.debug("Saving GuiBuildNovel settings")
-
- # Formatting
- self.theProject.data.setTitleFormat({
- "title": self.fmtTitle.text().strip(),
- "chapter": self.fmtChapter.text().strip(),
- "unnumbered": self.fmtUnnumbered.text().strip(),
- "scene": self.fmtScene.text().strip(),
- "section": self.fmtSection.text().strip(),
- })
-
- buildLang = self.buildLang.currentData()
- hideScene = self.hideScene.isChecked()
- hideSection = self.hideSection.isChecked()
- winWidth = CONFIG.rpxInt(self.width())
- winHeight = CONFIG.rpxInt(self.height())
- justifyText = self.justifyText.isChecked()
- noStyling = self.noStyling.isChecked()
- textFont = self.textFont.text()
- textSize = self.textSize.value()
- lineHeight = self.lineHeight.value()
- novelFiles = self.novelFiles.isChecked()
- noteFiles = self.noteFiles.isChecked()
- ignoreFlag = self.ignoreFlag.isChecked()
- incSynopsis = self.includeSynopsis.isChecked()
- incComments = self.includeComments.isChecked()
- incKeywords = self.includeKeywords.isChecked()
- incBodyText = self.includeBody.isChecked()
- replaceTabs = self.replaceTabs.isChecked()
- replaceUCode = self.replaceUCode.isChecked()
- rootFilter = self._generateRootFilter()
-
- mainSplit = self.mainSplit.sizes()
- boxWidth = CONFIG.rpxInt(mainSplit[0])
- docWidth = CONFIG.rpxInt(mainSplit[1])
-
- self.theProject.setProjectLang(buildLang)
-
- # GUI Settings
- pOptions = self.theProject.options
- pOptions.setValue("GuiBuildNovel", "hideScene", hideScene)
- pOptions.setValue("GuiBuildNovel", "hideSection", hideSection)
- pOptions.setValue("GuiBuildNovel", "winWidth", winWidth)
- pOptions.setValue("GuiBuildNovel", "winHeight", winHeight)
- pOptions.setValue("GuiBuildNovel", "boxWidth", boxWidth)
- pOptions.setValue("GuiBuildNovel", "docWidth", docWidth)
- pOptions.setValue("GuiBuildNovel", "justifyText", justifyText)
- pOptions.setValue("GuiBuildNovel", "noStyling", noStyling)
- pOptions.setValue("GuiBuildNovel", "textFont", textFont)
- pOptions.setValue("GuiBuildNovel", "textSize", textSize)
- pOptions.setValue("GuiBuildNovel", "lineHeight", lineHeight)
- pOptions.setValue("GuiBuildNovel", "addNovel", novelFiles)
- pOptions.setValue("GuiBuildNovel", "addNotes", noteFiles)
- pOptions.setValue("GuiBuildNovel", "ignoreFlag", ignoreFlag)
- pOptions.setValue("GuiBuildNovel", "incSynopsis", incSynopsis)
- pOptions.setValue("GuiBuildNovel", "incComments", incComments)
- pOptions.setValue("GuiBuildNovel", "incKeywords", incKeywords)
- pOptions.setValue("GuiBuildNovel", "incBodyText", incBodyText)
- pOptions.setValue("GuiBuildNovel", "replaceTabs", replaceTabs)
- pOptions.setValue("GuiBuildNovel", "replaceUCode", replaceUCode)
- pOptions.setValue("GuiBuildNovel", "rootFilter", rootFilter)
- pOptions.saveSettings()
-
- return
-
- def _reFmtCodes(self, theFormat):
- """Translates old formatting codes to new ones.
- """
- theFormat = theFormat.replace(r"%chnum%", r"%ch%")
- theFormat = theFormat.replace(r"%scnum%", r"%sc%")
- theFormat = theFormat.replace(r"%scabsnum%", r"%sca%")
- theFormat = theFormat.replace(r"%chnumword%", r"%chw%")
- return theFormat
-
-# END Class GuiBuildNovel
-
-
-class GuiBuildNovelDocView(QTextBrowser):
-
- def __init__(self, mainGui, theProject):
- super().__init__(parent=mainGui)
-
- logger.debug("Initialising GuiBuildNovelDocView ...")
-
- self.theProject = theProject
- self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
- self.buildTime = 0
-
- self.setMinimumWidth(40*self.mainGui.mainTheme.textNWidth)
- self.setOpenExternalLinks(False)
-
- self.document().setDocumentMargin(CONFIG.getTextMargin())
- self.setPlaceholderText(self.tr(
- "This area will show the content of the document to be "
- "exported or printed. Press the \"Build Preview\" button "
- "to generate content."
- ))
-
- theFont = QFont()
- theFont.setFamily(CONFIG.textFont)
- theFont.setPointSize(CONFIG.textSize)
- self.setFont(theFont)
-
- # Set the tab stops
- self.setTabStopDistance(CONFIG.getTabWidth())
-
- docPalette = self.palette()
- docPalette.setColor(QPalette.Base, QColor(255, 255, 255))
- docPalette.setColor(QPalette.Text, QColor(0, 0, 0))
- self.setPalette(docPalette)
-
- lblPalette = self.palette()
- lblPalette.setColor(QPalette.Background, lblPalette.toolTipBase().color())
- lblPalette.setColor(QPalette.Foreground, lblPalette.toolTipText().color())
-
- lblFont = self.font()
- lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
-
- fPx = int(1.1*self.mainTheme.fontPixelSize)
-
- self.theTitle = QLabel("", self)
- self.theTitle.setIndent(0)
- self.theTitle.setAutoFillBackground(True)
- self.theTitle.setAlignment(Qt.AlignCenter)
- self.theTitle.setFixedHeight(fPx)
- self.theTitle.setPalette(lblPalette)
- self.theTitle.setFont(lblFont)
-
- self._updateDocMargins()
- self._updateBuildAge()
- self.setStyleSheet()
-
- # Age Timer
- self.ageTimer = QTimer()
- self.ageTimer.setInterval(10000)
- self.ageTimer.timeout.connect(self._updateBuildAge)
- self.ageTimer.start()
-
- logger.debug("GuiBuildNovelDocView initialisation complete")
-
- return
-
- def setJustify(self, doJustify):
- """Set the justify text option.
- """
- theOpt = self.document().defaultTextOption()
- if doJustify:
- theOpt.setAlignment(Qt.AlignJustify)
- else:
- theOpt.setAlignment(Qt.AlignAbsolute)
- self.document().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, timeStamp):
- """Set the content, either from text or list of text.
- """
- if isinstance(theText, list):
- theText = "".join(theText)
-
- self.buildTime = timeStamp
- sPos = self.verticalScrollBar().value()
- qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
-
- theText = theText.replace("\t", "!!tab!!")
- theText = theText.replace("", "")
- theText = theText.replace("", "")
- self.setHtml(theText)
- qApp.processEvents()
-
- while self.find("!!tab!!"):
- theCursor = self.textCursor()
- theCursor.insertText("\t")
-
- self.verticalScrollBar().setValue(sPos)
- self._updateBuildAge()
-
- # Since we change the content while it may still be rendering, we mark
- # the document dirty again to make sure it's re-rendered properly.
- self.document().markContentsDirty(0, self.document().characterCount())
- qApp.restoreOverrideCursor()
-
- return
-
- def setStyleSheet(self, theStyles=None):
- """Set the stylesheet for the preview document.
- """
- if theStyles is None:
- theStyles = []
-
- if not theStyles:
- theStyles.append("h1, h2 {color: rgb(66, 113, 174);}")
- theStyles.append("h3, h4 {color: rgb(50, 50, 50);}")
- theStyles.append("a {color: rgb(66, 113, 174);}")
- theStyles.append(".tags {color: rgb(245, 135, 31); font-weight: bold;}")
-
- self.document().setDefaultStyleSheet("\n".join(theStyles))
-
- return
-
- def clearStyleSheet(self):
- """Clears the document stylesheet.
- """
- self.document().setDefaultStyleSheet("")
- return
-
- ##
- # Events
- ##
-
- def resizeEvent(self, theEvent):
- """Make sure the document title is the same width as the window.
- """
- super().resizeEvent(theEvent)
- self._updateDocMargins()
- return
-
- ##
- # Internal Functions
- ##
-
- def _updateBuildAge(self):
- """Update the build time and the fuzzy age.
- """
- if self.buildTime > 0:
- strBuildTime = "%s (%s)" % (
- datetime.fromtimestamp(self.buildTime).strftime("%x %X"),
- fuzzyTime(time() - self.buildTime)
- )
- else:
- strBuildTime = self.tr("Unknown")
-
- self.theTitle.setText("%s %s" % (self.tr("Build Time:"), strBuildTime))
-
- return
-
- def _updateDocMargins(self):
- """Automatically adjust the header to fill the top of the
- document within the viewport.
- """
- vBar = self.verticalScrollBar()
- if vBar.isVisible():
- sW = vBar.width()
- else:
- sW = 0
-
- tB = self.frameWidth()
- tW = self.width() - 2*tB - sW
- tH = self.theTitle.height()
-
- self.theTitle.setGeometry(tB, tB, tW, tH)
- self.setViewportMargins(0, tH, 0, 0)
-
- return
-
-# END Class GuiBuildNovelDocView
diff --git a/tests/test_core/test_core_options.py b/tests/test_core/test_core_options.py
index 1a9cf381..ce26dbe1 100644
--- a/tests/test_core/test_core_options.py
+++ b/tests/test_core/test_core_options.py
@@ -32,8 +32,7 @@ from novelwriter.gui.noveltree import NovelTreeColumn
@pytest.mark.core
def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
- """Test loading and saving from the OptionState class.
- """
+ """Test loading and saving from the OptionState class."""
theProject = NWProject(mockGUI)
theOpts = OptionState(theProject)
@@ -43,13 +42,12 @@ def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
# Write a test file
optFile = metaDir / nwFiles.OPTS_FILE
optFile.write_text(json.dumps({
- "GuiBuildNovel": {
- "winWidth": 1000,
- "winHeight": 700,
- "addNovel": True,
- "addNotes": False,
- "textFont": "Cantarell",
- "mockItem": None,
+ "GuiProjectSettings": {
+ "winWidth": 570,
+ "winHeight": 375,
+ "replaceColW": 130,
+ "statusColW": 130,
+ "importColW": 130
},
"MockGroup": {
"mockItem": None,
@@ -76,12 +74,12 @@ def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
# Check that unwanted items have been removed
assert theOpts._theState == {
- "GuiBuildNovel": {
- "winWidth": 1000,
- "winHeight": 700,
- "addNovel": True,
- "addNotes": False,
- "textFont": "Cantarell",
+ "GuiProjectSettings": {
+ "winWidth": 570,
+ "winHeight": 375,
+ "replaceColW": 130,
+ "statusColW": 130,
+ "importColW": 130
},
}
@@ -91,12 +89,12 @@ def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
# Load again to check we get the values back
assert theOpts.loadSettings()
assert theOpts._theState == {
- "GuiBuildNovel": {
- "winWidth": 1000,
- "winHeight": 700,
- "addNovel": True,
- "addNotes": False,
- "textFont": "Cantarell",
+ "GuiProjectSettings": {
+ "winWidth": 570,
+ "winHeight": 375,
+ "replaceColW": 130,
+ "statusColW": 130,
+ "importColW": 130
},
}
@@ -105,8 +103,7 @@ def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
@pytest.mark.core
def testCoreOptions_SetGet(mockGUI):
- """Test setting and getting values from the OptionState class.
- """
+ """Test setting and getting values from the OptionState class."""
theProject = NWProject(mockGUI)
theOpts = OptionState(theProject)
@@ -114,36 +111,33 @@ def testCoreOptions_SetGet(mockGUI):
# Set invalid values
assert theOpts.setValue("MockGroup", "mockItem", None) is False
- assert theOpts.setValue("GuiBuildNovel", "mockItem", None) is False
+ assert theOpts.setValue("GuiProjectSettings", "mockItem", None) is False
# Set valid value
- assert theOpts.setValue("GuiBuildNovel", "winWidth", 100)
+ assert theOpts.setValue("GuiProjectSettings", "winWidth", 100) is True
# Set some values of different types
- assert theOpts.setValue("GuiBuildNovel", "winWidth", 100)
- assert theOpts.setValue("GuiBuildNovel", "winHeight", 12.34)
- assert theOpts.setValue("GuiBuildNovel", "addNovel", True)
- assert theOpts.setValue("GuiBuildNovel", "textFont", "Cantarell")
- assert theOpts.setValue("GuiNovelView", "lastCol", nwColHidden)
+ assert theOpts.setValue("GuiProjectDetails", "winWidth", 100) is True
+ assert theOpts.setValue("GuiProjectDetails", "winHeight", 12.34) is True
+ assert theOpts.setValue("GuiProjectDetails", "clearDouble", True) is True
+ assert theOpts.setValue("GuiNovelView", "lastCol", nwColHidden) is True
# Generic get, doesn't check type
- assert theOpts.getValue("GuiBuildNovel", "winWidth", None) == 100
- assert theOpts.getValue("GuiBuildNovel", "winHeight", None) == 12.34
- assert theOpts.getValue("GuiBuildNovel", "addNovel", None) is True
- assert theOpts.getValue("GuiBuildNovel", "textFont", None) == "Cantarell"
- assert theOpts.getValue("GuiBuildNovel", "mockItem", None) is None
+ assert theOpts.getValue("GuiProjectDetails", "winWidth", None) == 100
+ assert theOpts.getValue("GuiProjectDetails", "winHeight", None) == 12.34
+ assert theOpts.getValue("GuiProjectDetails", "clearDouble", None) is True
+ assert theOpts.getValue("GuiProjectDetails", "mockItem", None) is None
# Get type-specific
- assert theOpts.getString("GuiBuildNovel", "winWidth", None) is None
- assert theOpts.getString("GuiBuildNovel", "mockItem", None) is None
- assert theOpts.getInt("GuiBuildNovel", "winWidth", None) == 100
- assert theOpts.getInt("GuiBuildNovel", "textFont", None) is None
- assert theOpts.getInt("GuiBuildNovel", "mockItem", None) is None
- assert theOpts.getFloat("GuiBuildNovel", "winWidth", None) == 100.0
- assert theOpts.getFloat("GuiBuildNovel", "textFont", None) is None
- assert theOpts.getFloat("GuiBuildNovel", "mockItem", None) is None
- assert theOpts.getBool("GuiBuildNovel", "addNovel", None) is True
- assert theOpts.getBool("GuiBuildNovel", "mockItem", None) is None
+ assert theOpts.getString("GuiProjectDetails", "winWidth", None) is None
+ assert theOpts.getString("GuiProjectDetails", "mockItem", None) is None
+ assert theOpts.getInt("GuiProjectDetails", "winWidth", None) == 100
+ assert theOpts.getInt("GuiProjectDetails", "textFont", None) is None
+ assert theOpts.getInt("GuiProjectDetails", "mockItem", None) is None
+ assert theOpts.getFloat("GuiProjectDetails", "winWidth", None) == 100.0
+ assert theOpts.getFloat("GuiProjectDetails", "mockItem", None) is None
+ assert theOpts.getBool("GuiProjectDetails", "clearDouble", None) is True
+ assert theOpts.getBool("GuiProjectDetails", "mockItem", None) is None
assert theOpts.getEnum("GuiNovelView", "lastCol", NovelTreeColumn, None) == nwColHidden
# Get from non-existent groups
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index f5b9ecc6..7c49585d 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -63,7 +63,7 @@ def testGuiMain_ProjectBlocker(nwGUI):
assert nwGUI.rebuildIndex() is False
assert nwGUI.showProjectSettingsDialog() is False
assert nwGUI.showProjectDetailsDialog() is False
- assert nwGUI.showBuildProjectDialog() is False
+ assert nwGUI.showBuildManuscriptDialog() is False
assert nwGUI.showProjectWordListDialog() is False
assert nwGUI.showWritingStatsDialog() is False
diff --git a/tests/test_tools/test_tools_build.py b/tests/test_tools/test_tools_build.py
deleted file mode 100644
index 798c3dfa..00000000
--- a/tests/test_tools/test_tools_build.py
+++ /dev/null
@@ -1,262 +0,0 @@
-"""
-novelWriter – Build Dialog Class Tester
-=======================================
-
-This file is a part of novelWriter
-Copyright 2018–2023, Veronica Berglyd Olsen
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-"""
-
-import pytest
-
-from shutil import copyfile
-
-from tools import ODT_IGNORE, cmpFiles, getGuiItem
-
-from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import QAction, QFileDialog
-
-from novelwriter import CONFIG
-from novelwriter.tools.build import GuiBuildNovel
-
-
-@pytest.mark.gui
-@pytest.mark.skip
-def testToolBuild_Main(qtbot, monkeypatch, nwGUI, prjLipsum, tstPaths):
- """Test the build tool.
- """
- # Block message box
- monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda a, b, c, **k: (c, None))
-
- # Check that we cannot open when there is no project
- nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
- assert getGuiItem("GuiBuildNovel") is None
-
- # Open a project
- assert nwGUI.openProject(prjLipsum)
-
- # Open the tool
- nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
- qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000)
-
- nwBuild = getGuiItem("GuiBuildNovel")
- assert isinstance(nwBuild, GuiBuildNovel)
-
- nwBuild.textFont.setText("DejaVu Sans")
- nwBuild.textSize.setValue(11)
-
- # Test Save
- # =========
-
- # Invalid file format
- assert not nwBuild._saveDocument(-1)
-
- # No path selected
- with monkeypatch.context() as mp:
- mp.setattr(QFileDialog, "getSaveFileName", lambda *a, **k: ("", ""))
- assert not nwBuild._saveDocument(nwBuild.FMT_NWD)
-
- # Default Settings
- CONFIG._lastPath = prjLipsum
- qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
-
- assert nwBuild._saveDocument(nwBuild.FMT_NWD)
- projFile = prjLipsum / "Lorem Ipsum.nwd"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step1_Lorem_Ipsum.nwd"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step1_Lorem_Ipsum.nwd"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_HTM)
- projFile = prjLipsum / "Lorem Ipsum.htm"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step1_Lorem_Ipsum.htm"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step1_Lorem_Ipsum.htm"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_MD)
- projFile = prjLipsum / "Lorem Ipsum.md"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step1_Lorem_Ipsum.md"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step1_Lorem_Ipsum.md"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_GH)
- projFile = prjLipsum / "Lorem Ipsum.md"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step1G_Lorem_Ipsum.md"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step1G_Lorem_Ipsum.md"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_FODT)
- projFile = prjLipsum / "Lorem Ipsum.fodt"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step1_Lorem_Ipsum.fodt"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step1_Lorem_Ipsum.fodt"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile, ignoreStart=ODT_IGNORE)
-
- # Change Title Formats and Flip Switches
- nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%")
- nwBuild.fmtScene.setText(r"Scene %ch%.%sc%: %title%")
- nwBuild.fmtSection.setText(r"%ch%.%sc%.1: %title%")
-
- qtbot.mouseClick(nwBuild.justifyText, Qt.LeftButton)
- qtbot.mouseClick(nwBuild.includeSynopsis, Qt.LeftButton)
- qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton)
- qtbot.mouseClick(nwBuild.includeKeywords, Qt.LeftButton)
- qtbot.mouseClick(nwBuild.replaceUCode, Qt.LeftButton)
-
- qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton)
- qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton)
-
- qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
-
- assert nwBuild._saveDocument(nwBuild.FMT_NWD)
- projFile = prjLipsum / "Lorem Ipsum.nwd"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step2_Lorem_Ipsum.nwd"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step2_Lorem_Ipsum.nwd"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_HTM)
- projFile = prjLipsum / "Lorem Ipsum.htm"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step2_Lorem_Ipsum.htm"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step2_Lorem_Ipsum.htm"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_MD)
- projFile = prjLipsum / "Lorem Ipsum.md"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step2_Lorem_Ipsum.md"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step2_Lorem_Ipsum.md"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_FODT)
- projFile = prjLipsum / "Lorem Ipsum.fodt"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step2_Lorem_Ipsum.fodt"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step2_Lorem_Ipsum.fodt"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile, ignoreStart=ODT_IGNORE)
-
- # Replace Tabs with Spaces
- qtbot.mouseClick(nwBuild.replaceTabs, Qt.LeftButton)
-
- qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
-
- # Save files that can be compared
- assert nwBuild._saveDocument(nwBuild.FMT_NWD)
- projFile = prjLipsum / "Lorem Ipsum.nwd"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step3_Lorem_Ipsum.nwd"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step3_Lorem_Ipsum.nwd"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_HTM)
- projFile = prjLipsum / "Lorem Ipsum.htm"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step3_Lorem_Ipsum.htm"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step3_Lorem_Ipsum.htm"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_MD)
- projFile = prjLipsum / "Lorem Ipsum.md"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step3_Lorem_Ipsum.md"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step3_Lorem_Ipsum.md"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_FODT)
- projFile = prjLipsum / "Lorem Ipsum.fodt"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step3_Lorem_Ipsum.fodt"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step3_Lorem_Ipsum.fodt"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile, ignoreStart=ODT_IGNORE)
-
- # Putline Mode
- nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%")
- nwBuild.fmtScene.setText(r"Scene %sca%: %title%")
- nwBuild.fmtSection.setText(r"Section: %title%")
-
- qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton)
- qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton)
- qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton)
- qtbot.mouseClick(nwBuild.includeBody, Qt.LeftButton)
-
- qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
-
- # Save files that can be compared
- assert nwBuild._saveDocument(nwBuild.FMT_NWD)
- projFile = prjLipsum / "Lorem Ipsum.nwd"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step4_Lorem_Ipsum.nwd"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step4_Lorem_Ipsum.nwd"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- assert nwBuild._saveDocument(nwBuild.FMT_HTM)
- projFile = prjLipsum / "Lorem Ipsum.htm"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step4_Lorem_Ipsum.htm"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step4_Lorem_Ipsum.htm"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile)
-
- # Check the JSON files too at this stage
- assert nwBuild._saveDocument(nwBuild.FMT_JSON_H)
- projFile = prjLipsum / "Lorem Ipsum.json"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step4H_Lorem_Ipsum.json"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step4H_Lorem_Ipsum.json"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile, [6])
-
- assert nwBuild._saveDocument(nwBuild.FMT_JSON_M)
- projFile = prjLipsum / "Lorem Ipsum.json"
- testFile = tstPaths.outDir / "guiBuild_Tool_Step4M_Lorem_Ipsum.json"
- compFile = tstPaths.refDir / "guiBuild_Tool_Step4M_Lorem_Ipsum.json"
- copyfile(projFile, testFile)
- assert cmpFiles(testFile, compFile, [6])
-
- # Since odt and fodt is built by the same code, we don't check the
- # output. but just that the different format can be written as well
- assert nwBuild._saveDocument(nwBuild.FMT_ODT)
- assert (prjLipsum / "Lorem Ipsum.odt").is_file()
-
- # Print to PDF
- if not CONFIG.osDarwin:
- assert nwBuild._saveDocument(nwBuild.FMT_PDF)
- assert (prjLipsum / "Lorem Ipsum.pdf").is_file()
-
- # Close the build tool
- htmlText = nwBuild.htmlText
- htmlStyle = nwBuild.htmlStyle
- buildTime = nwBuild.buildTime
- nwBuild._doClose()
-
- # Re-open build dialog from cahce
- nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
- qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000)
-
- nwBuild = getGuiItem("GuiBuildNovel")
- assert isinstance(nwBuild, GuiBuildNovel)
-
- assert nwBuild.viewCachedDoc()
- assert nwBuild.htmlText == htmlText
- assert nwBuild.htmlStyle == htmlStyle
- assert nwBuild.buildTime == buildTime
-
- nwBuild._doClose()
-
- # qtbot.stop()
-
-# END Test testToolBuild_Main