Merge branch 'dev' into project_details
This commit is contained in:
@@ -71,16 +71,16 @@ needed are `pyqt5`, `lxml` and `pyenchant`.
|
||||
|
||||
You can also install novelWriter from source with:
|
||||
```bash
|
||||
python3 setup.py sample
|
||||
sudo python3 setup.py install
|
||||
sudo python3 setup.py launcher
|
||||
python setup.py sample
|
||||
sudo python setup.py install
|
||||
sudo python setup.py xdg-install
|
||||
```
|
||||
|
||||
The last line will install the application icons and set up a launcher for novelWriter. The method
|
||||
uses hardcoded paths, so it may or may not work for your Linux distro. If you have any issues,
|
||||
please submit a ticket so the script can be tuned.
|
||||
The last line will install the application icons and set up a launcher for novelWriter. The script
|
||||
may prompt you to choose which executable to configure if it finds more than one.
|
||||
|
||||
The script may prompt you to choose which executable to configure if it finds more than one.
|
||||
**Note:** If your distro has multiple versions of Python installed, you may need to use the
|
||||
`python3` command instead of `python`.
|
||||
|
||||
### Running from Source
|
||||
|
||||
@@ -162,7 +162,8 @@ particularly useful for increasing logging output for debugging.
|
||||
|
||||
# Key Features
|
||||
|
||||
Some features of novelWriter are listed below. Consult the documentation for more information.
|
||||
Some features of novelWriter are listed below. Consult the
|
||||
[documentation](https://novelwriter.readthedocs.io/) for more information.
|
||||
|
||||
### Markdown Flavour
|
||||
|
||||
@@ -170,7 +171,7 @@ novelWriter is _not_ a full-feature Markdown editor. It allows for a minimal set
|
||||
needed for writing text documents for novels. These are currently limited to:
|
||||
|
||||
* Headings level 1 to 4 using the `#` syntax only.
|
||||
* Emphasised and strong text. These are rendered as italicised and bold.
|
||||
* Emphasised and strongly emphasised text. These are rendered as italicised and bold text.
|
||||
* Strikethrough text.
|
||||
* Hard line breaks using two or more spaces at the end of a line.
|
||||
|
||||
|
||||
+180
-130
@@ -7,105 +7,65 @@ Getting Started
|
||||
This is a brief guide to how you can get novelWriter running on your computer. These are the
|
||||
methods currently supported by the developer. Packages may also be available in other package
|
||||
managers, but those are not managed by the developer. A Windows installer file is also provided on
|
||||
the GitHub page and main website.
|
||||
the GitHub page and on the main website.
|
||||
|
||||
As novelWriter matures, more options for how to install it and get it running will be added. For
|
||||
non-Windows users the install process is at the present time best suited for people used to working
|
||||
with the command line.
|
||||
with the command line. But even if you're not, the install process is fairly straight forward.
|
||||
|
||||
.. note::
|
||||
The text below assumes the command ``python`` corresponds to a Python 3 executable. For
|
||||
operating systems with both Python 2 and 3, the command ``python3`` may be needed instead. On
|
||||
Linux, the scripts can also be made executable and run without the ``python`` command.
|
||||
Linux, the scripts can also be made executable and run without the ``python`` command. Likewise,
|
||||
``pip`` may need to be replaced with ``pip3``.
|
||||
|
||||
|
||||
.. _a_started_install:
|
||||
|
||||
Installation
|
||||
============
|
||||
Installing and Running
|
||||
======================
|
||||
|
||||
You can download the latest version of novelWriter from the source repository on GitHub_. You can
|
||||
also install it directly from PyPi with ``pip install novelwriter``, or download the packages
|
||||
directly from the PyPi_ project page.
|
||||
The application is written in Python 3 using Qt5 via PyQt5. It is developed on Linux, but it should
|
||||
in principle work fine on other operating systems as well as long as dependencies are met.
|
||||
|
||||
Latest version of novelWriter is |release|.
|
||||
You can download the latest version of novelWriter from the source repository on GitHub_.
|
||||
novelWriter is also hosted on PyPi_, and can be installed on all operating systems that support Qt5
|
||||
and Python 3. It is regularly tested on Linux, Windows and macOS.
|
||||
|
||||
To install from PyPi you must first have the ``python`` and ``pip`` commands available on your
|
||||
system. If you don't, see specific instructions for your operating system later in this document.
|
||||
To install novelWriter from PyPi, use the following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install novelwriter
|
||||
|
||||
To upgrade an existing installation, use:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install --upgrade novelwriter
|
||||
|
||||
The latest version of novelWriter is |release|.
|
||||
|
||||
.. _GitHub: https://github.com/vkbo/novelWriter/releases
|
||||
.. _PyPi: https://pypi.org/project/novelWriter/
|
||||
|
||||
|
||||
.. _a_started_install_win:
|
||||
|
||||
Windows Installer
|
||||
-----------------
|
||||
|
||||
You can run novelWriter directly from source on Windows, but a Windows installer is also provided
|
||||
for 64-bit Windows on the `main website`_ and GitHub_ page. This installer bundles all that is
|
||||
needed for novelWriter to run, including Python and the xml and Qt libraries.
|
||||
|
||||
.. _main website: https://novelwriter.io
|
||||
|
||||
|
||||
.. _a_started_install_source:
|
||||
|
||||
Install from Source on Linux
|
||||
----------------------------
|
||||
|
||||
For Linux systems, novelWriter can be installed from source with the provided ``setup.py`` script.
|
||||
To install novelWriter into the system's default Python install locations, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python setup.py install
|
||||
|
||||
To set up the novelWriter desktop launcher, the icons and the project file association, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python setup.py xdg-install
|
||||
|
||||
By default, these commands installs novelWriter and its icons for the current user only. To install
|
||||
for all users, run the script with the ``sudo`` command. Other options are also available. Run
|
||||
``python setup.py help`` for a full list of install options.
|
||||
|
||||
|
||||
.. _a_started_depend:
|
||||
|
||||
Dependencies
|
||||
============
|
||||
Python Dependencies
|
||||
-------------------
|
||||
|
||||
novelWriter has been designed to rely on as few dependencies as possible. Aside from the package(s)
|
||||
needed to communicate with the Qt GUI libraries, only one package is required for handling the XML
|
||||
format of the main project file. Everything else is handled with standard Python libraries.
|
||||
|
||||
Optionally, a package can be installed to interface with the Enchant spell checking libaries, but
|
||||
this isn't strictly required. If no external spell checking library is available, novelWriter falls
|
||||
back to using the internal ``difflib`` of Python to check spelling. This is a much slower approach,
|
||||
and it is less sophisticated than full spell checking libaries, but if you only work with small
|
||||
files, the performance loss is not noticeable.
|
||||
The following Python packages are needed to run novelWriter:
|
||||
|
||||
|
||||
.. _a_started_depend_packages:
|
||||
|
||||
Package Installation
|
||||
--------------------
|
||||
|
||||
If you already have Python installed, all you need to do is install the dependencies. To do this,
|
||||
you need to open your command line tool, find the folder where you extracted novelWriter, and run
|
||||
the following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
This will install all the dependencies and recommended packages.
|
||||
|
||||
The following Python packages are required to run novelWriter:
|
||||
|
||||
* ``pyqt5``, needed for connecting with the Qt5 libraries.
|
||||
* ``lxml``, needed full XML support.
|
||||
|
||||
You can of course also install these packages from your operating system's package repository.
|
||||
* ``pyqt5`` – needed for connecting with the Qt5 libraries.
|
||||
* ``lxml`` – needed for full XML support.
|
||||
* ``pyenchant`` – needed for efficient spell checking (optional).
|
||||
|
||||
PyQt/Qt should be at least 5.2.1, but ideally 5.10 or higher for nearly all features to work.
|
||||
Exporting to standard Markdown, for instance, requires PyQt/Qt 5.14. Searching using regular
|
||||
@@ -113,18 +73,158 @@ expressions requires 5.3, and for full Unicode support, 5.13. There is no known
|
||||
requirement for package ``lxml``, but the code was originally written with 4.2, which is therefore
|
||||
set as the minimum. It may work on lower versions. You have to test it.
|
||||
|
||||
The spell checking extension is optional, but recommended:
|
||||
Optionally, a package can be installed to interface with the Enchant spell checking libaries, but
|
||||
this isn't strictly required. If no external spell checking library is available, novelWriter falls
|
||||
back to using the internal ``difflib`` of Python to check spelling. This is a much slower approach,
|
||||
and it is less sophisticated than full spell checking libaries, but if you only work with small
|
||||
files, the performance loss is not noticeable. The spell check library must be at least 3.0 to work
|
||||
with Windows. On Linux, 2.0 also works fine.
|
||||
|
||||
* ``pyenchant``, needed for efficient spell checking.
|
||||
If you install from PyPi, these dependencies should be installed automatically. They can be
|
||||
manually installed with:
|
||||
|
||||
The optional spell check library must be at least 3.0 to work with Windows. On Linux, 2.0 also
|
||||
works fine.
|
||||
.. code-block:: console
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
|
||||
.. _a_started_depend_docs:
|
||||
.. _a_started_running:
|
||||
|
||||
Running from Source
|
||||
-------------------
|
||||
|
||||
If all the required dependencies are met, you can run novelWriter from the command line with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python novelWriter.py
|
||||
|
||||
A few switches are supported from the command line, mostly to assist in debugging if an error is
|
||||
encountered. To list all options, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python novelWriter.py --help
|
||||
|
||||
|
||||
.. _a_started_linux:
|
||||
|
||||
Setup on Linux
|
||||
==============
|
||||
|
||||
The dependencies of novelWriter are generally available from Linux distro repositories. For Debian
|
||||
and Ubuntu, they can be installed with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo apt install python3-pyqt5 python3-lxml python3-enchant
|
||||
|
||||
If you downloaded the source, you can use the provided ``setup.py`` script to install novelWriter
|
||||
into the system's default Python install locations. If so, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python setup.py install
|
||||
|
||||
To set up the novelWriter desktop launcher, the icons, and the project file association, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python setup.py xdg-install
|
||||
|
||||
By default, these commands install novelWriter and its icons for the current user only. To install
|
||||
for all users, run the script with the ``sudo`` command. Other options are also available. Run
|
||||
``python setup.py help`` for a full list of install options.
|
||||
|
||||
|
||||
.. _a_started_macos:
|
||||
|
||||
Setup on macOS
|
||||
==============
|
||||
|
||||
These instructions assume you're using brew, and have Python and pip set up. If not, see the
|
||||
`brew docs`_ for help. Main requirements are installed via the requirements file. You also need to
|
||||
install the ``pyobjc`` package, so you must run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip3 install --user -r requirements.txt
|
||||
pip3 install --user pyobjc
|
||||
|
||||
For spell checking you may also need to install the enchant package. It comes with a lot of default
|
||||
dictionaries.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
brew install enchant
|
||||
|
||||
.. _brew docs: https://docs.brew.sh/Homebrew-and-Python
|
||||
|
||||
|
||||
.. _a_started_windows:
|
||||
|
||||
Setup on Windows
|
||||
================
|
||||
|
||||
On Windows, you have two options: You can either run from source, or install novelWriter via a
|
||||
Windows installer.
|
||||
|
||||
|
||||
.. _a_started_win_installer:
|
||||
|
||||
Windows Installer
|
||||
-----------------
|
||||
|
||||
You can install novelWriter with the Windows installer for 64-bit Windows available on the
|
||||
`main website`_ and GitHub_ page. This installer bundles all that is needed for novelWriter to run,
|
||||
including Python and the xml and Qt libraries. When installing novelWriter this way, you don't need
|
||||
to install any of the dependencies manually. The installer is made with pyinstaller and Inno Setup.
|
||||
|
||||
.. _main website: https://novelwriter.io
|
||||
|
||||
|
||||
.. _a_started_win_source:
|
||||
|
||||
From Source
|
||||
-----------
|
||||
|
||||
To run from source, you may first need to install Python. If you don't have it installed, you can
|
||||
download it from the python.org_ website. novelWriter should work with Python 3.6 or higher, but it
|
||||
is recommended that you install the latest version of Python.
|
||||
|
||||
Also, make sure you select the "Add Python to PATH" option during installation.
|
||||
|
||||
.. image:: images/python_win_install.png
|
||||
:width: 600
|
||||
|
||||
Once Python is set up and running, you can either run novelWriter from the folder where you
|
||||
extracted it, or you can build an executable and run that from a desktop icon instead.
|
||||
|
||||
The PyPi installer should come bundled with the Python installation, so to install dependencies,
|
||||
run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install --user -r requirements.txt
|
||||
|
||||
.. tip::
|
||||
|
||||
To create a desktop shortcut to launch novelWriter, you can right click the ``novelWriter.py``
|
||||
file, create a shortcut, then right click again, select "Properties" and change the target to
|
||||
your python executable followed by ``novelWriter.py``. It should look something like this:
|
||||
``C:\...\AppData\Local\Programs\Python\Python38\python.exe novelWriter.py``
|
||||
|
||||
You can also run the ``make.py`` script to generate a single executable, or an installer.
|
||||
See `Build and Install novelWriter`_ for more details or run: ``python make.py help``.
|
||||
|
||||
.. _python.org: https://www.python.org/downloads/windows/
|
||||
.. _Build and Install novelWriter: https://github.com/vkbo/novelWriter/blob/main/setup/README.md
|
||||
|
||||
|
||||
.. _a_started_docs:
|
||||
|
||||
Building the Documentation
|
||||
--------------------------
|
||||
==========================
|
||||
|
||||
If you installed novelWriter from a package, the documentation should be included. If you're
|
||||
running novelWriter from the source code, a local copy of this documentation can be generated. It
|
||||
@@ -145,7 +245,7 @@ The documentation can then be built from the ``docs`` folder in the source code
|
||||
|
||||
make html
|
||||
|
||||
If successful, the documentation should then be available in the ``docs/build/html`` folder.
|
||||
If successful, the documentation should be available in the ``docs/build/html`` folder.
|
||||
|
||||
The documentation can also be built for the Qt Assistant. To build the help packages from the
|
||||
documentation source, run the following from the root source folder:
|
||||
@@ -164,53 +264,3 @@ locally first, then send you to the website as a fallback.
|
||||
computer. If it isn't available, or novelWriter cannot find it, the help feature will fall back
|
||||
to redirecting you to the documentation website.
|
||||
|
||||
|
||||
.. _a_started_running:
|
||||
|
||||
Running from Source
|
||||
===================
|
||||
|
||||
If all the required dependencies are met, you can run novelWriter from the command line:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python novelWriter.py
|
||||
|
||||
A few switches are supported from the command line, mostly to assist in debugging if an error is
|
||||
encountered. To list all options, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python novelWriter.py --help
|
||||
|
||||
|
||||
.. _a_started_standalone:
|
||||
|
||||
Building a Standalone Executable
|
||||
================================
|
||||
|
||||
A standalone executable can be built with ``pyinstaller``, using the provided python script
|
||||
``make.py`` in the source folder. This script can install dependencies, build a standalone
|
||||
executable of novelWriter, or build a ``setup.exe`` file with Inno Setup.
|
||||
|
||||
For a full list of the script's options, run ``python make.py help``.
|
||||
|
||||
|
||||
.. _a_started_standalone_win:
|
||||
|
||||
Additional Instructions for Windows
|
||||
-----------------------------------
|
||||
|
||||
If you don't have Python installed, you can download it from the python.org website. The installers
|
||||
for Windows are available at https://www.python.org/downloads/windows/
|
||||
|
||||
novelWriter should work with Python 3.6 or higher, and the executable installer is the easiest to
|
||||
install.
|
||||
|
||||
Also, make sure you select the "Add Python to PATH" option.
|
||||
|
||||
.. image:: images/python_win_install.png
|
||||
:width: 600
|
||||
|
||||
Once Python is set up and running, you can either run novelWriter from the folder where you
|
||||
extracted it, or you can build an executable and run that from a desktop icon instead.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from nw.constants.iso import isoLanguage, isoCountry
|
||||
from nw.constants.constants import (
|
||||
nwConst, nwRegEx, nwFiles, nwKeyWords, nwLabels, nwQuotes, nwUnicode
|
||||
nwConst, nwLists, nwRegEx, nwFiles, nwKeyWords, nwLabels, nwQuotes, nwUnicode
|
||||
)
|
||||
from nw.constants.enum import (
|
||||
nwAlert, nwDocAction, nwItemClass, nwItemLayout, nwItemType, nwOutline,
|
||||
@@ -11,18 +11,19 @@ from nw.constants.enum import (
|
||||
__all__ = [
|
||||
"isoCountry",
|
||||
"isoLanguage",
|
||||
"nwAlert",
|
||||
"nwConst",
|
||||
"nwDocAction",
|
||||
"nwDocInsert",
|
||||
"nwLists",
|
||||
"nwRegEx",
|
||||
"nwFiles",
|
||||
"nwKeyWords",
|
||||
"nwLabels",
|
||||
"nwQuotes",
|
||||
"nwUnicode",
|
||||
"nwAlert",
|
||||
"nwDocAction",
|
||||
"nwItemClass",
|
||||
"nwItemLayout",
|
||||
"nwItemType",
|
||||
"nwKeyWords",
|
||||
"nwLabels",
|
||||
"nwOutline",
|
||||
"nwQuotes",
|
||||
"nwRegEx",
|
||||
"nwUnicode",
|
||||
"nwDocInsert",
|
||||
]
|
||||
|
||||
@@ -45,10 +45,19 @@ class nwConst():
|
||||
SP_INTERNAL = "internal"
|
||||
SP_ENCHANT = "enchant"
|
||||
|
||||
# Check Lists
|
||||
# END Class nwConst
|
||||
|
||||
class nwLists():
|
||||
"""Lists used for grouping various other constants.
|
||||
"""
|
||||
|
||||
# Regular user-accessible item types
|
||||
REG_TYPES = {nwItemType.ROOT, nwItemType.FOLDER, nwItemType.FILE}
|
||||
|
||||
# END Class nwConst
|
||||
# Item classes where the full list of novel layouts are allowed
|
||||
CLS_NOVEL = {nwItemClass.NOVEL, nwItemClass.ARCHIVE}
|
||||
|
||||
# END Class nwLists
|
||||
|
||||
class nwRegEx():
|
||||
|
||||
|
||||
+4
-1
@@ -606,10 +606,13 @@ class NWProject():
|
||||
self.theParent.setStatus("Opened Project: %s" % self.projName)
|
||||
|
||||
self._scanProjectFolder()
|
||||
self.setProjectChanged(False)
|
||||
|
||||
self.currWCount = self.lastWCount
|
||||
self.projOpened = time()
|
||||
self.projAltered = False
|
||||
|
||||
self._writeLockFile()
|
||||
self.setProjectChanged(False)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
+18
-5
@@ -316,7 +316,6 @@ class GuiDocEditor(QTextEdit):
|
||||
self.lastEdit = time()
|
||||
self._runCounter()
|
||||
self.wcTimer.start()
|
||||
self.setDocumentChanged(False)
|
||||
self.theHandle = tHandle
|
||||
|
||||
self.setReadOnly(False)
|
||||
@@ -341,6 +340,9 @@ class GuiDocEditor(QTextEdit):
|
||||
self.docFooter.updateLineCount()
|
||||
self.lengthLast = self.qDocument.characterCount()
|
||||
|
||||
qApp.processEvents()
|
||||
self.setDocumentChanged(False)
|
||||
|
||||
qApp.restoreOverrideCursor()
|
||||
|
||||
return True
|
||||
@@ -373,8 +375,8 @@ class GuiDocEditor(QTextEdit):
|
||||
|
||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
self.setPlainText(theText)
|
||||
self.setDocumentChanged(True)
|
||||
self.updateDocMargins()
|
||||
self.setDocumentChanged(True)
|
||||
qApp.restoreOverrideCursor()
|
||||
|
||||
return True
|
||||
@@ -450,11 +452,17 @@ class GuiDocEditor(QTextEdit):
|
||||
lM = max(cM, fH)
|
||||
self.setViewportMargins(tM, uM, tM, lM)
|
||||
|
||||
docChanged = self.docChanged
|
||||
if self.mainConf.scrollPastEnd:
|
||||
docFrame = self.qDocument.rootFrame().frameFormat()
|
||||
docFrame.setBottomMargin(max(0, 0.6*(wH - uM - lM - 4*tB)))
|
||||
self.qDocument.rootFrame().setFrameFormat(docFrame)
|
||||
|
||||
# This is needed as the setFrameFormat function itself will
|
||||
# trigger the contetsChanged signal which sets docChanged, so we
|
||||
# set it back to whatever it was before.
|
||||
self.setDocumentChanged(docChanged)
|
||||
|
||||
return
|
||||
|
||||
def updateDocInfo(self, tHandle):
|
||||
@@ -895,12 +903,13 @@ class GuiDocEditor(QTextEdit):
|
||||
##
|
||||
|
||||
@pyqtSlot(int, int, int)
|
||||
def _docChange(self, thePos, charsRemoved, charsAdded):
|
||||
def _docChange(self, thePos, chrRem, chrAdd):
|
||||
"""Triggered by QTextDocument->contentsChanged. This also
|
||||
triggers the syntax highlighter.
|
||||
"""
|
||||
self.lastEdit = time()
|
||||
self.lastFind = None
|
||||
|
||||
if self.qDocument.characterCount() > nwConst.MAX_DOCSIZE:
|
||||
self.theParent.makeAlert((
|
||||
"The document has grown too big and you cannot add more text to it. "
|
||||
@@ -908,12 +917,16 @@ class GuiDocEditor(QTextEdit):
|
||||
) % (nwConst.MAX_DOCSIZE/1.0e6), nwAlert.ERROR)
|
||||
self.undo()
|
||||
return
|
||||
|
||||
if not self.docChanged:
|
||||
self.setDocumentChanged(True)
|
||||
self.setDocumentChanged(chrRem != 0 or chrAdd != 0)
|
||||
|
||||
if not self.wcTimer.isActive():
|
||||
self.wcTimer.start()
|
||||
if self.doReplace and charsAdded == 1:
|
||||
|
||||
if self.doReplace and chrAdd == 1:
|
||||
self._docAutoReplace(self.qDocument.findBlock(thePos))
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot("QPoint")
|
||||
|
||||
+57
-34
@@ -28,13 +28,14 @@
|
||||
import nw
|
||||
import logging
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QGridLayout, QLineEdit, QComboBox, QLabel,
|
||||
QDialogButtonBox
|
||||
)
|
||||
|
||||
from nw.gui.custom import QSwitch
|
||||
from nw.constants import nwLabels, nwItemLayout, nwItemClass, nwItemType
|
||||
from nw.constants import nwLabels, nwItemLayout, nwItemType, nwLists
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -50,23 +51,29 @@ class GuiItemEditor(QDialog):
|
||||
self.theProject = theProject
|
||||
self.theParent = theParent
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
##
|
||||
# Build GUI
|
||||
##
|
||||
|
||||
self.theItem = self.theProject.projTree[tHandle]
|
||||
if self.theItem is None:
|
||||
self._doClose()
|
||||
|
||||
self.setWindowTitle("Item Settings")
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
mVd = self.mainConf.pxInt(220)
|
||||
mSp = self.mainConf.pxInt(16)
|
||||
vSp = self.mainConf.pxInt(4)
|
||||
|
||||
# Item Label
|
||||
self.editName = QLineEdit()
|
||||
self.editName.setMinimumWidth(self.mainConf.pxInt(220))
|
||||
self.editName.setMaxLength(self.mainConf.pxInt(200))
|
||||
self.editName.setMinimumWidth(mVd)
|
||||
self.editName.setMaxLength(200)
|
||||
|
||||
# Item Status
|
||||
self.editStatus = QComboBox()
|
||||
if self.theItem.itemClass == nwItemClass.NOVEL:
|
||||
self.editStatus.setMinimumWidth(mVd)
|
||||
if self.theItem.itemClass in nwLists.CLS_NOVEL:
|
||||
for sLabel, _, _ in self.theProject.statusItems:
|
||||
self.editStatus.addItem(
|
||||
self.theParent.statusIcons[sLabel], sLabel, sLabel
|
||||
@@ -79,24 +86,24 @@ class GuiItemEditor(QDialog):
|
||||
|
||||
# Item Layout
|
||||
self.editLayout = QComboBox()
|
||||
self.validLayouts = []
|
||||
self.editLayout.setMinimumWidth(mVd)
|
||||
validLayouts = []
|
||||
if self.theItem.itemType == nwItemType.FILE:
|
||||
if self.theItem.itemClass == nwItemClass.NOVEL:
|
||||
self.validLayouts.append(nwItemLayout.TITLE)
|
||||
self.validLayouts.append(nwItemLayout.BOOK)
|
||||
self.validLayouts.append(nwItemLayout.PAGE)
|
||||
self.validLayouts.append(nwItemLayout.PARTITION)
|
||||
self.validLayouts.append(nwItemLayout.UNNUMBERED)
|
||||
self.validLayouts.append(nwItemLayout.CHAPTER)
|
||||
self.validLayouts.append(nwItemLayout.SCENE)
|
||||
self.validLayouts.append(nwItemLayout.NOTE)
|
||||
else:
|
||||
self.validLayouts.append(nwItemLayout.NOTE)
|
||||
if self.theItem.itemClass in nwLists.CLS_NOVEL:
|
||||
validLayouts.append(nwItemLayout.TITLE)
|
||||
validLayouts.append(nwItemLayout.BOOK)
|
||||
validLayouts.append(nwItemLayout.PAGE)
|
||||
validLayouts.append(nwItemLayout.PARTITION)
|
||||
validLayouts.append(nwItemLayout.UNNUMBERED)
|
||||
validLayouts.append(nwItemLayout.CHAPTER)
|
||||
validLayouts.append(nwItemLayout.SCENE)
|
||||
validLayouts.append(nwItemLayout.NOTE)
|
||||
else:
|
||||
self.validLayouts.append(nwItemLayout.NO_LAYOUT)
|
||||
validLayouts.append(nwItemLayout.NO_LAYOUT)
|
||||
self.editLayout.setEnabled(False)
|
||||
|
||||
for itemLayout in nwItemLayout:
|
||||
if itemLayout in self.validLayouts:
|
||||
if itemLayout in validLayouts:
|
||||
self.editLayout.addItem(nwLabels.LAYOUT_NAME[itemLayout], itemLayout)
|
||||
|
||||
# Export Switch
|
||||
@@ -109,23 +116,30 @@ class GuiItemEditor(QDialog):
|
||||
self.editExport.setEnabled(False)
|
||||
self.editExport.setChecked(False)
|
||||
|
||||
self.editName.setText(self.theItem.itemName)
|
||||
statusIdx = self.editStatus.findData(self.theItem.itemStatus)
|
||||
if statusIdx != -1:
|
||||
self.editStatus.setCurrentIndex(statusIdx)
|
||||
layoutIdx = self.editLayout.findData(self.theItem.itemLayout)
|
||||
if layoutIdx != -1:
|
||||
self.editLayout.setCurrentIndex(layoutIdx)
|
||||
|
||||
# Buttons
|
||||
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
self.buttonBox.accepted.connect(self._doSave)
|
||||
self.buttonBox.rejected.connect(self._doClose)
|
||||
|
||||
# Assemble
|
||||
# Set Current Values
|
||||
self.editName.setText(self.theItem.itemName)
|
||||
self.editName.selectAll()
|
||||
|
||||
statusIdx = self.editStatus.findData(self.theItem.itemStatus)
|
||||
if statusIdx != -1:
|
||||
self.editStatus.setCurrentIndex(statusIdx)
|
||||
|
||||
layoutIdx = self.editLayout.findData(self.theItem.itemLayout)
|
||||
if layoutIdx != -1:
|
||||
self.editLayout.setCurrentIndex(layoutIdx)
|
||||
|
||||
##
|
||||
# Assemble
|
||||
##
|
||||
|
||||
self.mainForm = QGridLayout()
|
||||
self.mainForm.setVerticalSpacing(self.mainConf.pxInt(4))
|
||||
self.mainForm.setHorizontalSpacing(self.mainConf.pxInt(16))
|
||||
self.mainForm.setVerticalSpacing(vSp)
|
||||
self.mainForm.setHorizontalSpacing(mSp)
|
||||
self.mainForm.addWidget(QLabel("Label"), 0, 0, 1, 1)
|
||||
self.mainForm.addWidget(self.editName, 0, 1, 1, 2)
|
||||
self.mainForm.addWidget(QLabel("Status"), 1, 0, 1, 1)
|
||||
@@ -134,20 +148,28 @@ class GuiItemEditor(QDialog):
|
||||
self.mainForm.addWidget(self.editLayout, 2, 1, 1, 2)
|
||||
self.mainForm.addWidget(self.textExport, 3, 0, 1, 2)
|
||||
self.mainForm.addWidget(self.editExport, 3, 2, 1, 1)
|
||||
self.mainForm.setColumnStretch(0, 0)
|
||||
self.mainForm.setColumnStretch(1, 1)
|
||||
self.mainForm.setColumnStretch(2, 0)
|
||||
|
||||
self.outerBox.setSpacing(self.mainConf.pxInt(16))
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.setSpacing(mSp)
|
||||
self.outerBox.addLayout(self.mainForm)
|
||||
self.outerBox.addStretch(1)
|
||||
self.outerBox.addWidget(self.buttonBox)
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
self.rejected.connect(self._doClose)
|
||||
self.editName.selectAll()
|
||||
|
||||
logger.debug("GuiItemEditor initialisation complete")
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Slots
|
||||
##
|
||||
|
||||
@pyqtSlot()
|
||||
def _doSave(self):
|
||||
"""Save the setting to the item.
|
||||
"""
|
||||
@@ -170,10 +192,11 @@ class GuiItemEditor(QDialog):
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _doClose(self):
|
||||
"""Close the dialog without saving the settings.
|
||||
"""
|
||||
logger.verbose("ItemEditor close button clicked")
|
||||
logger.verbose("ItemEditor cancel button clicked")
|
||||
self.close()
|
||||
return
|
||||
|
||||
|
||||
+7
-13
@@ -553,36 +553,30 @@ class GuiProjectTree(QTreeWidget):
|
||||
the project tree. Does not trigger a tree change as the data is
|
||||
already coming from the project tree.
|
||||
"""
|
||||
trItem = self._getTreeItem(tHandle)
|
||||
nwItem = self.theProject.projTree[tHandle]
|
||||
tName = nwItem.itemName
|
||||
tClass = nwItem.itemClass
|
||||
tHandle = nwItem.itemHandle
|
||||
trItem = self._getTreeItem(tHandle)
|
||||
nwItem = self.theProject.projTree[tHandle]
|
||||
|
||||
expIcon = QIcon()
|
||||
|
||||
stClass = nwLabels.CLASS_FLAG[nwItem.itemClass]
|
||||
stLayout = ""
|
||||
stFlags = nwLabels.CLASS_FLAG[nwItem.itemClass]
|
||||
if nwItem.itemType == nwItemType.FILE:
|
||||
stLayout = "."+nwLabels.LAYOUT_FLAG[nwItem.itemLayout]
|
||||
stFlags += "."+nwLabels.LAYOUT_FLAG[nwItem.itemLayout]
|
||||
if nwItem.isExported:
|
||||
expIcon = self.theTheme.getIcon("check")
|
||||
else:
|
||||
expIcon = self.theTheme.getIcon("cross")
|
||||
tStatus = stClass+stLayout
|
||||
|
||||
iStatus = nwItem.itemStatus
|
||||
if tClass == nwItemClass.NOVEL:
|
||||
if nwItem.itemClass == nwItemClass.NOVEL:
|
||||
iStatus = self.theProject.statusItems.checkEntry(iStatus) # Make sure it's valid
|
||||
flagIcon = self.theParent.statusIcons[iStatus]
|
||||
else:
|
||||
iStatus = self.theProject.importItems.checkEntry(iStatus) # Make sure it's valid
|
||||
flagIcon = self.theParent.importIcons[iStatus]
|
||||
|
||||
trItem.setText(self.C_NAME, tName)
|
||||
trItem.setText(self.C_NAME, nwItem.itemName)
|
||||
trItem.setIcon(self.C_EXPORT, expIcon)
|
||||
trItem.setText(self.C_FLAGS, tStatus)
|
||||
trItem.setIcon(self.C_FLAGS, flagIcon)
|
||||
trItem.setText(self.C_FLAGS, stFlags)
|
||||
|
||||
return
|
||||
|
||||
|
||||
+2
-17
@@ -51,9 +51,6 @@ class GuiMainStatus(QStatusBar):
|
||||
self.theTheme = theParent.theTheme
|
||||
self.refTime = None
|
||||
|
||||
self.projWords = 0
|
||||
self.sessWords = 0
|
||||
|
||||
colNone = QColor(*self.theTheme.statNone)
|
||||
colTrue = QColor(*self.theTheme.statUnsaved)
|
||||
colFalse = QColor(*self.theTheme.statSaved)
|
||||
@@ -182,26 +179,14 @@ class GuiMainStatus(QStatusBar):
|
||||
def setStats(self, pWC, sWC):
|
||||
"""Set the current project statistics.
|
||||
"""
|
||||
self.projWords = pWC
|
||||
self.sessWords = sWC
|
||||
self._updateStats()
|
||||
self.statsText.setText(f"Words: {pWC:n} ({sWC:+n})")
|
||||
self.statsText.setToolTip("Project word count (session change)")
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _updateStats(self):
|
||||
"""Update statistics.
|
||||
"""
|
||||
self.statsText.setToolTip(
|
||||
"Project word count (session change)"
|
||||
)
|
||||
self.statsText.setText(
|
||||
f"Words: {self.projWords:n} ({self.sessWords:+n})"
|
||||
)
|
||||
return
|
||||
|
||||
def _updateTime(self):
|
||||
"""Update the session clock.
|
||||
"""
|
||||
|
||||
+11
-3
@@ -47,7 +47,7 @@ from nw.gui import (
|
||||
GuiProjectTree, GuiProjectWizard, GuiTheme, GuiWritingStats
|
||||
)
|
||||
from nw.core import NWProject, NWDoc, NWIndex
|
||||
from nw.constants import nwItemType, nwItemClass, nwAlert, nwConst
|
||||
from nw.constants import nwItemType, nwItemClass, nwAlert, nwLists
|
||||
from nw.common import getGuiItem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -446,10 +446,12 @@ class GuiMain(QMainWindow):
|
||||
self.docEditor.setSpellCheck(self.theProject.spellCheck)
|
||||
self.mainMenu.setAutoOutline(self.theProject.autoOutline)
|
||||
self.statusBar.setRefTime(self.theProject.projOpened)
|
||||
self.statusBar.setStats(self.theProject.currWCount, 0)
|
||||
|
||||
# Restore previously open documents, if any
|
||||
if self.theProject.lastEdited is not None:
|
||||
self.openDocument(self.theProject.lastEdited, doScroll=True)
|
||||
|
||||
if self.theProject.lastViewed is not None:
|
||||
self.viewDocument(self.theProject.lastViewed)
|
||||
|
||||
@@ -457,6 +459,12 @@ class GuiMain(QMainWindow):
|
||||
if self.theIndex.indexBroken:
|
||||
self.rebuildIndex()
|
||||
|
||||
# Make sure the changed status is set to false on all that was
|
||||
# just opened
|
||||
qApp.processEvents()
|
||||
self.docEditor.setDocumentChanged(False)
|
||||
self.theProject.setProjectChanged(False)
|
||||
|
||||
logger.debug("Project load complete")
|
||||
|
||||
return True
|
||||
@@ -477,7 +485,7 @@ class GuiMain(QMainWindow):
|
||||
return False
|
||||
|
||||
self.treeView.saveTreeOrder()
|
||||
self.theProject.saveProject(autoSave)
|
||||
self.theProject.saveProject(autoSave=autoSave)
|
||||
self.theIndex.saveIndex()
|
||||
|
||||
return True
|
||||
@@ -743,7 +751,7 @@ class GuiMain(QMainWindow):
|
||||
tItem = self.theProject.projTree[tHandle]
|
||||
if tItem is None:
|
||||
return
|
||||
if tItem.itemType not in nwConst.REG_TYPES:
|
||||
if tItem.itemType not in nwLists.REG_TYPES:
|
||||
return
|
||||
|
||||
logger.verbose("Requesting change to item %s" % tHandle)
|
||||
|
||||
Reference in New Issue
Block a user