From 95c79e1c2304327b99650ef0153e8ad7efe9540b Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Fri, 20 Aug 2021 17:16:14 +0200
Subject: [PATCH] Documentation and ODT exporter updates (#859)
* Clean up a few things in the ODT exporter
* Remove local HTML docs and instead add PDF docs
* Update documentation
---
.gitignore | 2 +
docs/source/conf.py | 61 +++++++--------------
docs/source/index.rst | 39 +++++++-------
docs/source/int_started.rst | 14 ++---
docs/source/tech_storage.rst | 12 ++---
docs/source/tech_tests.rst | 85 ++++++++++++++++++++++++++++++
docs/source/usage_shortcuts.rst | 4 +-
nw/config.py | 11 ++++
nw/core/toodt.py | 36 ++++++++-----
nw/gui/mainmenu.py | 46 ++++++----------
nw/guimain.py | 2 +
setup.py | 75 +++++++++++++++++++-------
tests/test_core/test_core_toodt.py | 6 +--
13 files changed, 255 insertions(+), 138 deletions(-)
create mode 100644 docs/source/tech_tests.rst
diff --git a/.gitignore b/.gitignore
index 1b03d0dd..6645bcf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,8 @@ i18n/*.qph
# Documentation
/docs/build/
/nw/assets/help/html/
+/nw/assets/help/manual.pdf
+/UserManual.pdf
*.qch
*.qhc
diff --git a/docs/source/conf.py b/docs/source/conf.py
index b253da66..99e955bc 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -4,20 +4,15 @@
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config
-
-# -- Path setup --------------------------------------------------------------
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
#
-# import sys
-# sys.path.insert(0, os.path.abspath("."))
+
+# -- Imports -----------------------------------------------------------------
+
import os
import time
-import sphinx_rtd_theme # noqa: F401
+import sphinx_rtd_theme # noqa: F401
-# -- Project information -----------------------------------------------------
+# -- Project Information -----------------------------------------------------
project = "novelWriter"
copyright = "2018–2021, Veronica Berglyd Olsen"
@@ -28,7 +23,7 @@ version = "1.5"
# The full version, including alpha/beta/rc tags
release = "1.5-alpha0"
-# -- General configuration ---------------------------------------------------
+# -- General Configuration ---------------------------------------------------
os.environ["TZ"] = "Europe/Oslo"
time.tzset()
@@ -45,7 +40,7 @@ language = None
exclude_patterns = []
pygments_style = None
-# -- Options for HTML output -------------------------------------------------
+# -- Options for HTML Output -------------------------------------------------
html_theme = "sphinx_rtd_theme"
html_logo = "images/novelwriter.png"
@@ -64,48 +59,32 @@ html_css_files = [
"css/custom.css",
]
-# Custom sidebar templates, must be a dictionary that maps document names
-# to template names.
-# The default sidebars (for documents that don"t match any pattern) are
-# defined by theme itself. Builtin themes are using these templates by
-# default: ``["localtoc.html", "relations.html", "sourcelink.html",
-# "searchbox.html"]``.
-# html_sidebars = {}
-
-# -- Options for HTMLHelp output ---------------------------------------------
+# -- Options for HTMLHelp Output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = "novelWriterDoc"
-# -- Options for LaTeX output ------------------------------------------------
+# -- Options for LaTeX Output ------------------------------------------------
latex_elements = {
- # The paper size ("letterpaper" or "a4paper").
- #
- # "papersize": "letterpaper",
-
- # The font size ("10pt", "11pt" or "12pt").
- #
- # "pointsize": "10pt",
-
- # Additional stuff for the LaTeX preamble.
- #
- # "preamble": "",
-
- # Latex figure (float) alignment
- #
- # "figure_align": "htbp",
+ "papersize": "a4paper",
+ "pointsize": "11pt",
+ "preamble": (
+ "\\usepackage[utf8]{inputenc}\n"
+ "\\DeclareUnicodeCharacter{2212}{\\textendash}\n"
+ ),
+ "figure_align": "htbp",
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [(
- master_doc, "novelWriter.tex", "novelWriter Documentation",
+ master_doc, "manual.tex", "novelWriter Documentation",
author, "manual"
)]
-# -- Options for manual page output ------------------------------------------
+# -- Options for Man Page Output ---------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
@@ -113,7 +92,7 @@ man_pages = [(
master_doc, "novelwriter", "novelWriter Documentation", [author], 1
)]
-# -- Options for Texinfo output ----------------------------------------------
+# -- Options for Texinfo Output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
@@ -123,7 +102,7 @@ texinfo_documents = [(
"novelWriter", "Markdown-like editor for novels.", "Miscellaneous"
)]
-# -- Options for Epub output -------------------------------------------------
+# -- Options for EPub Output -------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 6c0eb7f2..1a0401f0 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -2,29 +2,31 @@
novelWriter |release|
#####################
-.. image:: https://github.com/vkbo/novelWriter/workflows/python%203.8/badge.svg?branch=main
- :target: https://github.com/vkbo/novelWriter/actions
- :alt: Python Tests
+.. only:: html
-.. image:: https://codecov.io/gh/vkbo/novelWriter/branch/main/graph/badge.svg
- :target: https://codecov.io/gh/vkbo/novelWriter
- :alt: Code Coverage
+ .. image:: https://github.com/vkbo/novelWriter/workflows/python%203.8/badge.svg?branch=main
+ :target: https://github.com/vkbo/novelWriter/actions
+ :alt: Python Tests
-.. image:: https://readthedocs.org/projects/novelwriter/badge/?version=latest
- :target: https://novelwriter.readthedocs.io/en/latest/?badge=latest
- :alt: Documentation
+ .. image:: https://codecov.io/gh/vkbo/novelWriter/branch/main/graph/badge.svg
+ :target: https://codecov.io/gh/vkbo/novelWriter
+ :alt: Code Coverage
-.. image:: https://img.shields.io/github/v/release/vkbo/novelwriter
- :target: https://github.com/vkbo/novelWriter/releases
- :alt: GitHub Release
+ .. image:: https://readthedocs.org/projects/novelwriter/badge/?version=latest
+ :target: https://novelwriter.readthedocs.io/en/latest/?badge=latest
+ :alt: Documentation
-.. image:: https://img.shields.io/pypi/v/novelwriter
- :target: https://pypi.org/project/novelWriter/
- :alt: PyPI
+ .. image:: https://img.shields.io/github/v/release/vkbo/novelwriter
+ :target: https://github.com/vkbo/novelWriter/releases
+ :alt: GitHub Release
-.. image:: https://img.shields.io/pypi/pyversions/novelwriter
- :target: https://pypi.org/project/novelWriter/
- :alt: Python Version
+ .. image:: https://img.shields.io/pypi/v/novelwriter
+ :target: https://pypi.org/project/novelWriter/
+ :alt: PyPI
+
+ .. image:: https://img.shields.io/pypi/pyversions/novelwriter
+ :target: https://pypi.org/project/novelWriter/
+ :alt: Python Version
**Last Updated:** |today|
@@ -101,6 +103,7 @@ for your operating system for further details.
:caption: Under the Hood
tech_storage
+ tech_tests
Indices and Tables
diff --git a/docs/source/int_started.rst b/docs/source/int_started.rst
index 51384019..51a3f67e 100644
--- a/docs/source/int_started.rst
+++ b/docs/source/int_started.rst
@@ -157,13 +157,15 @@ The documentation can then be built from the ``docs`` folder in the source code
If successful, the documentation should be available in the ``docs/build/html`` folder and you can
open the ``index.html`` file in your browser.
-You can also build the documentation by using the setup script:
+You can also build the PDF documentation locally using the setup script:
.. code-block:: console
- python setup.py docs
+ python setup.py pdfdocs
-This does the same as the ``make help`` command, but in addition it copies the documentation into
-novelWriter's assets folder. This will make it possible to open the documentation from inside of
-novelWriter by pressing :kbd:`F1` even without an internet connection, as it will instead open the
-local copy.
+This will build the documentation as a PDF using LaTeX. The file will then be copied into the
+assets folder and made available in the :guilabel:`Help` menu in novelWriter. The Sphinx build
+system has a few extra dependencies when building the PDF. Please check the `Sphinx Docs`_ if you
+have any issues.
+
+.. _Sphinx Docs: https://www.sphinx-doc.org/
diff --git a/docs/source/tech_storage.rst b/docs/source/tech_storage.rst
index a279706d..c06aff2e 100644
--- a/docs/source/tech_storage.rst
+++ b/docs/source/tech_storage.rst
@@ -35,9 +35,9 @@ your own backup solution.
extensions `.json` as JSON files are used to cache the index and various run-time settings and
are generally large files that change often. You'd also want to exclude the ``cache`` folder.
-The project XML file is indent-formatted, suitable for diff tools and version control since most of
-the file will stay static, although a timesetamp is set in the meta section on line 2, and various
-meta data entries incremented, on each save.
+The project XML file is indent-formatted, and is suitable for diff tools and version control since
+most of the file will stay static, although a timesetamp is set in the meta section on line 2, and
+various meta data entries incremented, on each save.
Project Documents
@@ -45,7 +45,7 @@ Project Documents
All the project documents are saved in a folder in the main project folder named ``content``. Each
document has a file handle taken from the first 13 characters of a SHA256 hash of the system time
-plus an incremented number when the document was first created. The documents are saved with a
+when the document was first created, plus an incremented number. The documents are saved with a
filename assembled from this hash and the file extension ``.nwd``.
If you wish to find the file system location of a document in the project, you can either look it
@@ -60,7 +60,7 @@ what the user names the document within the project, or changes it to.
Each document file contains a plain text version of the text from the editor. The file can in
principle be edited in any text editor, and is suitable for diffing and version control if so
-desired. Just make sure the file remains in utf-8 encoding, otherwise unicode chatracters may
+desired. Just make sure the file remains in utf-8 encoding, otherwise unicode characters may
become mangled when the file is opened in novelWriter again.
Editing these files is generally not recommended outside of special circumstances, whatever they
@@ -115,7 +115,7 @@ project, and the word counts within each header section.
The integrity of the index is checked when the file is loaded. It is possible to corrupt the index
if the file is manually edited and manipulated, so the check is important to avoid sudden crashes
-of novelWriter. if the file contains errors, novelWriter will automatically build it anew. If the
+of novelWriter. If the file contains errors, novelWriter will automatically build it anew. If the
check somehow fails and novelWriter keeps crashing, you can delete the file manually and rebuild
the index. If this too fails, you have likely encountered a bug.
diff --git a/docs/source/tech_tests.rst b/docs/source/tech_tests.rst
new file mode 100644
index 00000000..5fe24149
--- /dev/null
+++ b/docs/source/tech_tests.rst
@@ -0,0 +1,85 @@
+.. _a_pytest:
+
+*************
+Running Tests
+*************
+
+The novelWriter source code is well covered by tests. The test framework used for the development
+is ``pytest`` with the use of an extension for Qt.
+
+
+Dependencies
+============
+
+The dependencies for running the tests can be installed with:
+
+.. code-block:: console
+
+ pip install -r requirements-dev.txt
+
+This will install a couple of extra packages for coverage and test management. The minimum
+requirement is just ``pytest`` and ``pytest-qt``.
+
+
+Simple Test Run
+===============
+
+To run the tests, you simply need to execute the following from the root of the source folder:
+
+.. code-block:: console
+
+ pytest
+
+Since several of the tests involve opening up the novelWriter GUI, you may want to disable the GUI
+for the duration of the test run. Moving your mouse while the tests are running may otherwise
+interfere with the execution of some tests.
+
+You can disable the renderring of the GUI by setting the flag ``export QT_QPA_PLATFORM=offscreen``,
+or alternatively run the tests with the ``xvfb`` package, like so:
+
+.. code-block:: console
+
+ xvfb-run pytest
+
+
+Advanced Options
+================
+
+Adding the flag ``-v`` to the ``pytest`` command will increase verbosity of the test execution.
+
+You can also add coverage report generation. For instance to HTML:
+
+.. code-block:: console
+
+ xvfb-run pytest -v --cov=nw --cov-report=html
+
+Other useful report formats are ``xml``, and ``term`` for terminal output.
+
+You can also run tests per subpackage of novelWriter with the ``-m`` command. The available
+subpackage groups are ``base``, ``core``, and ``gui``. Consider for instance:
+
+.. code-block:: console
+
+ xvfb-run pytest -v --cov=nw --cov-report=html -m core
+
+This will only run the tests of the "core" package, that is, all the classes that deal with the
+project data of a novelWriter project. The "gui" tests, likewise, will run the tests for the GUI
+components, and the "base" tests cover the bits in-between.
+
+You can also filter the tests with the ``-k`` switch. The following will do the same as
+``-m core``:
+
+.. code-block:: console
+
+ xvfb-run pytest -v --cov=nw --cov-report=html -k testCore
+
+All tests are named in such a way that you can filter them by adding more bits of the test names.
+They all start with the word "test". Then comes the group: "Core", "Base", "Dlg", "Tool", or "Gui".
+Finally comes the name of the class or module, which generally corresponds to a single source code
+file. For instance, running the following will run all tests for the document editor:
+
+.. code-block:: console
+
+ xvfb-run pytest -v --cov=nw --cov-report=html -k testGuiEditor
+
+To run a single test, simply add the full test name to the ``-k`` switch.
diff --git a/docs/source/usage_shortcuts.rst b/docs/source/usage_shortcuts.rst
index 6c92c350..7a06e26a 100644
--- a/docs/source/usage_shortcuts.rst
+++ b/docs/source/usage_shortcuts.rst
@@ -80,7 +80,7 @@ The main shorcuts are as follows:
":kbd:`Ctrl`:kbd:`Shift`:kbd:`W`", "Close the current project."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`Z`", "Undo move of project tree item."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`Del`", "If in the project tree, move a document to trash, or delete a folder."
- ":kbd:`F1`", "Open the documentation. This will either open the Qt Assistant, if available, or send you to the documentation website."
+ ":kbd:`F1`", "Open the online user manual."
":kbd:`F2`", "If in the project tree, edit a document or folder settings. (Same as :kbd:`Ctrl`:kbd:`E`)"
":kbd:`F3`", "Find next occurrence of search word in current document. (Same as :kbd:`Ctrl`:kbd:`G`)"
":kbd:`F5`", "Open the :guilabel:`Build Novel Project` dialog."
@@ -90,7 +90,7 @@ The main shorcuts are as follows:
":kbd:`F9`", "Re-build the project index."
":kbd:`F10`", "Re-build the project outline."
":kbd:`F11`", "Activate full screen mode."
- ":kbd:`Shift`:kbd:`F1`", "Open the online documentation in the system default browser."
+ ":kbd:`Shift`:kbd:`F1`", "Open the local user manual (PDF) if it is available."
":kbd:`Shift`:kbd:`F3`", "Find previous occurrence of search word in current document. (Same as :kbd:`Ctrl`:kbd:`Shift`:kbd:`G`.)"
":kbd:`Shift`:kbd:`F6`", "Open the :guilabel:`Project Details` dialog."
":kbd:`Return`", "If in the project tree, open a document for editing."
diff --git a/nw/config.py b/nw/config.py
index 031449fe..5d49ecd0 100644
--- a/nw/config.py
+++ b/nw/config.py
@@ -71,6 +71,7 @@ class Config:
self.themeRoot = None # The full path to the nw/assets/themes folder
self.dictPath = None # The full path to the nw/assets/dict folder
self.iconPath = None # The full path to the nw/assets/icons folder
+ self.pdfDocs = None # The location of the PDF manual, if it exists
# Runtime Settings and Variables
self.confChanged = False # True whenever the config has chenged, false after save
@@ -356,6 +357,16 @@ class Config:
if self.spellLanguage is None:
self.spellLanguage = "en"
+ # Look for a PDF version of the manual
+ lookIn = [
+ os.path.join(self.assetPath, "help", "manual.pdf"),
+ os.path.join(self.appRoot, "UserManual.pdf"),
+ ]
+ for pdfDocs in lookIn:
+ if os.path.isfile(pdfDocs):
+ self.pdfDocs = pdfDocs
+ break
+
logger.debug("Config initialisation complete")
return True
diff --git a/nw/core/toodt.py b/nw/core/toodt.py
index 69dac848..152d2889 100644
--- a/nw/core/toodt.py
+++ b/nw/core/toodt.py
@@ -107,7 +107,7 @@ class ToOdt(Tokenizer):
self.headerText = ""
# Internal
- self._fontFamily = "'Liberation Sans'"
+ self._fontFamily = "'Liberation Serif'"
self._fontPitch = "variable"
self._fSizeTitle = "30pt"
self._fSizeHead1 = "24pt"
@@ -239,6 +239,9 @@ class ToOdt(Tokenizer):
self._blockIndent = self._emToCm(self.blockIndent)
self._textAlign = "justify" if self.doJustify else "left"
+ # Clear Errors
+ self._errData = []
+
# Document Header
# ===============
@@ -546,8 +549,8 @@ class ToOdt(Tokenizer):
rFmt += "_B%s b_ " % (" "*len(tText))
if len(theBits) > 1:
if theBits[0] == nwKeyWords.TAG_KEY:
- rTxt += "%s" % theBits[1]
- rFmt += "%s" % (" "*len(theBits[1]))
+ rTxt += theBits[1]
+ rFmt += " "*len(theBits[1])
else:
tTags = ", ".join(theBits[1:])
rTxt += tTags
@@ -585,12 +588,15 @@ class ToOdt(Tokenizer):
tTemp = ""
xFmt = 0x00
pFmt = 0x00
+ pErr = 0
parProc = XMLParagraph(xElem)
for i, c in enumerate(theText):
- if theFmt[i] == "_":
+ if theFmt[i] == " ":
+ tTemp += c
+ elif theFmt[i] == "_":
continue
elif theFmt[i] == "B":
xFmt |= X_BLD
@@ -604,9 +610,8 @@ class ToOdt(Tokenizer):
xFmt |= X_DEL
elif theFmt[i] == "s":
xFmt &= M_DEL
-
- if theFmt[i] == " ":
- tTemp += c
+ else:
+ pErr += 1
if xFmt != pFmt:
if pFmt == 0x00:
@@ -624,6 +629,9 @@ class ToOdt(Tokenizer):
else:
parProc.appendSpan(tTemp, self._textStyle(pFmt))
+ if pErr > 0:
+ self._errData.append("Unknown format tag encountered")
+
nErr, errMsg = parProc.checkError()
if nErr > 0: # pragma: no cover
# This one should only capture bugs
@@ -652,23 +660,23 @@ class ToOdt(Tokenizer):
return newName
- def _textStyle(self, styleCode):
+ def _textStyle(self, tFmt):
"""Return a text style for a given style code.
"""
- if styleCode in self._autoText:
- return self._autoText[styleCode][0]
+ if tFmt in self._autoText:
+ return self._autoText[tFmt][0]
newName = "T%d" % (len(self._autoText) + 1)
newStyle = ODTTextStyle()
- if styleCode & X_BLD:
+ if tFmt & X_BLD:
newStyle.setFontWeight("bold")
- if styleCode & X_ITA:
+ if tFmt & X_ITA:
newStyle.setFontStyle("italic")
- if styleCode & X_DEL:
+ if tFmt & X_DEL:
newStyle.setStrikeStyle("solid")
newStyle.setStrikeType("single")
- self._autoText[styleCode] = (newName, newStyle)
+ self._autoText[tFmt] = (newName, newStyle)
return newName
diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py
index c80ffa46..0c3dc5e5 100644
--- a/nw/gui/mainmenu.py
+++ b/nw/gui/mainmenu.py
@@ -23,11 +23,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import nw
import logging
-from http.client import HTTPSConnection
from urllib.parse import urljoin
from urllib.request import pathname2url
@@ -137,31 +135,13 @@ class GuiMainMenu(QMenuBar):
QDesktopServices.openUrl(QUrl(theUrl))
return True
- def _openDocumentation(self):
- """Open the documentation, and select whether it should be the
- stable or latest version. If no internet connection, open
- local.
+ def _openUserManualFile(self):
+ """Open the documentation in PDF format.
"""
- if nw.__hexversion__[-2] == "f":
- docsPath = "/en/stable/"
- else:
- docsPath = "/en/latest/"
-
- try:
- conn = HTTPSConnection(nw.__docurl__.replace("https://", ""))
- conn.request("HEAD", docsPath)
- resp = conn.getresponse()
- hasAccess = resp.code == 200
- except Exception:
- hasAccess = False
-
- docsFile = os.path.join(self.mainConf.assetPath, "help", "html", "index.html")
- if hasAccess or not os.path.isfile(docsFile):
- self._openWebsite(nw.__docurl__ + docsPath)
- else:
- self._openWebsite(urljoin("file:", pathname2url(docsFile)))
-
- return
+ if self.mainConf.pdfDocs is None:
+ return False
+ QDesktopServices.openUrl(QUrl(urljoin("file:", pathname2url(self.mainConf.pdfDocs))))
+ return True
##
# Menu Builders
@@ -1106,13 +1086,21 @@ class GuiMainMenu(QMenuBar):
# Help > Separator
self.helpMenu.addSeparator()
- # Help > Documentation
- self.aHelpDocs = QAction(self.tr("Documentation"), self)
+ # Help > User Manual (Online)
+ self.aHelpDocs = QAction(self.tr("User Manual (Online)"), self)
self.aHelpDocs.setStatusTip(self.tr("Open documentation in browser"))
- self.aHelpDocs.triggered.connect(self._openDocumentation)
self.aHelpDocs.setShortcut("F1")
+ self.aHelpDocs.triggered.connect(lambda: self._openWebsite(nw.__docurl__))
self.helpMenu.addAction(self.aHelpDocs)
+ # Help > User Manual (PDF)
+ if self.mainConf.pdfDocs is not None:
+ self.aPdfDocs = QAction(self.tr("User Manual (PDF)"), self)
+ self.aPdfDocs.setStatusTip(self.tr("Open PDF documentation"))
+ self.aPdfDocs.setShortcut("Shift+F1")
+ self.aPdfDocs.triggered.connect(self._openUserManualFile)
+ self.helpMenu.addAction(self.aPdfDocs)
+
# Help > Separator
self.helpMenu.addSeparator()
diff --git a/nw/guimain.py b/nw/guimain.py
index add555f4..61422a2d 100644
--- a/nw/guimain.py
+++ b/nw/guimain.py
@@ -1373,6 +1373,8 @@ class GuiMain(QMainWindow):
# Help
self.addAction(self.mainMenu.aHelpDocs)
+ if self.mainConf.pdfDocs is not None:
+ self.addAction(self.mainMenu.aPdfDocs)
return True
diff --git a/setup.py b/setup.py
index 590c0f4a..a2345f61 100755
--- a/setup.py
+++ b/setup.py
@@ -222,35 +222,51 @@ def buildQtDocs():
##
-# Html Documentation Builder (docs)
+# Html or PDF Documentation Builder (docs, docs_pdf)
##
-def buildHtmlDocs():
- """This function will build the Sphinx HTML documentation. The files
- are then copied into the nw/assets/help/html directory and can be
- included in builds.
+def buildLocalDocs(bldFmt="HTML"):
+ """This function will build the Sphinx HTML or PDF documentation.
+ For HTML, the files are then copied into the nw/assets/help/html
+ directory and can be included in builds.
"""
- buildDir = os.path.join("docs", "build", "html")
- helpDir = os.path.join("nw", "assets", "help", "html")
-
print("")
print("Building Documentation")
print("======================")
+ print("Format: %s" % bldFmt)
print("")
+ if bldFmt == "HTML":
+ buildDir = os.path.join("docs", "build", "html")
+ elif bldFmt == "PDF":
+ buildDir = os.path.join("docs", "build", "latex")
+ else:
+ print("Docs Build Error:")
+ return
+
buildFail = False
try:
subprocess.call(["make", "-C", "docs", "clean"])
- subprocess.call(["make", "-C", "docs", "html"])
+ if bldFmt == "HTML":
+ subprocess.call(["make", "-C", "docs", "html"])
+ elif bldFmt == "PDF":
+ subprocess.call(["make", "-C", "docs", "latexpdf"])
except Exception as e:
print("Docs Build Error:")
print(str(e))
buildFail = True
try:
- if os.path.isdir(helpDir):
- shutil.rmtree(helpDir)
- shutil.copytree(buildDir, helpDir)
+ if bldFmt == "HTML":
+ helpDir = os.path.join("nw", "assets", "help", "html")
+ if os.path.isdir(helpDir):
+ shutil.rmtree(helpDir)
+ shutil.copytree(buildDir, helpDir)
+ elif bldFmt == "PDF":
+ os.rename(
+ os.path.join(buildDir, "manual.pdf"),
+ os.path.join("nw", "assets", "help", "manual.pdf")
+ )
except Exception as e:
print("Docs Build Error:")
print(str(e))
@@ -262,7 +278,11 @@ def buildHtmlDocs():
print("")
print("Dependencies:")
print(" * pip install sphinx")
- print(" * pip install sphinx-rtd-theme")
+ if bldFmt == "HTML":
+ print(" * pip install sphinx-rtd-theme")
+ elif bldFmt == "PDF":
+ print(" * Package latexmk")
+ print(" * LaTeX build system")
sys.exit(1)
else:
print("Documentation build: OK")
@@ -401,7 +421,7 @@ def makeMinimalPackage(targetOS):
# Build docs
try:
- buildHtmlDocs()
+ buildLocalDocs(bldFmt="PDF")
except Exception as e:
print("Failed with error:")
print(str(e))
@@ -440,7 +460,19 @@ def makeMinimalPackage(targetOS):
if os.path.isfile(outFile):
os.unlink(outFile)
- rootFiles = ["LICENSE.md", "README.md", "CHANGELOG.md", "requirements.txt", "setup.py"]
+ # Add the manual also to the root
+ pdfDocs = os.path.join("nw", "assets", "help", "manual.pdf")
+ if os.path.isfile(pdfDocs):
+ os.rename(pdfDocs, "UserManual.pdf")
+
+ rootFiles = [
+ "CHANGELOG.md",
+ "LICENSE.md",
+ "README.md",
+ "requirements.txt",
+ "setup.py",
+ "UserManual.pdf",
+ ]
with ZipFile(outFile, "w", compression=ZIP_DEFLATED, compresslevel=9) as zipObj:
@@ -1195,7 +1227,8 @@ if __name__ == "__main__":
"",
"Additional Builds:",
"",
- " docs Build the help documentation as HTML."
+ " htmldocs Build the help documentation as HTML.",
+ " pdfdocs Build the help documentation as PDF (requires LaTeX).",
" qthelp Build the help documentation for use with the Qt Assistant.",
" qtlupdate Update the translation files for internationalisation.",
" qtlrelease Build the language files for internationalisation.",
@@ -1262,9 +1295,13 @@ if __name__ == "__main__":
# Additional Builds
# =================
- if "docs" in sys.argv:
- sys.argv.remove("docs")
- buildHtmlDocs()
+ if "htmldocs" in sys.argv:
+ sys.argv.remove("htmldocs")
+ buildLocalDocs(bldFmt="HTML")
+
+ if "pdfdocs" in sys.argv:
+ sys.argv.remove("pdfdocs")
+ buildLocalDocs(bldFmt="PDF")
if "qthelp" in sys.argv:
sys.argv.remove("qthelp")
diff --git a/tests/test_core/test_core_toodt.py b/tests/test_core/test_core_toodt.py
index fd6f1c0b..f9c551e3 100644
--- a/tests/test_core/test_core_toodt.py
+++ b/tests/test_core/test_core_toodt.py
@@ -199,10 +199,10 @@ def testCoreToOdt_TextFormatting(mockGUI):
# Incorrectly Formatted Text
theDoc.initDocument()
- theTxt = "A **few** _words"
- theFmt = " _b b_ I "
+ theTxt = "A **few** _wordsXXX"
+ theFmt = " _b b_ I XXX"
theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt)
- assert theDoc.getErrors() == []
+ assert theDoc.getErrors() == ["Unknown format tag encountered"]
assert xmlToText(theDoc._xText) == (
""
""