Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
448057edf6 | ||
|
|
9d993b2992 | ||
|
|
8ca13f6e08 | ||
|
|
80fc4c9538 | ||
|
|
9f8867c1b4 | ||
|
|
481ce883ab | ||
|
|
63f184dd60 | ||
|
|
3d4d9ed111 | ||
|
|
b2ba932735 | ||
|
|
8c1070b318 | ||
|
|
6c4d8f3ede | ||
|
|
f2c118776a | ||
|
|
87890dd249 | ||
|
|
15301c9121 | ||
|
|
8dc4b661d8 | ||
|
|
d47ec4157d | ||
|
|
9d64a59b70 | ||
|
|
234fc20048 | ||
|
|
8432dfdd1f | ||
|
|
5fddfd395e | ||
|
|
11d0e4220f | ||
|
|
6d4e066810 | ||
|
|
9f1274f953 | ||
|
|
9ac1692e2a | ||
|
|
6f88357977 | ||
|
|
19bdbf9aca | ||
|
|
5a25d34ba3 | ||
|
|
13e6199af2 | ||
|
|
5be1e2c954 | ||
|
|
306bd245fc | ||
|
|
7e42d04e36 | ||
|
|
53dfdb3a2e | ||
|
|
eb113a8928 | ||
|
|
c369ef450f | ||
|
|
6674cf99a6 | ||
|
|
70cca405f5 | ||
|
|
d7d211baf2 | ||
|
|
d5a35fa86f | ||
|
|
dc265e57f3 | ||
|
|
4b79b2bd57 | ||
|
|
80c9e54a9a | ||
|
|
eba0b607a4 | ||
|
|
04464a2798 | ||
|
|
202b5192ed | ||
|
|
62397225f9 | ||
|
|
b220fffd6f | ||
|
|
e14f7881a3 | ||
|
|
2085fbe107 | ||
|
|
31a75f044e | ||
|
|
5b74125fcd | ||
|
|
1cf3cfcf77 | ||
|
|
defaf6c1ee | ||
|
|
e0f467fa10 | ||
|
|
362da679b6 | ||
|
|
0b35bcfc3b | ||
|
|
fad162c6c1 | ||
|
|
97fc64fcae | ||
|
|
5224234637 | ||
|
|
b4f1d0ec77 | ||
|
|
5911c43b5b | ||
|
|
4f137466c5 | ||
|
|
3836a2a56c | ||
|
|
49e59d74cc | ||
|
|
9461eea03a | ||
|
|
136939d391 | ||
|
|
33aea82e6e | ||
|
|
4a6511b39f | ||
|
|
6448f05557 | ||
|
|
c08eca7c3b | ||
|
|
df6ca2e17b | ||
|
|
c39a5f9708 | ||
|
|
46d69c31d1 | ||
|
|
e924d121bf | ||
|
|
2fa1dcccac | ||
|
|
dc9413fa7e | ||
|
|
1b34bc30c7 | ||
|
|
4d33f087df | ||
|
|
81a4d5fadb | ||
|
|
7682ae0425 | ||
|
|
677274adb3 |
5
.github/workflows/build_mac.yml
vendored
@@ -8,8 +8,7 @@ jobs:
|
||||
|
||||
buildMac-AMD64:
|
||||
needs: buildAssets
|
||||
# Stay on macos-12 due to https://github.com/create-dmg/create-dmg/issues/143
|
||||
runs-on: macos-12
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
PYTHON_VERSION: "3.12"
|
||||
PACKAGE_ARCH: x86_64
|
||||
@@ -40,7 +39,7 @@ jobs:
|
||||
|
||||
buildMac-M1:
|
||||
needs: buildAssets
|
||||
runs-on: macos-14
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
PYTHON_VERSION: "3.12"
|
||||
PACKAGE_ARCH: aarch64
|
||||
|
||||
2
.github/workflows/test_linux.yml
vendored
@@ -41,6 +41,6 @@ jobs:
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
2
.github/workflows/test_mac.yml
vendored
@@ -32,6 +32,6 @@ jobs:
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
2
.github/workflows/test_win.yml
vendored
@@ -28,6 +28,6 @@ jobs:
|
||||
run: |
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
82
CHANGELOG.md
@@ -1,5 +1,87 @@
|
||||
# novelWriter Changelog
|
||||
|
||||
## Version 2.6 [2025-01-26]
|
||||
|
||||
### Release Notes
|
||||
|
||||
The 2.6 release fixes a few minor issues from the RC 1 pre-release, and updates most translations.
|
||||
|
||||
See the website for complete [Release Notes](https://novelwriter.io/releases/release_2_6.html).
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed a bug in the novel selector dropdown used a few places that would clear the selection if
|
||||
the novel list was refreshed. PR #2179.
|
||||
* Fixed a bug that would crash the app if the project tree was clicked without any project having
|
||||
been loaded. The selection model does not exist prior to a project load. Issue #2173. PR #2181.
|
||||
* Replaced a broken link on the dictionary install tool available on Windows. PR #2189.
|
||||
* Backported a few code fixes from 2.7 related to freeing memory from closed dialogs and one
|
||||
instance of a potentially uninitialised variable. PR #2202.
|
||||
* Fixed word wrapping in the item details panel for status and importance labels with very long
|
||||
names. PR #2202.
|
||||
* Fixed the project tree context menu so that it is not opened when right-clicking on an empty area
|
||||
of the tree widget. PR #2202.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* Chapter headings are now level 1 headings in all manuscript output formats, not just HTML like
|
||||
before. Most applications that post-processes output will assume chapters are level 1.
|
||||
Correspondingly, scenes are now level 2 and sections are level 3. Notes headings remain
|
||||
unchanged. Issue #2205. PR #2206.
|
||||
|
||||
**Internationalisation**
|
||||
|
||||
* German, US English, Italian, Japanese, Norwegian and Polish have been updated in full. Brazilian
|
||||
Portuguese and Chinese have been partially updated. PR #2207.
|
||||
|
||||
**Documentation**
|
||||
|
||||
* Documentation has been updated with 2.6 features. PR #2210.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.6 RC 1 [2025-01-09]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a release candidate of the next release version, and is intended for testing purposes.
|
||||
Please be careful when using this version on live writing projects, and make sure you take frequent
|
||||
backups.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**New Features**
|
||||
|
||||
* The session timer in the status bar can now be hidden by clicking on it. Issue #1029. PR #2149.
|
||||
* Status and importance labels can now be exported and imported. Issue #1847. PRs #2152 and #2153.
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fix a beta release bug where it was not possible to change the status or importance flag on
|
||||
folders in the project tree. Issue #2145. PR #2147.
|
||||
* Fix an issue where the word counter would override the selection counter in the editor. This was
|
||||
caused by the selection counter being on a much shorter timer than the word counter, so in some
|
||||
cases the latter result came in after the former even if the user actions where the other way
|
||||
around. The selection counter now takes precedence, always. Issue #2155. PRs #2156 and #2157.
|
||||
* Fix a minor issue where the search panel header background would not update colour when the theme
|
||||
was changed. Issue #2162. PR #2167.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* It is no longer necessary to click the "Apply" button when making changes to status and
|
||||
importance labels, or auto-replace settings, in Project Settings. The changes are applied
|
||||
directly to the listed items. They are not applied to the project until the Project Settings are
|
||||
accepted. This is a more intuitive approach. Issue #2150. PR #2151.
|
||||
|
||||
**Packaging and Installation**
|
||||
|
||||
* MacOS packages are now built on the latest MacOS image available on GitHub. The x86_64 build was
|
||||
previously locked to MacOS 12, which is no loner available. PR #2141.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.6 Beta 2 [2024-12-23]
|
||||
|
||||
### Release Notes
|
||||
|
||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 530 KiB After Width: | Height: | Size: 516 KiB |
|
Before Width: | Height: | Size: 540 KiB After Width: | Height: | Size: 535 KiB |
@@ -13,7 +13,7 @@ Glossary
|
||||
see :ref:`a_proj_roots`.
|
||||
|
||||
Novel Documents
|
||||
These are documents that are created under a "Novel" :term:`root folder`. They behave
|
||||
These are documents that are created under a "Novel" :term:`Root Folder`. They behave
|
||||
differently than :term:`Project Notes`, and have some more restrictions. For instance, they
|
||||
can not exist in folders intended only for project notes. See the :ref:`a_struct` chapter for
|
||||
more details.
|
||||
|
||||
@@ -16,7 +16,7 @@ This is a list of hopefully helpful little tips on how to get the most out of no
|
||||
Managing the Project
|
||||
====================
|
||||
|
||||
.. dropdown:: Create a Project from a Template
|
||||
.. dropdown:: How do I create a project from a template?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
On the Welcome dialog's **Create New Project** form, you can select to "Prefill Project" from
|
||||
@@ -24,7 +24,7 @@ Managing the Project
|
||||
dedicated to be a template project. If you have a structure and settings you want to use for
|
||||
every new project, this is the best solution.
|
||||
|
||||
.. dropdown:: Merge Multiple Documents Into One
|
||||
.. dropdown:: How do I merge multiple documents into one?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
If you need to merge a selection of documents in your project into a single document, you can
|
||||
@@ -35,28 +35,18 @@ Managing the Project
|
||||
In the dialog that pops up, the documents will be in the same order as in the folder, but you
|
||||
can rearrange them here of you wish. See :ref:`a_ui_tree_split_merge` for more details.
|
||||
|
||||
.. dropdown:: How do I share status or importance labels between projects?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
The status or importance labels you have defined in a project can be exported from **Project
|
||||
Settings** from the respective configuration tabs. You can then import these labels in another
|
||||
project.
|
||||
|
||||
|
||||
Layout Tricks
|
||||
=============
|
||||
|
||||
.. dropdown:: Align Paragraphs with Line Breaks
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
If you have line breaks in you paragraphs, and also want to apply additional text alignment or
|
||||
indentation, you must apply the alignment tags to the first line.
|
||||
|
||||
For example, this will centre the two lines.
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
>> Line one is centred. <<
|
||||
Line two is also centred.
|
||||
|
||||
This text is not centred, because it is a new paragraph.
|
||||
|
||||
See :ref:`a_fmt_align` for more details.
|
||||
|
||||
.. dropdown:: Create a Simple Table
|
||||
.. dropdown:: How do I create a table?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
The formatting tools available in novelWriter don't allow for complex structures like tables.
|
||||
@@ -69,12 +59,22 @@ Layout Tricks
|
||||
This is most suitable for your notes, as the result in exported documents cannot be guaranteed
|
||||
to match. Especially if you don't use the same font in your manuscript as in the editor.
|
||||
|
||||
.. dropdown:: Turn Off First Line Indent for a Paragraph
|
||||
.. dropdown:: How do I force a line break when line breaks are ignored in my manuscript?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
In the **Manuscript Build Settings** you can choose to ignore line breaks within paragraphs in
|
||||
your text. However, some times you still need those breaks. Like for instance on the cover page
|
||||
where you may need to add your name and address. In such cases, you can add ``[br]`` where you
|
||||
want line breaks. These breaks cannot be ignored by any settings and will always be respected.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
.. dropdown:: How do I turn off first line indent for a specific paragraph?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
If you have first line indent enabled, but have a specific paragraph that you don't want
|
||||
indented, you can disable the indentation by explicitly add text alignment. Aligned paragraphs
|
||||
are not indented. For instance by adding ``<<`` to the end to left-align it,
|
||||
indented, you can disable the indentation by explicitly adding text alignment. For instance by
|
||||
adding ``<<`` to the end to left-align it. Aligned paragraphs are not indented.
|
||||
|
||||
See :ref:`a_fmt_align` for more details.
|
||||
|
||||
@@ -82,7 +82,7 @@ Layout Tricks
|
||||
Organising Your Text
|
||||
====================
|
||||
|
||||
.. dropdown:: Add Introductory Text to Chapters
|
||||
.. dropdown:: How do I add introductory text to chapters?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
Sometimes chapters have a short preface, like a brief piece of text or a quote to set the stage
|
||||
@@ -92,7 +92,7 @@ Organising Your Text
|
||||
such text. Separating chapter and scene files also allows you to make scene files child
|
||||
documents of the chapter.
|
||||
|
||||
.. dropdown:: Distinguishing Soft and Hard Scene Breaks
|
||||
.. dropdown:: How do I distinguishing between soft and hard scene breaks?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
Depending on your writing style, you may need to separate between soft and hard scene breaks
|
||||
@@ -101,8 +101,8 @@ Organising Your Text
|
||||
In such cases you may want to use different scene headings for hard and soft scene breaks. The
|
||||
**Build Manuscript** tool will let you define a different format for scenes using the ``###``
|
||||
and ``###!`` heading codes when you generate your manuscript. You can for instance add the
|
||||
common "``* * *``" for hard breaks and select to soft scene breaks, which will just insert an
|
||||
empty paragraph in their place. See :ref:`a_manuscript_settings` for more details.
|
||||
common "``* * *``" for hard breaks and select to hide soft scene breaks, which will just insert
|
||||
an empty paragraph in their place. See :ref:`a_manuscript_settings` for more details.
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
@@ -110,7 +110,7 @@ Organising Your Text
|
||||
Other Tools
|
||||
===========
|
||||
|
||||
.. dropdown:: Convert Project to/from yWriter Format
|
||||
.. dropdown:: How do I convert my project to/from the yWriter format?
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
There is a tool available that lets you convert a `yWriter <http://spacejock.com/yWriter7.html>`_
|
||||
|
||||
@@ -39,7 +39,8 @@ your notes about your characters, your world building, and so on.
|
||||
You can at any point split the individual documents by their headings up into multiple documents,
|
||||
or merge multiple documents into a single document. This makes it easier to use variations of the
|
||||
Snowflake_ method for writing. You can start by writing larger structure-focused documents, like
|
||||
for instance one document per act, and later effortlessly split these up into chapters or scenes.
|
||||
for instance one document per act, and later effortlessly split these up into individual chapter or
|
||||
scene documents.
|
||||
|
||||
|
||||
.. _a_intro_features:
|
||||
@@ -53,7 +54,7 @@ Below are some key features of novelWriter.
|
||||
The aim of the user interface is to let you focus on writing instead of spending time formatting
|
||||
text. Formatting is therefore limited to a small set of formatting tags for simple things like
|
||||
text emphasis and paragraph alignment. Additional shortcodes are available for special
|
||||
formatting cases.
|
||||
formatting cases when you need them.
|
||||
|
||||
When you really want to focus on just writing, you can switch the editor into **Focus Mode**
|
||||
where only the text editor panel itself is visible, and the project structure view is hidden
|
||||
@@ -78,19 +79,19 @@ Below are some key features of novelWriter.
|
||||
Your main story text lives in the "Novel" root folder. You can have multiple such folders in a
|
||||
project, and rename them to whatever you want. This allows you to keep a series of individual
|
||||
novels with the same characters and world building in the same project, and create manuscripts
|
||||
for them individually.
|
||||
for them separately.
|
||||
|
||||
**Keep track of your story elements**
|
||||
All notes in your project can be assigned a :term:`tag` that you can then :term:`reference` from
|
||||
any other document or note. In fact, you can add a new tag under each heading of a note if you
|
||||
need to be able to reference specific sections of it, or you want to keep several topics in the
|
||||
same note.
|
||||
All documents in your project can be assigned a :term:`tag` that you can then :term:`reference`
|
||||
from any other document or note. In fact, you can add a new tag under each heading of a note if
|
||||
you need to be able to reference specific sections of it, or you want to keep several topics or
|
||||
scenes in the same document.
|
||||
|
||||
**Get an overview of your story**
|
||||
It is not the documents themselves that define the chapters and scenes of your story, but the
|
||||
headings that separate them. In the **Outline View** on the main window you can see an outline
|
||||
of all the chapter and scene headings of each novel root folder in your project. If they have
|
||||
any references in them, like which character is in what chapter and scene, these are listed in
|
||||
headings within them. In the **Outline View** on the main window you can see an outline of all
|
||||
the chapter and scene headings of each novel root folder in your project. If they have any
|
||||
references in them, like which character is in what chapter and scene, these are listed in
|
||||
additional columns.
|
||||
|
||||
You can also add a synopsis to each chapter or scene, which can be listed here as well. You have
|
||||
@@ -107,9 +108,9 @@ Below are some key features of novelWriter.
|
||||
Whether you want to assemble a manuscript, or export all your notes, or generate an outline of
|
||||
your chapters and scenes with a synopsis included, you can use the **Build Manuscript** tool to
|
||||
do so. The tool lets you select what information you want to include in the generated document,
|
||||
and how it is formatted. You can send the result to a printer or PDF, or generate an Open
|
||||
Document file that can be opened by most office type word processors. You can also generate the
|
||||
result as HTML, or Markdown, both suitable for further conversion to other formats.
|
||||
and how it is formatted. You can send the result to a printer, or generate an Open Document or
|
||||
Word Document file that can be opened by most office type word processors. You can also generate
|
||||
the result as HTML, or Markdown, both suitable for further conversion to other formats.
|
||||
|
||||
|
||||
.. _a_intro_screenshots:
|
||||
|
||||
@@ -5,10 +5,10 @@ What to Read First
|
||||
******************
|
||||
|
||||
The documentation of novelWriter is quite extensive. There are a lot of features to get used to,
|
||||
but you don't need all of them to get started.
|
||||
but you don't need to know all of them to get started.
|
||||
|
||||
The chapters below labelled "Essential Information" are the ones you need to know to use the
|
||||
application correctly. By "correctly", it is meant: in a way so novelWriter understands the basic
|
||||
application correctly. By "correctly" it is meant: in a way so novelWriter understands the basic
|
||||
structure of your text. It collects a lot of information from your text and uses it to display the
|
||||
structure of it in various ways to help you get an overview of your writing.
|
||||
|
||||
@@ -23,7 +23,7 @@ Using novelWriter
|
||||
=================
|
||||
|
||||
In order to use novelWriter effectively, you need to know the basics of how it works. The following
|
||||
chapters will explain the main principles. It starts with the basics, and gets more detailed as you
|
||||
chapters will explain the main principles. They start with the basics, and get more detailed as you
|
||||
read on.
|
||||
|
||||
:ref:`a_breakdown` – Essential Information
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Setup and Installation
|
||||
**********************
|
||||
|
||||
.. _Enchant: https://abiword.github.io/enchant/
|
||||
.. _Enchant: http://rrthomas.github.io/enchant/
|
||||
.. _GitHub: https://github.com/vkbo/novelWriter
|
||||
.. _Downloads page: https://download.novelwriter.io
|
||||
.. _PPA: https://launchpad.net/~vkbo/+archive/ubuntu/novelwriter
|
||||
@@ -15,7 +15,7 @@ Setup and Installation
|
||||
.. _AppImage: https://appimage.org/
|
||||
|
||||
Ready-made packages and installers for novelWriter are available for all major platforms, including
|
||||
Linux, Windows and MacOS, from the `Downloads page`_. See below for install additional instructions
|
||||
Linux, Windows and MacOS, from the `Downloads page`_. See below for additional install instructions
|
||||
for each platform.
|
||||
|
||||
You can also install novelWriter from the Python Package Index (PyPi_). See :ref:`a_started_pip`.
|
||||
@@ -40,12 +40,6 @@ If you have any issues, try uninstalling the previous version and making a fresh
|
||||
already had a version installed via a different method, you should uninstall that first as having
|
||||
multiple installations has been known to cause problems.
|
||||
|
||||
.. note::
|
||||
The novelWriter installer is not signed because Microsoft doesn't currently provide a way for
|
||||
non-profit open source projects to properly sign their installers. The novelWriter project
|
||||
doesn't have the funding to pay for commercial software signing certificates. You will therefore
|
||||
see an additional warning about this when you download and run the installer.
|
||||
|
||||
|
||||
.. _a_started_linux:
|
||||
|
||||
@@ -93,10 +87,6 @@ Then run the update and install commands as for Ubuntu:
|
||||
sudo apt update
|
||||
sudo apt install novelwriter
|
||||
|
||||
.. note::
|
||||
You may need to use the Ubuntu 20.04 (focal) packages for Debian 11 or earlier. The newer Ubuntu
|
||||
packages use a different compression algorithm that may not be supported.
|
||||
|
||||
.. tip::
|
||||
If you get an error message like ``gpg: failed to create temporary file`` when importing the key
|
||||
from the Ubuntu keyserver, try creating the folder it fails on, and import the key again:
|
||||
@@ -142,7 +132,7 @@ done by holding down the option key on your keyboard and clicking on the applica
|
||||
.. note::
|
||||
The novelWriter DMG is not signed because Apple doesn't currently provide a way for non-profit
|
||||
open source projects to properly sign their installers. The novelWriter project doesn't have the
|
||||
funding to pay for commercial software signing certificates.
|
||||
funding to pay for a commercial software signing certificate.
|
||||
|
||||
|
||||
.. _a_started_pip:
|
||||
|
||||
@@ -11,6 +11,7 @@ from the text in your project. All of this is handled by the **Manuscript Build*
|
||||
activate it from the sidebar, the **Tools** menu, or by pressing :kbd:`F5`.
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
This tool is new for version 2.1. A simpler tool was used for earlier versions. The simpler tool
|
||||
only allows you to define a single set of options for the build, but otherwise had much the same
|
||||
functionality.
|
||||
@@ -58,6 +59,7 @@ Each build definition can be edited by opening it in the **Manuscript Build Sett
|
||||
either by double-clicking or by selecting it and pressing the edit button in the toolbar.
|
||||
|
||||
.. tip::
|
||||
|
||||
You can keep the **Manuscript Build Settings** dialog open while testing the different options,
|
||||
and just hit the :guilabel:`Apply` button. You can test the result of your settings by pressing
|
||||
the :guilabel:`Preview` button in the main **Manuscript Build** window. When you're happy with
|
||||
@@ -177,21 +179,34 @@ Open Document Format
|
||||
flat version of the document format as a single XML file. Most rich text editors support the
|
||||
former, and only a few the latter.
|
||||
|
||||
Microsoft Word Document Format
|
||||
The Microsoft Word Document format writes a single ``.docx`` file. It uses a fairly basic format
|
||||
that should be compatible with most rich text editors.
|
||||
|
||||
Portable Document Format (PDF)
|
||||
The PDF is generated from a copy of the preview document, and should have the same formatting
|
||||
capabilities as the preview. It's identical to what is produced if you select the print option
|
||||
and print to PDF.
|
||||
|
||||
novelWriter HTML
|
||||
The HTML format writes a single ``.htm`` file with minimal style formatting. The HTML document
|
||||
is suitable for further processing by document conversion tools like Pandoc_, for importing in
|
||||
word processors, or for printing from browser.
|
||||
|
||||
Standard/Extended Markdown
|
||||
The Markdown format comes in both Standard and Extended flavour. The *only* difference in terms
|
||||
of novelWriter functionality is the support for strike through text, which is not supported by
|
||||
the Standard flavour.
|
||||
|
||||
novelWriter Markup
|
||||
This is simply a concatenation of the project documents selected by the filters into a ``.txt``
|
||||
file. The documents are stacked together in the order they appear in the project tree, with
|
||||
comments, tags, etc. included if they are selected. This is a useful format for exporting the
|
||||
project for later import back into novelWriter.
|
||||
|
||||
Standard/Extended Markdown
|
||||
The Markdown format comes in both Standard and Extended flavour. The *only* difference in terms
|
||||
of novelWriter functionality is the support for strike through text, which is not supported by
|
||||
the Standard flavour.
|
||||
.. versionadded:: 2.6
|
||||
|
||||
Microsoft Word and PDF output options were added.
|
||||
|
||||
|
||||
Additional Formats
|
||||
@@ -211,13 +226,14 @@ file can be imported directly into a Python dict object or a PHP array, to menti
|
||||
|
||||
.. _a_manuscript_print:
|
||||
|
||||
Print and PDF
|
||||
=============
|
||||
Printing
|
||||
========
|
||||
|
||||
The :guilabel:`Print` button allows you to print the content in the preview window. You can either
|
||||
print to one of your system's printers, or select PDF as your output format from the printer icon
|
||||
on the print dialog.
|
||||
|
||||
.. note::
|
||||
|
||||
The paper format should in all cases default to whatever your system default is. If you want to
|
||||
change it, you have to select it from the **Print Preview** dialog.
|
||||
|
||||
@@ -115,19 +115,17 @@ Root Folder Types
|
||||
options. Tags in this folder type can be references using the ``@custom`` keyword.
|
||||
|
||||
The root folders are closely tied to the tags and reference system. Each folder type corresponds to
|
||||
the categories of tags that can be used to reference them. For more information about the tags
|
||||
listed, see :ref:`a_references_references`.
|
||||
categories of tags that can be used to reference them. For more information about the tags listed,
|
||||
see :ref:`a_references_references`.
|
||||
|
||||
There is also a ``@mention`` keyword that can be used to reference any tag.
|
||||
See :ref:`a_references_references` for more details.
|
||||
|
||||
.. note::
|
||||
|
||||
You can rename root folders to whatever you want. However, this doesn't change the reference
|
||||
keyword or what they do.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
As of version 2.0, you can make multiple root folders of each kind to split up your project.
|
||||
|
||||
|
||||
.. _a_proj_roots_del:
|
||||
|
||||
@@ -170,11 +168,10 @@ The folders are there purely as a way for you to organise the documents in meani
|
||||
to be able to collapse and hide them in the project tree when you're not working on those
|
||||
documents.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
As of version 2.0 it is possible to add child documents to other documents. This is particularly
|
||||
useful when you create chapters and scenes. If you add separate scene documents, you should also
|
||||
add separate chapter documents, even if they only contain a chapter heading. You can then add
|
||||
scene documents as child items to the chapters.
|
||||
In addition to using folders. it is also possible to add child documents to other documents. This
|
||||
is particularly useful when you create chapters and scenes. If you add separate scene documents,
|
||||
you should also add separate chapter documents, even if they only contain a chapter heading. You
|
||||
can then add scene documents as child items to the chapters.
|
||||
|
||||
|
||||
.. _a_proj_roots_orphaned:
|
||||
@@ -185,7 +182,7 @@ Recovered Documents
|
||||
If novelWriter crashes or otherwise exits without saving the project state, or if you're using a
|
||||
file synchronisation tool that runs out of sync, there may be files in the project storage folder
|
||||
that aren't tracked in the core project file. These files, when discovered, are recovered and added
|
||||
back into the project.
|
||||
back into the project when a project is opened.
|
||||
|
||||
The discovered files are scanned for metadata that give clues as to where the document may
|
||||
previously have been located in the project. The project loading routine will try to put them back
|
||||
@@ -205,19 +202,21 @@ be named after its internal key, which is a string of characters and numbers.
|
||||
Project Lockfile
|
||||
----------------
|
||||
|
||||
To prevent lost documents caused by file conflicts when novelWriter projects are synchronised via
|
||||
file synchronisation tools, a project lockfile is written to the project storage folder when a
|
||||
project is open. If you try to open a project which already has such a file present, you will be
|
||||
presented with a warning, and some information about where else novelWriter thinks the project is
|
||||
also open. You will be given the option to ignore this warning, and continue opening the project at
|
||||
your own risk.
|
||||
To prevent data loss caused by file conflicts when novelWriter projects are synchronised via file
|
||||
synchronisation tools, a project lockfile is written to the project storage folder when a project
|
||||
is open. If you try to open a project which already has such a file present, you will be presented
|
||||
with a warning, and some information about where else novelWriter thinks the project is also open.
|
||||
You will be given the option to ignore this warning, and continue opening the project at your own
|
||||
risk.
|
||||
|
||||
.. note::
|
||||
|
||||
If, for some reason, novelWriter or your computer crashes, the lock file may remain even if
|
||||
there are no other instances keeping the project open. In such a case it is safe to ignore the
|
||||
lock file warning when re-opening the project.
|
||||
|
||||
.. warning::
|
||||
|
||||
If you choose to ignore the warning and continue opening the project, and multiple instances of
|
||||
the project are in fact open, you are likely to cause inconsistencies and create diverging
|
||||
project files, potentially resulting in loss of data and orphaned files. You are not likely to
|
||||
@@ -318,9 +317,14 @@ use these to indicate at what stage of completion each novel document is, or how
|
||||
content of a note is to the story. You don't have to use them this way, that's just what they were
|
||||
intended for, but you can make them whatever you want.
|
||||
|
||||
Both status and importance labels can be exported and imported so you can share them between
|
||||
projects, or define a standard set for all your writing projects. When you import labels to a
|
||||
project, they are always added as *new* labels.
|
||||
|
||||
See also :ref:`a_ui_tree_status`.
|
||||
|
||||
.. note::
|
||||
|
||||
The status or importance level currently in use by one or more documents cannot be deleted, but
|
||||
they can be edited.
|
||||
|
||||
@@ -384,7 +388,22 @@ also export the filtered data to a JSON file or to a CSV file that can be opened
|
||||
application like for instance Libre Office Calc or Excel.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
As of version 1.2, the log file also stores how much of the session time was spent idle. The
|
||||
definition of idle here is that the novelWriter main window loses focus, or the user hasn't made
|
||||
any changes to the currently open document in five minutes. The number of minutes can be altered
|
||||
in **Preferences**.
|
||||
|
||||
|
||||
Session Timer
|
||||
-------------
|
||||
|
||||
A session timer is by default visible in the status bar. The icon will show you a clock icon when
|
||||
you are active, and a pause icon when you are considered "idle" per the criteria mentioned above.
|
||||
|
||||
If you do not wish to see the timer, you can click on it once to hide it. The icon will still be
|
||||
visible. Click the icon once more to display the timer again.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
As of version 2.6, clicking the timer text or icon in the status bar will toggle its visibility.
|
||||
|
||||
@@ -15,8 +15,9 @@ applications. It is therefore not always obvious to new users how this is suppos
|
||||
this chapter hopes to explain in more detail how to use this tags and references system.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you find the Tags and Reference system difficult to follow just from reading this chapter,
|
||||
you can create a new project in the **Welcome** dialog's New project form and select "Create an
|
||||
you can create a new project in the **Welcome** dialog's New project form and select "Create an
|
||||
example project" from the "Pre-fill project" option. The example project contains several
|
||||
examples of tags and references.
|
||||
|
||||
@@ -39,7 +40,8 @@ documents up using the document split feature. See :ref:`a_ui_tree_split_merge`
|
||||
You can do the same with your notes. You can treat each heading as an independent element of your
|
||||
notes that can be referenced somewhere else. That way you can collect all your minor or background
|
||||
characters in a single note file, and still be able to reference them individually by separating
|
||||
them with headings and assigning each a tag.
|
||||
them with headings and assigning each a tag. Or, you can lay out your plot in a single document and
|
||||
have a tag for each plot stage under separate headings.
|
||||
|
||||
|
||||
.. _a_references_tags:
|
||||
@@ -82,13 +84,20 @@ to the manuscript, or an outline document. If you want to compile a single docum
|
||||
notes, you can do this from the **Manuscript Build** tool.
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
Tags are no longer case sensitive. The tags are by default displayed with the capitalisation you
|
||||
use when defining the tag, but you don't have to use the same capitalisation when referencing
|
||||
it later.
|
||||
|
||||
.. versionadded:: 2.3
|
||||
|
||||
Tags can have an optional display name for manuscript builds.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
You can now add tags also to Novel Documents. These can be used for cross-referencing between
|
||||
chapters and scenes, and also from notes if desired.
|
||||
|
||||
Example of a heading with a tag for a character of the story:
|
||||
|
||||
.. code-block:: md
|
||||
@@ -168,15 +177,21 @@ reference keywords allow multiple values.
|
||||
it. This can be useful when checking for consistency later. Any tag in any root note folder can
|
||||
be listed under mentions.
|
||||
|
||||
``@story``
|
||||
This is used when referencing a Novel Document, like a scene or chapter, from somewhere else in
|
||||
your project.
|
||||
|
||||
The syntax highlighter will alert the user that the tags and references are used correctly, and
|
||||
that the tags referenced exist.
|
||||
|
||||
.. note::
|
||||
|
||||
The highlighter may be mistaken if the index of defined tags is out of date. If so, press
|
||||
:kbd:`F9` to regenerate it, or select **Rebuild Index** from the **Tools** menu. In general, the
|
||||
index for a document is regenerated when it is saved, so this shouldn't normally be necessary.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you add a reference in the editor to a tag that doesn't yet exist, you can right-click it and
|
||||
select **Create Note for Tag**. This will generate a new project note automatically with the new
|
||||
tag defined. In order for this to be possible, a root folder for that category of references
|
||||
@@ -192,6 +207,7 @@ meaningful if you want to be able to click-navigate between them, or of course i
|
||||
highlight that two notes are related.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you cross-reference between notes and export your project as an HTML document using the
|
||||
**Manuscript Build** tool, the cross-references become clickable links in the exported HTML
|
||||
document as well.
|
||||
|
||||
@@ -11,8 +11,8 @@ Active novel documents can only live in a **Novel** type root folder. You can al
|
||||
**Archive** and **Trash** of course, where they become inactive.
|
||||
|
||||
The project tree can distinguish between the different heading levels of the novel documents using
|
||||
coloured icons, and optionally add emphasis on the label, set in **Preferences** for easier
|
||||
identification.
|
||||
coloured icons, and optionally add emphasis on the label. Emphasis can be enabled in
|
||||
**Preferences**.
|
||||
|
||||
|
||||
.. _a_struct_heads:
|
||||
@@ -27,6 +27,7 @@ Four levels of headings are supported, signified by the number of hashes (``#``)
|
||||
title. See also the :ref:`a_fmt` section for more details about the markup syntax.
|
||||
|
||||
.. note::
|
||||
|
||||
The heading levels are not only important when generating the manuscript, they are also used by
|
||||
the indexer when building the outline tree in the **Outline View** as well as in the **Novel
|
||||
Tree**. Each heading also starts a new region where new Tags and References can be defined. See
|
||||
@@ -60,16 +61,25 @@ The syntax for the four basic heading types, and the three special types, is lis
|
||||
mid-scene, like if you change the point-of-view character. You are free to use sections as you
|
||||
wish, and you can filter them out of the final manuscript.
|
||||
|
||||
Page breaks can be automatically added before partition, chapter and scene headings from the
|
||||
**Manuscript Build** tool when you build your project to a format that supports page breaks. If you
|
||||
want page breaks in other places, you have to specify them manually. See :ref:`a_fmt_break`.
|
||||
Page breaks can be automatically added before titles, partition, chapter and scene headings from
|
||||
the **Manuscript Build** tool when you build your project to a format that supports page breaks. If
|
||||
you want page breaks in other places, you have to specify them manually. See :ref:`a_fmt_break`.
|
||||
|
||||
.. tip::
|
||||
|
||||
There are multiple options of how to process novel headings when building the manuscript. For
|
||||
instance, chapter numbers can be applied automatically, and so can scene numbers if you want
|
||||
them in a draft manuscript. You can also insert point-of-view character names in chapter titles.
|
||||
See the :ref:`a_manuscript` page for more details.
|
||||
|
||||
.. note::
|
||||
|
||||
As of 2.6, the heading levels internally in novelWriter do not map directly to heading levels in
|
||||
manuscript documents. In manuscript documents, chapters are considered the top level heading,
|
||||
and partitions become plain text paragraphs with a larger font.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
|
||||
.. _a_struct_heads_title:
|
||||
|
||||
@@ -77,15 +87,28 @@ Novel Title and Front Matter
|
||||
----------------------------
|
||||
|
||||
It is recommended that you add a document at the very top of each **Novel** root folder with the
|
||||
novel title as the first line. You should modify the level 1 heading format code with an ``!`` in
|
||||
order to render it as a document title that is excluded from any automatic Table of Content in a
|
||||
manuscript build document, like so:
|
||||
novel title in it. You should modify the level 1 heading format code with an ``!`` in order to
|
||||
render it as a document title that is excluded from any automatic Table of Content in a manuscript
|
||||
build document.
|
||||
|
||||
You can also add the author name and address above this if this is required by the manuscript
|
||||
format you use, and additional space added before the title.
|
||||
|
||||
This is the title page novelWriter generates automatically for a new project as of version 2.6:
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
Jane Doe[br]
|
||||
Address 1[br]
|
||||
Address 2 <<
|
||||
|
||||
[vspace:5]
|
||||
|
||||
#! My Novel
|
||||
|
||||
>> _by Jane Doe_ <<
|
||||
>> **By Jane Doe** <<
|
||||
|
||||
>> Word Count: [field:textWords] <<
|
||||
|
||||
The title is by default centred on the page. You can add more text to the page as you wish, like
|
||||
for instance the author's name and details.
|
||||
|
||||
@@ -7,6 +7,8 @@ How it Works
|
||||
.. _Fusion: https://doc.qt.io/qt-6/gallery.html
|
||||
.. _Pandoc: https://pandoc.org/
|
||||
.. _Open Document: https://en.wikipedia.org/wiki/OpenDocument
|
||||
.. _Office Open XML: https://en.wikipedia.org/wiki/Office_Open_XML
|
||||
.. _version control: https://en.wikipedia.org/wiki/Version_control
|
||||
|
||||
The main features of novelWriter are listed in the :ref:`a_intro` chapter. In this chapter, we go
|
||||
into some more details on how they are implemented. This is intended as an overview. Later on in
|
||||
@@ -42,9 +44,10 @@ views you can switch between, a quick link to the **Build Manuscript** tool, and
|
||||
project-related tools and quick access to settings at the bottom.
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
A number of new formatting options were added in 2.2 to allow for some special formatting cases.
|
||||
At the same time, a small formatting toolbar was added to the editor. It is hidden by default,
|
||||
but can be opened by pressing the button in the top right corner of the editor header.
|
||||
but can be opened by pressing the button in the top--left corner of the editor header.
|
||||
|
||||
|
||||
Project Tree and Editor View
|
||||
@@ -54,9 +57,9 @@ Project Tree and Editor View
|
||||
|
||||
A screenshot of the Project Tree and Editor View.
|
||||
|
||||
When the application is in **Project Tree View** mode, the main work area of the main window is
|
||||
split in two, or optionally three, panels. The left-most panel contains the project tree and all
|
||||
the documents in your project. The second panel is the document editor.
|
||||
When the application is in **Project Tree View** mode, the work area of the main window is split in
|
||||
two, or optionally three, panels. The left-most panel contains the project tree and all the
|
||||
documents in your project. The second panel is the document editor.
|
||||
|
||||
An optional third panel on the right side contains a document viewer which can view any document in
|
||||
your project independently of what is open in the document editor. This panel is not intended as a
|
||||
@@ -68,6 +71,14 @@ The editor also has a **Focus Mode** you can toggle either from the menu, from t
|
||||
editor's header, or by pressing :kbd:`F8`. When **Focus Mode** is enabled, all the user interface
|
||||
elements other than the document editor itself are hidden away.
|
||||
|
||||
The project tree will highlight with a different background colour the document that is currently
|
||||
open in the editor.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
You can now drag and drop documents from the project tree onto the editor or viewer panels to
|
||||
open them.
|
||||
|
||||
|
||||
Novel View and Editor View
|
||||
--------------------------
|
||||
@@ -110,21 +121,20 @@ Novel Outline View
|
||||
|
||||
A screenshot of the Novel Outline View.
|
||||
|
||||
When the application is in **Novel Outline View** mode, the tree, editor and viewer will be
|
||||
replaced by a large table that shows the entire novel structure with all the tags and references
|
||||
listed. Pretty much all collected meta data is available here in different columns.
|
||||
When the application is in **Novel Outline View** mode, the tree, editor and viewer are replaced by
|
||||
a large table that shows the entire novel structure with all the tags and references listed. Pretty
|
||||
much all collected meta data is available here in different columns.
|
||||
|
||||
You can select which novel root folder to display from the dropdown box, and you can select which
|
||||
columns to show or hide from the menu button. You can also rearrange the columns by drag and drop.
|
||||
The app will remember your column order and size between sessions, and for each individual project.
|
||||
The app remembers your column order and sizes between sessions, and for each individual project.
|
||||
|
||||
|
||||
Colour Themes
|
||||
-------------
|
||||
|
||||
By default, novelWriter will use the colour theme provided by the Qt library, which is determined
|
||||
by the Fusion_ style setting. You can also choose between a standard dark and light theme that have
|
||||
neutral colours from **Preferences**.
|
||||
By default, novelWriter uses a light colour theme. You can also choose between a standard dark
|
||||
theme that have neutral colours, or a series of other included themes, from **Preferences**.
|
||||
|
||||
If you wish, you *can* create your own colour themes, and even have them added to the application.
|
||||
See :ref:`a_custom_theme` for more details.
|
||||
@@ -134,6 +144,7 @@ separate colour selectable from the "Document colour theme" setting in **Prefere
|
||||
separated because there are a lot more options to choose from for the editor and viewer.
|
||||
|
||||
.. note::
|
||||
|
||||
If you switch between light and dark mode on the GUI, you should also switch editor theme to
|
||||
match, otherwise icons may be hard to see in the editor and viewer.
|
||||
|
||||
@@ -155,11 +166,11 @@ If the project or novel view does not have focus, pressing :kbd:`Ctrl+T` switche
|
||||
whichever of the two is visible. If one of them already has focus, the key press will switch
|
||||
between them instead.
|
||||
|
||||
Likewise, pressing :kbd:`Ctrl+E` with switch focus to the document editor or viewer, or if any of
|
||||
Likewise, pressing :kbd:`Ctrl+E` will switch focus to the document editor or viewer, or if any of
|
||||
them already have focus, it will switch focus between them,
|
||||
|
||||
These two shortcuts makes it possible to jump between all these GUI elements without having to
|
||||
reach for the mouse or touchpad.
|
||||
These two shortcuts make it possible to jump between all these GUI elements without having to reach
|
||||
for the mouse or touchpad.
|
||||
|
||||
|
||||
.. _a_breakdown_project:
|
||||
@@ -167,7 +178,7 @@ reach for the mouse or touchpad.
|
||||
Project Layout
|
||||
==============
|
||||
|
||||
This is a brief introduction to how you structure your writing projects. All of this will be
|
||||
This is a brief introduction to how you should structure your writing projects. All of this will be
|
||||
covered in more detail later.
|
||||
|
||||
The main point of novelWriter is that you are free to organise your project documents as you wish
|
||||
@@ -193,12 +204,19 @@ This heading level structure is only taken into account for :term:`novel documen
|
||||
:term:`project notes`, the heading levels have no structural meaning, and you are free to use them
|
||||
however you want. See :ref:`a_struct` and :ref:`a_references` for more details.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
.. tip::
|
||||
|
||||
You can add documents as child items of other documents. This is often more useful than adding
|
||||
folders, since you anyway may want to have the chapter heading in a separate document from your
|
||||
individual scene documents so that you can rearrange scene documents freely without affecting
|
||||
chapter placement.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
The heading levels for partitions, chapters and scenes only apply within novelWriter. When you
|
||||
generate your manuscript, chapters are considered as the topmost heading level, with scenes
|
||||
below it. Partitions are inserted as text elements in most formats.
|
||||
|
||||
|
||||
.. _a_breakdown_export:
|
||||
|
||||
@@ -206,22 +224,24 @@ Building a Manuscript
|
||||
=====================
|
||||
|
||||
The project can at any time be assembled into a range of different formats through the
|
||||
**Build Manuscript** tool. Natively, novelWriter supports `Open Document`_, HTML5, and
|
||||
various flavours of Markdown.
|
||||
**Build Manuscript** tool. Natively, novelWriter supports `Open Document`_, Microsoft Word Document
|
||||
(known as `Office Open XML`_), HTML5, and various flavours of Markdown. You can also generate a PDF
|
||||
document.
|
||||
|
||||
The HTML5 format is suitable for conversion by a number of other tools like Pandoc_, or for
|
||||
importing into word processors if the Open Document format isn't suitable. The Open Document format
|
||||
is supported by most office type applications. In addition, printing is also possible. Print to PDF
|
||||
is available from the print dialog.
|
||||
importing into word processors if the Open Document or Word Document format isn't suitable. The
|
||||
Open Document format is supported by most office type applications, so is the Word Document format.
|
||||
In addition, printing is also possible.
|
||||
|
||||
For advanced processing, you can export the content of the project to a JSON file. This is useful
|
||||
if you want to write your own custom processing script in for instance Python, as the entire novel
|
||||
can be read into a Python dictionary with a couple of lines of code. The JSON file can be populated
|
||||
with either HTML formatted text, or with the raw text as typed into the novel documents.
|
||||
with either HTML formatted text, or with the raw text as typed it into the novel documents.
|
||||
|
||||
See :ref:`a_manuscript` for more details.
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
You can now define multiple build definitions in the **Build Manuscript** tool. This allows you
|
||||
to define specific settings for various types of draft documents, outline documents, and
|
||||
manuscript formats. See :ref:`a_manuscript` for more details.
|
||||
@@ -234,8 +254,8 @@ Project Storage
|
||||
|
||||
The files of a novelWriter project are stored in a dedicated project folder. The project structure
|
||||
is kept in a file at the root of this folder called ``nwProject.nwx``. All the document files and
|
||||
associated meta data is stored in other folders below the project folder. For more technical
|
||||
details about what all the files mean and how they're organised, see the :ref:`a_storage` section.
|
||||
associated meta data are stored in other folders below the project folder. For a more technical
|
||||
description of what all the files mean and how they're organised, see the :ref:`a_storage` section.
|
||||
|
||||
This way of storing data was chosen for several reasons.
|
||||
|
||||
@@ -247,17 +267,19 @@ crashes.
|
||||
Secondly, having multiple small files means it is very easy to synchronise them between computers
|
||||
with standard file synchronisation tools.
|
||||
|
||||
Thirdly, if you use version control software to track the changes to your project, the file formats
|
||||
used for the files are well suited. All the JSON documents have line breaks and indents as well,
|
||||
which makes it easier to track them with version control software.
|
||||
Thirdly, if you use `version control`_ software to track the changes to your project, the file
|
||||
formats used for the files are well suited. All the JSON documents have line breaks and indents as
|
||||
well, which makes it easier to track them with version control software.
|
||||
|
||||
.. note::
|
||||
|
||||
Since novelWriter has to keep track of a bunch of files and folders when a project is open, it
|
||||
may not run well on some virtual file systems. A file or folder must be accessible with exactly
|
||||
the path it was saved or created with. An example where this is not the case is the way Google
|
||||
Drive is mapped on Linux Gnome desktops using gvfs/gio.
|
||||
|
||||
.. caution::
|
||||
|
||||
You should not add additional files to the project folder yourself. Nor should you, as a rule,
|
||||
manually edit files within it. If you really must manually edit the text files, e.g. with some
|
||||
automated task you want to perform, you need to rebuild the :term:`Project Index` when you open
|
||||
|
||||
@@ -14,6 +14,10 @@ In addition to formatting codes, novelWriter allows for comments, a synopsis tag
|
||||
keyword and value sets used for :term:`tags<tag>` and :term:`references<reference>`. There are also
|
||||
some codes that apply to whole paragraphs. See :ref:`a_fmt_text` for more details.
|
||||
|
||||
URLs should also be highlighted and become clickable. However, only URLs starting with "http" or
|
||||
"https" are recognised. In the editor, you must hold down the :kbd:`Ctrl` key when clicking a URL
|
||||
to follow it.
|
||||
|
||||
|
||||
.. _a_fmt_hlight:
|
||||
|
||||
@@ -76,14 +80,13 @@ For headings level one through three, adding a ``!`` modifies the meaning of the
|
||||
|
||||
``#! Title Text``
|
||||
This tells the build tool that the level one heading is intended to be used for the novel or
|
||||
notes folder's main title, like for instance on the front page. When building the manuscript,
|
||||
this will use a different styling and will exclude the title from, for instance, a Table of
|
||||
Contents in Libre Office.
|
||||
notes folder's main title, like for instance the novel title on the cover page. When building
|
||||
the manuscript, this will use a different styling.
|
||||
|
||||
``##! Title Text``
|
||||
This tells the build tool to not assign a chapter number to this chapter title if automatic
|
||||
chapter numbers are being used. Such titles are useful for a prologue for instance. See
|
||||
:ref:`a_struct_heads_unnum` for more details.
|
||||
chapter numbers are being used. Such titles are useful for prologues and epilogues for instance.
|
||||
See :ref:`a_struct_heads_unnum` for more details.
|
||||
|
||||
``###! Title Text``
|
||||
This is an alternative scene heading that can be formatted differently in the **Manuscript
|
||||
@@ -92,6 +95,7 @@ For headings level one through three, adding a ``!`` modifies the meaning of the
|
||||
details.
|
||||
|
||||
.. note::
|
||||
|
||||
The space after the ``#`` or ``!`` character is mandatory. The syntax highlighter will change
|
||||
colour and font size when the heading is correctly formatted.
|
||||
|
||||
@@ -118,10 +122,18 @@ Non-breaking spaces are highlighted by the syntax highlighter with an alternate
|
||||
background, depending on the selected theme.
|
||||
|
||||
.. tip::
|
||||
|
||||
Non-breaking spaces are for instance the correct type of space to separate a number from its
|
||||
unit. Generally, non-breaking spaces are used to prevent line wrapping algorithms from adding
|
||||
line breaks where they shouldn't.
|
||||
|
||||
.. note::
|
||||
|
||||
You should not manually apply text indentation in your paragraphs in the editor. These can be
|
||||
added automatically in the **Manuscript Build** tool if you want to have them in the manuscript.
|
||||
Each new paragraph should be separated from the previous content by an empty line and with no
|
||||
indentation.
|
||||
|
||||
|
||||
.. _a_fmt_emph:
|
||||
|
||||
@@ -160,6 +172,7 @@ In addition, the following rules apply:
|
||||
allow for formatting, and any formatting markup will be rendered as-is.
|
||||
|
||||
.. tip::
|
||||
|
||||
novelWriter supports standard escape syntax for the emphasis markup characters in case the
|
||||
editor misunderstands your intended usage of them. That is, ``\*``, ``\_`` and ``\~`` will
|
||||
generate a plain ``*``, ``_`` and ``~``, respectively, without interpreting them as part of the
|
||||
@@ -216,8 +229,8 @@ In addition to the above formatting features, novelWriter also allows for commen
|
||||
The text of a comment is always ignored by the word counter. The text can also be filtered out
|
||||
when building the manuscript or viewing the document.
|
||||
|
||||
The first word of a comment, followed by a colon, can be one of a small set of modifiers that
|
||||
indicates the comment is intended for a specific purpose. For instance, if the comment starts with
|
||||
The first word of a comment, followed by a colon, can be one of a set of modifiers that indicates
|
||||
the comment is intended for a specific purpose. For instance, if the comment starts with
|
||||
``Synopsis:``, the comment is treated in a special manner and will show up in the
|
||||
:ref:`a_ui_outline` in a dedicated column. The word ``synopsis`` is not case sensitive. If it is
|
||||
correctly formatted, the syntax highlighter will indicate this by altering the colour of the word.
|
||||
@@ -246,6 +259,7 @@ The different styles of comments are as follows:
|
||||
use them in your text.
|
||||
|
||||
.. note::
|
||||
|
||||
Only one comment can be flagged as a synopsis or short comment for each heading. If multiple
|
||||
comments are flagged as synopsis or short comments, the last one will be used and the rest
|
||||
ignored.
|
||||
@@ -365,6 +379,7 @@ Examples:
|
||||
"``> Left/right indented text <``", "The text has both margins increased."
|
||||
|
||||
.. note::
|
||||
|
||||
The text editor will not show the alignment and indentation live. But the viewer will show them
|
||||
when you open the document there. It will of course also be reflected in the document generated
|
||||
from the manuscript build tool as long as the format supports paragraph alignment.
|
||||
@@ -373,18 +388,15 @@ Examples:
|
||||
Alignment with Line Breaks
|
||||
--------------------------
|
||||
|
||||
If you have line breaks in the paragraph, like for instance when you are writing verses, the
|
||||
alignment markers must be applied to the first line. Markers on the other lines are ignored. The
|
||||
markers for the first line are used for all the other lines.
|
||||
|
||||
For the following text, all lines will be centred, not just the first:
|
||||
If you have line breaks in the paragraph, the markers for all the lines are combined and used for
|
||||
the entire paragraph. For the following text, all lines will be centred:
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
>> I am the very model of a modern Major-General <<
|
||||
>> I am the very model of a modern Major-General
|
||||
I've information vegetable, animal, and mineral
|
||||
I know the kings of England, and I quote the fights historical
|
||||
From Marathon to Waterloo, in order categorical
|
||||
From Marathon to Waterloo, in order categorical <<
|
||||
|
||||
|
||||
Alignment with First Line Indent
|
||||
@@ -424,6 +436,7 @@ If you need to add a page break somewhere, put the text ``[new page]`` on a line
|
||||
the text you wish to start on a new page.
|
||||
|
||||
.. note::
|
||||
|
||||
The page break code is applied to the text that follows it. It adds a "page break before" mark
|
||||
to the text when exporting to HTML or Open Document. This means that a ``[new page]`` which has
|
||||
no text following it, it will not result in a page break.
|
||||
@@ -442,3 +455,16 @@ the text you wish to start on a new page.
|
||||
[new page]
|
||||
|
||||
This text will start on a new page if the build format has pages.
|
||||
|
||||
|
||||
.. _a_fmt_stats:
|
||||
|
||||
Inserting Word Counts in the Text
|
||||
=================================
|
||||
|
||||
The cover page of a manuscript normally has the word count stated on it. Any statistics value
|
||||
collected by novelWriter can be inserted into any document. You can generate the code for this from
|
||||
the **Insert** menu under **Word/Character Count**.
|
||||
|
||||
The value inserted is the actual count for your entire manuscript, so it is not populated until you
|
||||
run the **Manuscript Build** tool. Until then they will show up as "0" in the viewer panel.
|
||||
|
||||
@@ -63,6 +63,7 @@ currently selected item. This panel also includes the latest paragraph and chara
|
||||
addition to the word count.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you want to set the label of a document to be the same as a header within it, you can
|
||||
right-click a header in the document when it is open in the editor and select
|
||||
:guilabel:`Set as Document Name` from the context menu.
|
||||
@@ -140,23 +141,19 @@ lives in. If it's in a **Novel** type folder, it uses the "Status" flag, otherwi
|
||||
Project Tree Drag & Drop
|
||||
------------------------
|
||||
|
||||
The project tree allows drag & drop to a certain extent to allow you to reorder your documents and
|
||||
folders. Moving a document in the project tree will affect the text's position when you assemble
|
||||
your manuscript in the **Manuscript Build** tool.
|
||||
The project tree allows drag & drop to allow you to reorder your documents and folders. Moving a
|
||||
document in the project tree will affect the text's position when you assemble your manuscript in
|
||||
the **Manuscript Build** tool.
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
You can now select multiple items in the project tree by holding down the :kbd:`Ctrl` or
|
||||
:kbd:`Shift` key while selecting items.
|
||||
|
||||
You can drag and drop documents and regular folders, but not root folders. If you select multiple
|
||||
items, they can only be dragged and dropped if they are siblings. That is, they have the same
|
||||
parent item in the project. This limitation is due to the way drag and drop is implemented in the
|
||||
user interface framework novelWriter is built upon.
|
||||
|
||||
Documents and their folders can be rearranged freely within their root folders. If you move a
|
||||
**Novel Document** out of a **Novel** folder, it will be converted to a **Project Note**. Notes can
|
||||
be moved freely between all root folders, but keep in mind that if you move a note into a **Novel**
|
||||
type root folder, its "Importance" setting will be switched with a "Status" setting. See
|
||||
type root folder, its "Importance" setting will be replaced by a "Status" setting. See
|
||||
:ref:`a_ui_tree_status`. The old value will not be overwritten though, and should be restored if
|
||||
you move it back at some point.
|
||||
|
||||
@@ -164,6 +161,10 @@ Root folders in the project tree cannot be dragged and dropped at all. If you wa
|
||||
you can move them up or down with respect to each other from the arrow buttons at the top of the
|
||||
project tree, or by pressing :kbd:`Ctrl+Up` or :kbd:`Ctrl+Down` when they are selected.
|
||||
|
||||
.. tip::
|
||||
|
||||
You can drag and drop documents onto the editor or viewer panel to open them.
|
||||
|
||||
|
||||
.. _a_ui_tree_novel:
|
||||
|
||||
@@ -180,6 +181,7 @@ the view in the **Outline View**. It is convenient when you want to browse the s
|
||||
story itself rather than the document files.
|
||||
|
||||
.. note::
|
||||
|
||||
You cannot reorganise the entries in the novel view, or add any new documents, as that would
|
||||
imply restructuring the content of the document files themselves. Any such editing must be done
|
||||
in the project tree. However, you can add new headings to existing documents, or change
|
||||
@@ -208,6 +210,7 @@ You can select which novel folder to display from the dropdown menu. You can opt
|
||||
to show a combination of all novel folders.
|
||||
|
||||
.. note::
|
||||
|
||||
Since the internal structure of the novel does not depend directly on the folder and document
|
||||
structure of the project tree, this view will not necessarily look the same, depending on how
|
||||
you choose to organise your documents. See the :ref:`a_struct` page for more details.
|
||||
@@ -218,6 +221,7 @@ the menu button in the toolbar. The order of the columns can also be rearranged
|
||||
a different position. You column settings are saved between sessions on a per-project basis.
|
||||
|
||||
.. note::
|
||||
|
||||
The **Title** column cannot be disabled or moved.
|
||||
|
||||
The information viewed in the outline is based on the :term:`project index`. While novelWriter does
|
||||
|
||||
@@ -18,10 +18,10 @@ Editing a Document
|
||||
|
||||
A screenshot of the Document Editor panel.
|
||||
|
||||
To edit a document, double-click it in the project tree, or press the :kbd:`Return` key while
|
||||
having it selected. This will open the document in the document editor. The editor uses a
|
||||
Markdown-like syntax for some features, and a novelWriter-specific syntax for others. The syntax
|
||||
format is described in the :ref:`a_fmt` chapter.
|
||||
To edit a document, double-click it in the project tree, press the :kbd:`Return` key while having
|
||||
it selected, or drag and drop it onto the editor panel. This will open the document in the document
|
||||
editor. The editor uses a Markdown-like syntax for some features, and a novelWriter-specific syntax
|
||||
for others. The syntax format is described in the :ref:`a_fmt` chapter.
|
||||
|
||||
The editor has a maximise button, which toggles the **Focus Mode**, and a close button in the
|
||||
top--right corner. On the top--left side you will find a tools button that opens a toolbar with a
|
||||
@@ -33,6 +33,7 @@ header at the top of the edit or view panel. Optionally, the full project path t
|
||||
be shown. This can be set in **Preferences**.
|
||||
|
||||
.. tip::
|
||||
|
||||
Clicking on the document title bar will select the document in the project tree and thus reveal
|
||||
its location there, making it easier to find in a large project.
|
||||
|
||||
@@ -79,14 +80,14 @@ Viewing a Document
|
||||
A screenshot of the Document Viewer panel.
|
||||
|
||||
Any document in the project tree can also be viewed in parallel in a right hand side document
|
||||
viewer. To view a document, press :kbd:`Ctrl+R`, or select **View Document** in the menu or context
|
||||
menu. If you have a middle mouse button, middle-clicking on the document will also open it in the
|
||||
viewer.
|
||||
viewer. To view a document, press :kbd:`Ctrl+R`, select **View Document** in the menu or context
|
||||
menu, or drag and drop the document onto the viewer panel. If you have a middle mouse button,
|
||||
middle-clicking on the document will also open it in the viewer.
|
||||
|
||||
The document viewed does not have to be the same document as the one currently being edited.
|
||||
However, If you *are* viewing the same document, pressing :kbd:`Ctrl+R` again will update the
|
||||
document with your latest changes. You can also press the reload button in the top--right corner of
|
||||
the viewer panel, next to the close button, to achieve the same thing.
|
||||
However, If you *are* viewing the same document, pressing :kbd:`Ctrl+R` from the editor will update
|
||||
the document with your latest changes. You can also press the reload button in the top--right
|
||||
corner of the viewer panel, next to the close button, to achieve the same thing.
|
||||
|
||||
In the viewer :term:`references<reference>` become clickable links. Clicking them will replace the
|
||||
content of the viewer with the content of the document the reference points to.
|
||||
@@ -95,7 +96,7 @@ The document viewer keeps a history of viewed documents, which you can navigate
|
||||
buttons in the top--left corner of the viewer. If your mouse has backward and forward navigation
|
||||
buttons, these can be used as well. They work just like the backward and forward features in a
|
||||
browser. The left-most button is a dropdown menu for quickly navigation between headings in the
|
||||
document.
|
||||
document. The edit button on the right will open the viewed document in the editor.
|
||||
|
||||
At the bottom of the view panel there is a **References** panel. (If it is hidden, click the button
|
||||
on the left side of the footer area to reveal it.) This panel contains a References tab with links
|
||||
@@ -104,12 +105,14 @@ you have created root folders and tags for various story elements like character
|
||||
these will appear as additional tabs in this panel.
|
||||
|
||||
.. note::
|
||||
|
||||
The **References** panel relies on an up-to-date :term:`index<project index>` of the project.
|
||||
The index is maintained automatically. However, if anything is missing, or seems wrong, the
|
||||
index can always be rebuilt by selecting **Rebuild Index** from the **Tools** menu, or by
|
||||
pressing :kbd:`F9`.
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
The reference panel was redesigned and the additional tabs added.
|
||||
|
||||
|
||||
@@ -136,10 +139,8 @@ document when reaching the end. There is also a switch that will try to match th
|
||||
when the replacement is made. That is, it will try to keep the word upper, lower, or capitalised to
|
||||
match the word being replaced.
|
||||
|
||||
The regular expression search is somewhat dependant on which version of Qt your system has. If you
|
||||
have Qt 5.13 or higher, there is better support for Unicode symbols in the search.
|
||||
|
||||
.. seealso::
|
||||
|
||||
For more information on the capabilities of the Regular Expression option, see the Qt
|
||||
documentation for the `QRegularExpression <https://doc.qt.io/qt-5/qregularexpression.html>`_
|
||||
class.
|
||||
@@ -154,6 +155,7 @@ A few auto-replace features are supported by the editor. You can control every a
|
||||
auto-replace feature from **Preferences**. You can also disable this feature entirely if you wish.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you don't like auto-replacement, all symbols inserted by this feature are also available in
|
||||
the :guilabel:`Insert` menu, and via :ref:`a_kb_ins`. You may also be using a `Compose Key`_
|
||||
setup, which means you may not need the auto-replace feature at all.
|
||||
@@ -165,6 +167,22 @@ always accurate. Especially distinguishing between closing single quote and apos
|
||||
tricky for languages that use the same symbol for these, like English does.
|
||||
|
||||
.. tip::
|
||||
|
||||
If the auto-replace feature changes a symbol when you did not want it to change, pressing
|
||||
:kbd:`Ctrl+Z` once after the auto-replacement will undo it without undoing the character
|
||||
you typed before it.
|
||||
|
||||
|
||||
.. _a_ui_edit_dialogue:
|
||||
|
||||
Dialogue Highlighting
|
||||
=====================
|
||||
|
||||
The editor and viewer can optionally highlight character dialogue in your novel documents. By
|
||||
default, this feature is set to display text in double quotes as dialogue. In **Preferences**, you
|
||||
can change this to support various other dialogue markers that instead uses dashes to indicate
|
||||
dialogue, like those used in Spanish, Portuguese, Polish, etc.
|
||||
|
||||
Various styles are supported by changing the settings under "Text Highlighting" in **Preferences**.
|
||||
|
||||
It is also possible to include the dialogue highlighting in your manuscripts.
|
||||
|
||||
2617
i18n/nw_base.ts
2499
i18n/nw_de_DE.ts
2489
i18n/nw_en_US.ts
2452
i18n/nw_es_419.ts
2452
i18n/nw_fr_FR.ts
2489
i18n/nw_it_IT.ts
2493
i18n/nw_ja_JP.ts
2489
i18n/nw_nb_NO.ts
2452
i18n/nw_nl_NL.ts
2487
i18n/nw_pl_PL.ts
2487
i18n/nw_pt_BR.ts
2452
i18n/nw_ru_RU.ts
2489
i18n/nw_zh_CN.ts
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2018-09-22 [0.0.1] main
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -47,9 +47,9 @@ __license__ = "GPLv3"
|
||||
__author__ = "Veronica Berglyd Olsen"
|
||||
__maintainer__ = "Veronica Berglyd Olsen"
|
||||
__email__ = "code@vkbo.net"
|
||||
__version__ = "2.6b2"
|
||||
__hexversion__ = "0x020600b2"
|
||||
__date__ = "2024-12-23"
|
||||
__version__ = "2.6"
|
||||
__hexversion__ = "0x020600f0"
|
||||
__date__ = "2025-01-26"
|
||||
__status__ = "Stable"
|
||||
__domain__ = "novelwriter.io"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Synopsis",
|
||||
"Short Description": "Kurzbeschreibung",
|
||||
"Footnotes": "Fußnoten",
|
||||
"Comment": "Kommentar",
|
||||
"Notes": "Notizen",
|
||||
"Tag": "Schlagwort",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "Objekte",
|
||||
"Entities": "Organisationen",
|
||||
"Custom": "Benutzerdefiniert",
|
||||
"New Page": "Neue Seite",
|
||||
"0": "Null",
|
||||
"1": "Eins",
|
||||
"2": "Zwei",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Synopsis",
|
||||
"Short Description": "Short Description",
|
||||
"Footnotes": "Footnotes",
|
||||
"Comment": "Comment",
|
||||
"Notes": "Notes",
|
||||
"Tag": "Tag",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "Objects",
|
||||
"Entities": "Entities",
|
||||
"Custom": "Custom",
|
||||
"New Page": "New Page",
|
||||
"0": "Zero",
|
||||
"1": "One",
|
||||
"2": "Two",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Sinossi",
|
||||
"Short Description": "Breve descrizione",
|
||||
"Footnotes": "Note a piè pagina",
|
||||
"Comment": "Commento",
|
||||
"Notes": "Note",
|
||||
"Tag": "Etichetta",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "Oggetti",
|
||||
"Entities": "Enti",
|
||||
"Custom": "Personalizzato",
|
||||
"New Page": "Nuova pagina",
|
||||
"0": "Zero",
|
||||
"1": "Uno",
|
||||
"2": "Due",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "あらすじ",
|
||||
"Short Description": "短い説明",
|
||||
"Footnotes": "脚注",
|
||||
"Comment": "コメント ",
|
||||
"Notes": "ノート",
|
||||
"Tag": "タグ",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "オブジェクト",
|
||||
"Entities": "エンティティ",
|
||||
"Custom": "カスタム",
|
||||
"New Page": "新規ページ",
|
||||
"0": "零",
|
||||
"1": "一",
|
||||
"2": "二",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Sammendrag",
|
||||
"Short Description": "Kort beskrivelse",
|
||||
"Footnotes": "Fotnoter",
|
||||
"Comment": "Kommentar",
|
||||
"Notes": "Notat",
|
||||
"Tag": "Knagg",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "Objekter",
|
||||
"Entities": "Enheter",
|
||||
"Custom": "Annet",
|
||||
"New Page": "Ny side",
|
||||
"0": "null",
|
||||
"1": "én",
|
||||
"2": "to",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Synopsis",
|
||||
"Short Description": "Korte beschrijving",
|
||||
"Footnotes": "Voetnoten",
|
||||
"Comment": "Opmerking",
|
||||
"Notes": "Notities",
|
||||
"Tag": "Label",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "Objecten",
|
||||
"Entities": "Entiteiten",
|
||||
"Custom": "Aangepast",
|
||||
"New Page": "Nieuwe pagina",
|
||||
"0": "nul",
|
||||
"1": "één",
|
||||
"2": "twee",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Streszczenie",
|
||||
"Short Description": "Krótki opis",
|
||||
"Footnotes": "Przypisy",
|
||||
"Comment": "Komentarz",
|
||||
"Notes": "Notatki",
|
||||
"Tag": "Znacznik",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "Obiekty",
|
||||
"Entities": "Podmioty",
|
||||
"Custom": "Różne",
|
||||
"New Page": "Nowa strona",
|
||||
"0": "zero",
|
||||
"1": "pierwszy",
|
||||
"2": "drugi",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Sinopse",
|
||||
"Short Description": "Descrição breve",
|
||||
"Footnotes": "Notas de rodapé",
|
||||
"Comment": "Comentário",
|
||||
"Notes": "Notas",
|
||||
"Tag": "Etiqueta",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "Objetos",
|
||||
"Entities": "Entidades",
|
||||
"Custom": "Outros",
|
||||
"New Page": "Nova página",
|
||||
"0": "Zero",
|
||||
"1": "Um",
|
||||
"2": "Dois",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "概要",
|
||||
"Short Description": "简短描述",
|
||||
"Footnotes": "注释",
|
||||
"Comment": "注释",
|
||||
"Notes": "笔记",
|
||||
"Tag": "标签",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "物品",
|
||||
"Entities": "条目",
|
||||
"Custom": "自定义",
|
||||
"New Page": "新建页面",
|
||||
"0": "零",
|
||||
"1": "一",
|
||||
"2": "二",
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2019-05-12 [0.1.0]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -8,7 +8,7 @@ Created: 2022-11-09 [2.0rc2] RecentProjects
|
||||
Created: 2024-06-16 [2.5rc1] RecentPaths
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -112,7 +112,7 @@ class Config:
|
||||
|
||||
# General GUI Settings
|
||||
self.guiLocale = self._qLocale.name()
|
||||
self.guiTheme = "default" # GUI theme
|
||||
self.guiTheme = "default_light" # GUI theme
|
||||
self.guiSyntax = "default_light" # Syntax theme
|
||||
self.guiFont = QFont() # Main GUI font
|
||||
self.guiScale = 1.0 # Set automatically by Theme class
|
||||
@@ -194,6 +194,7 @@ class Config:
|
||||
# State
|
||||
self.showViewerPanel = True # The panel for the viewer is visible
|
||||
self.showEditToolBar = False # The document editor toolbar visibility
|
||||
self.showSessionTime = True # Show the session time in the status bar
|
||||
self.viewComments = True # Comments are shown in the viewer
|
||||
self.viewSynopsis = True # Synopsis is shown in the viewer
|
||||
|
||||
@@ -674,6 +675,7 @@ class Config:
|
||||
sec = "State"
|
||||
self.showViewerPanel = conf.rdBool(sec, "showviewerpanel", self.showViewerPanel)
|
||||
self.showEditToolBar = conf.rdBool(sec, "showedittoolbar", self.showEditToolBar)
|
||||
self.showSessionTime = conf.rdBool(sec, "showsessiontime", self.showSessionTime)
|
||||
self.viewComments = conf.rdBool(sec, "viewcomments", self.viewComments)
|
||||
self.viewSynopsis = conf.rdBool(sec, "viewsynopsis", self.viewSynopsis)
|
||||
self.searchCase = conf.rdBool(sec, "searchcase", self.searchCase)
|
||||
@@ -784,6 +786,7 @@ class Config:
|
||||
conf["State"] = {
|
||||
"showviewerpanel": str(self.showViewerPanel),
|
||||
"showedittoolbar": str(self.showEditToolBar),
|
||||
"showsessiontime": str(self.showSessionTime),
|
||||
"viewcomments": str(self.viewComments),
|
||||
"viewsynopsis": str(self.viewSynopsis),
|
||||
"searchcase": str(self.searchCase),
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2019-04-28 [0.0.1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -207,7 +207,7 @@ class nwLists:
|
||||
|
||||
class nwStats:
|
||||
|
||||
CHARS_ALL = "allChars"
|
||||
CHARS = "allChars"
|
||||
CHARS_TEXT = "textChars"
|
||||
CHARS_TITLE = "titleChars"
|
||||
PARAGRAPHS = "paragraphCount"
|
||||
@@ -215,14 +215,14 @@ class nwStats:
|
||||
WCHARS_ALL = "allWordChars"
|
||||
WCHARS_TEXT = "textWordChars"
|
||||
WCHARS_TITLE = "titleWordChars"
|
||||
WORDS_ALL = "allWords"
|
||||
WORDS = "allWords"
|
||||
WORDS_TEXT = "textWords"
|
||||
WORDS_TITLE = "titleWords"
|
||||
|
||||
# Note: The order here affects the order of menu entries
|
||||
ALL_FIELDS = [
|
||||
WORDS_ALL, WORDS_TEXT, WORDS_TITLE,
|
||||
CHARS_ALL, CHARS_TEXT, CHARS_TITLE,
|
||||
WORDS, WORDS_TEXT, WORDS_TITLE,
|
||||
CHARS, CHARS_TEXT, CHARS_TITLE,
|
||||
WCHARS_ALL, WCHARS_TEXT, WCHARS_TITLE,
|
||||
PARAGRAPHS, TITLES,
|
||||
]
|
||||
@@ -329,17 +329,17 @@ class nwLabels:
|
||||
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
|
||||
}
|
||||
STATS_NAME = {
|
||||
nwStats.CHARS_ALL: QT_TRANSLATE_NOOP("Constant", "Characters"),
|
||||
nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Constant", "Characters in Text"),
|
||||
nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Constant", "Characters in Headings"),
|
||||
nwStats.PARAGRAPHS: QT_TRANSLATE_NOOP("Constant", "Paragraphs"),
|
||||
nwStats.TITLES: QT_TRANSLATE_NOOP("Constant", "Headings"),
|
||||
nwStats.WCHARS_ALL: QT_TRANSLATE_NOOP("Constant", "Characters, No Spaces"),
|
||||
nwStats.WCHARS_TEXT: QT_TRANSLATE_NOOP("Constant", "Characters in Text, No Spaces"),
|
||||
nwStats.WCHARS_TITLE: QT_TRANSLATE_NOOP("Constant", "Characters in Headings, No Spaces"),
|
||||
nwStats.WORDS_ALL: QT_TRANSLATE_NOOP("Constant", "Words"),
|
||||
nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Constant", "Words in Text"),
|
||||
nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Constant", "Words in Headings"),
|
||||
nwStats.CHARS: QT_TRANSLATE_NOOP("Stats", "Characters"),
|
||||
nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in Text"),
|
||||
nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in Headings"),
|
||||
nwStats.PARAGRAPHS: QT_TRANSLATE_NOOP("Stats", "Paragraphs"),
|
||||
nwStats.TITLES: QT_TRANSLATE_NOOP("Stats", "Headings"),
|
||||
nwStats.WCHARS_ALL: QT_TRANSLATE_NOOP("Stats", "Characters, No Spaces"),
|
||||
nwStats.WCHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in Text, No Spaces"),
|
||||
nwStats.WCHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in Headings, No Spaces"),
|
||||
nwStats.WORDS: QT_TRANSLATE_NOOP("Stats", "Words"),
|
||||
nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Stats", "Words in Text"),
|
||||
nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Stats", "Words in Headings"),
|
||||
}
|
||||
BUILD_FMT = {
|
||||
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
|
||||
@@ -366,32 +366,32 @@ class nwLabels:
|
||||
nwBuildFmt.J_NWD: ".json",
|
||||
}
|
||||
SHAPES_PLAIN = {
|
||||
nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Constant", "Square"),
|
||||
nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Constant", "Triangle"),
|
||||
nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Constant", "Nabla"),
|
||||
nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Constant", "Diamond"),
|
||||
nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Constant", "Pentagon"),
|
||||
nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Constant", "Hexagon"),
|
||||
nwStatusShape.STAR: QT_TRANSLATE_NOOP("Constant", "Star"),
|
||||
nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Constant", "Pacman"),
|
||||
nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Shape", "Square"),
|
||||
nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Shape", "Triangle"),
|
||||
nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Shape", "Nabla"),
|
||||
nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Shape", "Diamond"),
|
||||
nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Shape", "Pentagon"),
|
||||
nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Shape", "Hexagon"),
|
||||
nwStatusShape.STAR: QT_TRANSLATE_NOOP("Shape", "Star"),
|
||||
nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Shape", "Pacman"),
|
||||
}
|
||||
SHAPES_CIRCLE = {
|
||||
nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Constant", "1/4 Circle"),
|
||||
nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Constant", "Half Circle"),
|
||||
nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Constant", "3/4 Circle"),
|
||||
nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Constant", "Full Circle"),
|
||||
nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Shape", "1/4 Circle"),
|
||||
nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Shape", "Half Circle"),
|
||||
nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Shape", "3/4 Circle"),
|
||||
nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Shape", "Full Circle"),
|
||||
}
|
||||
SHAPES_BARS = {
|
||||
nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Constant", "1 Bar"),
|
||||
nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Constant", "2 Bars"),
|
||||
nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Constant", "3 Bars"),
|
||||
nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Constant", "4 Bars"),
|
||||
nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Shape", "1 Bar"),
|
||||
nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Shape", "2 Bars"),
|
||||
nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Shape", "3 Bars"),
|
||||
nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Shape", "4 Bars"),
|
||||
}
|
||||
SHAPES_BLOCKS = {
|
||||
nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Constant", "1 Block"),
|
||||
nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Constant", "2 Blocks"),
|
||||
nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Constant", "3 Blocks"),
|
||||
nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Constant", "4 Blocks"),
|
||||
nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Shape", "1 Block"),
|
||||
nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Shape", "2 Blocks"),
|
||||
nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Shape", "3 Blocks"),
|
||||
nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Shape", "4 Blocks"),
|
||||
}
|
||||
FILE_FILTERS = {
|
||||
"*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2023-02-14 [2.1b1] BuildSettings
|
||||
Created: 2023-05-22 [2.1b1] BuildCollection
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -159,6 +159,13 @@ SETTINGS_LABELS = {
|
||||
"format.indentFirstPar": QT_TRANSLATE_NOOP("Builds", "Indent First Paragraph"),
|
||||
|
||||
"format.grpMargins": QT_TRANSLATE_NOOP("Builds", "Text Margins"),
|
||||
"format.titleMargin": QT_TRANSLATE_NOOP("Builds", "Title and Partition"),
|
||||
"format.h1Margin": QT_TRANSLATE_NOOP("Builds", "Heading 1 and Chapter"),
|
||||
"format.h2Margin": QT_TRANSLATE_NOOP("Builds", "Heading 2 and Scene"),
|
||||
"format.h3Margin": QT_TRANSLATE_NOOP("Builds", "Heading 3 and Section"),
|
||||
"format.h4Margin": QT_TRANSLATE_NOOP("Builds", "Heading 4"),
|
||||
"format.textMargin": QT_TRANSLATE_NOOP("Builds", "Text Paragraph"),
|
||||
"format.sepMargin": QT_TRANSLATE_NOOP("Builds", "Scene Separator"),
|
||||
|
||||
"format.grpPage": QT_TRANSLATE_NOOP("Builds", "Page Layout"),
|
||||
"format.pageUnit": QT_TRANSLATE_NOOP("Builds", "Unit"),
|
||||
|
||||
@@ -9,7 +9,7 @@ Created: 2022-11-03 [2.0rc2] ProjectBuilder
|
||||
Created: 2023-07-20 [2.1b1] DocDuplicator
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2022-12-01 [2.1b1] NWBuildDocument
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2018-09-29 [0.0.1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -10,7 +10,7 @@ Created: 2022-05-29 [2.0rc1] TagsIndex
|
||||
Created: 2022-05-29 [2.0rc1] ItemIndex
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2018-10-27 [0.0.1] NWItem
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2024-11-16 [2.6b2] ProjectNode
|
||||
Created: 2024-11-16 [2.6b2] ProjectModel
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2019-10-21 [0.3.1] OptionState
|
||||
Rewritten: 2020-02-19 [0.4.5] OptionState
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2018-09-29 [0.0.1] NWProject
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2022-10-30 [2.0rc2] NWProjectData
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -29,7 +29,8 @@ import uuid
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from novelwriter.common import (
|
||||
checkBool, checkInt, checkStringNone, checkUuid, isHandle, simplified
|
||||
checkBool, checkInt, checkStringNone, checkUuid, isHandle,
|
||||
makeFileNameSafe, simplified
|
||||
)
|
||||
from novelwriter.core.status import NWStatus
|
||||
|
||||
@@ -101,6 +102,11 @@ class NWProjectData:
|
||||
"""Return the project name."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def fileSafeName(self) -> str:
|
||||
"""Return the project name in a file name safe format."""
|
||||
return makeFileNameSafe(self._name)
|
||||
|
||||
@property
|
||||
def author(self) -> str:
|
||||
"""Return the project author."""
|
||||
|
||||
@@ -8,7 +8,7 @@ Created: 2022-09-28 [2.0rc2] ProjectXMLReader
|
||||
Created: 2022-10-31 [2.0rc2] ProjectXMLWriter
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2023-06-11 [2.1b1] NWSessionLog
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2019-06-11 [0.1.5] NWSpellEnchant
|
||||
Created: 2023-06-13 [2.1b1] UserDictionary
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2019-05-19 [0.1.3] NWStatus
|
||||
Rewritten: 2022-04-05 [2.0b1] NWStatus
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -37,7 +37,7 @@ from PyQt5.QtGui import QColor, QIcon, QPainter, QPainterPath, QPixmap, QPolygon
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.common import simplified
|
||||
from novelwriter.enum import nwStatusShape
|
||||
from novelwriter.types import QtPaintAnitAlias, QtTransparent
|
||||
from novelwriter.types import QtPaintAntiAlias, QtTransparent
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from typing import TypeGuard # Requires Python 3.10
|
||||
@@ -174,6 +174,20 @@ class NWStatus:
|
||||
"""Yield entries from the status icons."""
|
||||
yield from self._store.items()
|
||||
|
||||
def fromRaw(self, data: list[str]) -> StatusEntry | None:
|
||||
"""Create a StatusEntry from a list of three strings consisting
|
||||
of shape, colour, and name. This entry is not automatically
|
||||
added to the list of entries.
|
||||
"""
|
||||
try:
|
||||
shape = nwStatusShape[str(data[0])]
|
||||
color = QColor(str(data[1]))
|
||||
icon = NWStatus.createIcon(self._height, color, shape)
|
||||
return StatusEntry(simplified(data[2]), color, shape, icon)
|
||||
except Exception:
|
||||
logger.error("Could not parse entry %s", str(data))
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def createIcon(height: int, color: QColor, shape: nwStatusShape) -> QIcon:
|
||||
"""Generate an icon for a status label."""
|
||||
@@ -181,7 +195,7 @@ class NWStatus:
|
||||
pixmap.fill(QtTransparent)
|
||||
|
||||
painter = QPainter(pixmap)
|
||||
painter.setRenderHint(QtPaintAnitAlias)
|
||||
painter.setRenderHint(QtPaintAntiAlias)
|
||||
painter.fillPath(_SHAPES.getShape(shape), color)
|
||||
painter.end()
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2022-11-01 [2.0rc2] NWStorage
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2020-05-07 [0.4.5] NWTree
|
||||
Rewritten: 2024-11-16 [2.6b2] NWTree
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2020-05-21 [0.5.2] GuiAbout
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2020-01-23 [0.4.3] GuiDocMerge
|
||||
Rewritten: 2022-10-06 [2.0rc1] GuiDocMerge
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2020-02-01 [0.4.3] GuiDocSplit
|
||||
Rewritten: 2022-10-12 [2.0rc1] GuiDocSplit
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2022-06-11 [2.0rc1] GuiEditLabel
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2019-06-10 [0.1.5] GuiPreferences
|
||||
Rewritten: 2024-01-08 [2.3b1] GuiPreferences
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -584,7 +584,7 @@ class GuiPreferences(NDialog):
|
||||
self.narratorBreak.setText(CONFIG.narratorBreak)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Narrator break symbol"), self.narratorBreak,
|
||||
self.tr("Symbol to indicate a narrator break in dialogue")
|
||||
self.tr("Symbol to indicate a narrator break in dialogue.")
|
||||
)
|
||||
|
||||
self.narratorDialog = QLineEdit(self)
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2018-09-29 [0.0.1] GuiProjectSettings
|
||||
Rewritten: 2024-01-26 [2.3b1] GuiProjectSettings
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -24,18 +24,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QCloseEvent, QColor
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractItemView, QApplication, QColorDialog, QDialogButtonBox,
|
||||
QHBoxLayout, QLineEdit, QMenu, QStackedWidget, QToolButton, QTreeWidget,
|
||||
QTreeWidgetItem, QVBoxLayout, QWidget
|
||||
QFileDialog, QGridLayout, QHBoxLayout, QLineEdit, QMenu, QStackedWidget,
|
||||
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import qtLambda, simplified
|
||||
from novelwriter.common import formatFileFilter, qtLambda, simplified
|
||||
from novelwriter.constants import nwLabels, trConst
|
||||
from novelwriter.core.status import NWStatus, StatusEntry
|
||||
from novelwriter.enum import nwStatusShape
|
||||
@@ -310,11 +313,13 @@ class _StatusPage(NFixedPage):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
if isStatus:
|
||||
status = SHARED.project.data.itemStatus
|
||||
self._kind = self.tr("Status")
|
||||
self._store = SHARED.project.data.itemStatus
|
||||
pageLabel = self.tr("Novel Document Status Levels")
|
||||
colSetting = "statusColW"
|
||||
else:
|
||||
status = SHARED.project.data.itemImport
|
||||
self._kind = self.tr("Importance")
|
||||
self._store = SHARED.project.data.itemImport
|
||||
pageLabel = self.tr("Project Note Importance Levels")
|
||||
colSetting = "importColW"
|
||||
|
||||
@@ -352,29 +357,42 @@ class _StatusPage(NFixedPage):
|
||||
self.listBox.setIndentation(0)
|
||||
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self.listBox.itemSelectionChanged.connect(self._selectionChanged)
|
||||
self.listBox.itemSelectionChanged.connect(self._onSelectionChanged)
|
||||
|
||||
for key, entry in status.iterItems():
|
||||
for key, entry in self._store.iterItems():
|
||||
self._addItem(key, StatusEntry.duplicate(entry))
|
||||
|
||||
# List Controls
|
||||
self.addButton = NIconToolButton(self, iSz, "add")
|
||||
self.addButton.clicked.connect(self._newItem)
|
||||
self.addButton.setToolTip(self.tr("Add Label"))
|
||||
self.addButton.clicked.connect(self._onItemCreate)
|
||||
|
||||
self.delButton = NIconToolButton(self, iSz, "remove")
|
||||
self.delButton.clicked.connect(self._delItem)
|
||||
self.delButton.setToolTip(self.tr("Delete Label"))
|
||||
self.delButton.clicked.connect(self._onItemDelete)
|
||||
|
||||
self.upButton = NIconToolButton(self, iSz, "up")
|
||||
self.upButton.setToolTip(self.tr("Move Up"))
|
||||
self.upButton.clicked.connect(qtLambda(self._moveItem, -1))
|
||||
|
||||
self.dnButton = NIconToolButton(self, iSz, "down")
|
||||
self.dnButton.clicked.connect(qtLambda(self._moveItem, 1))
|
||||
self.downButton = NIconToolButton(self, iSz, "down")
|
||||
self.downButton.setToolTip(self.tr("Move Down"))
|
||||
self.downButton.clicked.connect(qtLambda(self._moveItem, 1))
|
||||
|
||||
self.importButton = NIconToolButton(self, iSz, "import")
|
||||
self.importButton.setToolTip(self.tr("Import Labels"))
|
||||
self.importButton.clicked.connect(self._importLabels)
|
||||
|
||||
self.exportButton = NIconToolButton(self, iSz, "export")
|
||||
self.exportButton.setToolTip(self.tr("Export Labels"))
|
||||
self.exportButton.clicked.connect(self._exportLabels)
|
||||
|
||||
# Edit Form
|
||||
self.editName = QLineEdit(self)
|
||||
self.editName.setMaxLength(40)
|
||||
self.editName.setPlaceholderText(self.tr("Select item to edit"))
|
||||
self.editName.setEnabled(False)
|
||||
self.labelText = QLineEdit(self)
|
||||
self.labelText.setMaxLength(40)
|
||||
self.labelText.setPlaceholderText(self.tr("Select item to edit"))
|
||||
self.labelText.setEnabled(False)
|
||||
self.labelText.textEdited.connect(self._onNameEdit)
|
||||
|
||||
buttonStyle = (
|
||||
f"QToolButton {{padding: 0 {bPd}px;}} "
|
||||
@@ -386,13 +404,13 @@ class _StatusPage(NFixedPage):
|
||||
self.colorButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
|
||||
self.colorButton.setStyleSheet(buttonStyle)
|
||||
self.colorButton.setEnabled(False)
|
||||
self.colorButton.clicked.connect(self._selectColour)
|
||||
self.colorButton.clicked.connect(self._onColourSelect)
|
||||
|
||||
def buildMenu(menu: QMenu, items: dict[nwStatusShape, str]) -> None:
|
||||
for shape, label in items.items():
|
||||
icon = NWStatus.createIcon(self._iPx, iColor, shape)
|
||||
action = menu.addAction(icon, trConst(label))
|
||||
action.triggered.connect(lambda _, shape=shape: self._selectShape(shape))
|
||||
action.triggered.connect(qtLambda(self._selectShape, shape))
|
||||
self._icons[shape] = icon
|
||||
|
||||
self.shapeMenu = QMenu(self)
|
||||
@@ -408,33 +426,27 @@ class _StatusPage(NFixedPage):
|
||||
self.shapeButton.setStyleSheet(buttonStyle)
|
||||
self.shapeButton.setEnabled(False)
|
||||
|
||||
self.applyButton = QToolButton(self)
|
||||
self.applyButton.setText(self.tr("Apply"))
|
||||
self.applyButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
|
||||
self.applyButton.setEnabled(False)
|
||||
self.applyButton.clicked.connect(self._applyChanges)
|
||||
|
||||
# Assemble
|
||||
self.listControls = QVBoxLayout()
|
||||
self.listControls.addWidget(self.addButton)
|
||||
self.listControls.addWidget(self.delButton)
|
||||
self.listControls.addWidget(self.upButton)
|
||||
self.listControls.addWidget(self.dnButton)
|
||||
self.listControls.addWidget(self.downButton)
|
||||
self.listControls.addStretch(1)
|
||||
self.listControls.addWidget(self.importButton)
|
||||
self.listControls.addWidget(self.exportButton)
|
||||
|
||||
self.editBox = QHBoxLayout()
|
||||
self.editBox.addWidget(self.editName, 1)
|
||||
self.editBox.addWidget(self.labelText, 1)
|
||||
self.editBox.addWidget(self.colorButton, 0)
|
||||
self.editBox.addWidget(self.shapeButton, 0)
|
||||
self.editBox.addWidget(self.applyButton, 0)
|
||||
|
||||
self.mainBox = QVBoxLayout()
|
||||
self.mainBox.addWidget(self.listBox, 1)
|
||||
self.mainBox.addLayout(self.editBox, 0)
|
||||
|
||||
self.innerBox = QHBoxLayout()
|
||||
self.innerBox.addLayout(self.mainBox, 1)
|
||||
self.innerBox.addLayout(self.listControls, 0)
|
||||
self.innerBox = QGridLayout()
|
||||
self.innerBox.addWidget(self.listBox, 0, 0)
|
||||
self.innerBox.addLayout(self.listControls, 0, 1)
|
||||
self.innerBox.addLayout(self.editBox, 1, 0)
|
||||
self.innerBox.setRowStretch(0, 1)
|
||||
self.innerBox.setColumnStretch(0, 1)
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.addWidget(self.pageTitle, 0)
|
||||
@@ -474,16 +486,28 @@ class _StatusPage(NFixedPage):
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _onNameEdit(self, text: str) -> None:
|
||||
"""Update the status label text."""
|
||||
if item := self._getSelectedItem():
|
||||
name = simplified(text)
|
||||
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
entry.name = name
|
||||
item.setText(self.C_LABEL, name)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectColour(self) -> None:
|
||||
def _onColourSelect(self) -> None:
|
||||
"""Open a dialog to select the status icon colour."""
|
||||
if (color := QColorDialog.getColor(self._color, self, self.trSelColor)).isValid():
|
||||
self._color = color
|
||||
self._setButtonIcons()
|
||||
self._updateIcon()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _newItem(self) -> None:
|
||||
def _onItemCreate(self) -> None:
|
||||
"""Create a new status item."""
|
||||
color = QColor(100, 100, 100)
|
||||
shape = nwStatusShape.SQUARE
|
||||
@@ -493,7 +517,7 @@ class _StatusPage(NFixedPage):
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _delItem(self) -> None:
|
||||
def _onItemDelete(self) -> None:
|
||||
"""Delete a status item."""
|
||||
if item := self._getSelectedItem():
|
||||
iRow = self.listBox.indexOfTopLevelItem(item)
|
||||
@@ -506,28 +530,7 @@ class _StatusPage(NFixedPage):
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _applyChanges(self) -> None:
|
||||
"""Save changes made to a status item."""
|
||||
if item := self._getSelectedItem():
|
||||
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
|
||||
name = simplified(self.editName.text())
|
||||
icon = NWStatus.createIcon(self._iPx, self._color, self._shape)
|
||||
|
||||
entry.name = name
|
||||
entry.color = self._color
|
||||
entry.shape = self._shape
|
||||
entry.icon = icon
|
||||
|
||||
item.setText(self.C_LABEL, name)
|
||||
item.setIcon(self.C_LABEL, icon)
|
||||
|
||||
self._changed = True
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectionChanged(self) -> None:
|
||||
def _onSelectionChanged(self) -> None:
|
||||
"""Extract the info of a selected item and populate the settings
|
||||
boxes and button. If no item is selected, clear the form.
|
||||
"""
|
||||
@@ -537,25 +540,59 @@ class _StatusPage(NFixedPage):
|
||||
self._shape = entry.shape
|
||||
self._setButtonIcons()
|
||||
|
||||
self.editName.setText(entry.name)
|
||||
self.editName.selectAll()
|
||||
self.editName.setFocus()
|
||||
self.labelText.setText(entry.name)
|
||||
self.labelText.selectAll()
|
||||
self.labelText.setFocus()
|
||||
|
||||
self.editName.setEnabled(True)
|
||||
self.labelText.setEnabled(True)
|
||||
self.colorButton.setEnabled(True)
|
||||
self.shapeButton.setEnabled(True)
|
||||
self.applyButton.setEnabled(True)
|
||||
|
||||
else:
|
||||
self._color = QColor(100, 100, 100)
|
||||
self._shape = nwStatusShape.SQUARE
|
||||
self._setButtonIcons()
|
||||
self.editName.setText("")
|
||||
self.labelText.setText("")
|
||||
|
||||
self.editName.setEnabled(False)
|
||||
self.labelText.setEnabled(False)
|
||||
self.colorButton.setEnabled(False)
|
||||
self.shapeButton.setEnabled(False)
|
||||
self.applyButton.setEnabled(False)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _importLabels(self) -> None:
|
||||
"""Import labels from file."""
|
||||
if path := QFileDialog.getOpenFileName(
|
||||
self, self.tr("Import File"),
|
||||
str(CONFIG.homePath()), filter=formatFileFilter(["*.csv", "*"]),
|
||||
)[0]:
|
||||
try:
|
||||
with open(path, mode="r", encoding="utf-8") as fo:
|
||||
for row in csv.reader(fo):
|
||||
if entry := self._store.fromRaw(row):
|
||||
self._addItem(None, entry)
|
||||
self._changed = True
|
||||
except Exception as exc:
|
||||
SHARED.error("Could not read file.", exc=exc)
|
||||
return
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _exportLabels(self) -> None:
|
||||
"""Export labels to file."""
|
||||
name = f"{SHARED.project.data.fileSafeName} - {self._kind}.csv"
|
||||
if path := QFileDialog.getSaveFileName(
|
||||
self, self.tr("Export File"), str(CONFIG.homePath() / name),
|
||||
)[0]:
|
||||
try:
|
||||
path = Path(path).with_suffix(".csv")
|
||||
with open(path, mode="w", encoding="utf-8") as fo:
|
||||
writer = csv.writer(fo)
|
||||
for n in range(self.listBox.topLevelItemCount()):
|
||||
if item := self.listBox.topLevelItem(n):
|
||||
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
writer.writerow([entry.shape.name, entry.color.name(), entry.name])
|
||||
except Exception as exc:
|
||||
SHARED.error("Could not write file.", exc=exc)
|
||||
return
|
||||
|
||||
##
|
||||
@@ -566,6 +603,19 @@ class _StatusPage(NFixedPage):
|
||||
"""Set the current shape."""
|
||||
self._shape = shape
|
||||
self._setButtonIcons()
|
||||
self._updateIcon()
|
||||
return
|
||||
|
||||
def _updateIcon(self) -> None:
|
||||
"""Apply changes made to a status icon."""
|
||||
if item := self._getSelectedItem():
|
||||
icon = NWStatus.createIcon(self._iPx, self._color, self._shape)
|
||||
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
entry.color = self._color
|
||||
entry.shape = self._shape
|
||||
entry.icon = icon
|
||||
item.setIcon(self.C_LABEL, icon)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def _addItem(self, key: str | None, entry: StatusEntry) -> None:
|
||||
@@ -644,7 +694,7 @@ class _ReplacePage(NFixedPage):
|
||||
self.listBox.setIndentation(0)
|
||||
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self.listBox.itemSelectionChanged.connect(self._selectionChanged)
|
||||
self.listBox.itemSelectionChanged.connect(self._onSelectionChanged)
|
||||
|
||||
for aKey, aVal in SHARED.project.data.autoReplace.items():
|
||||
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
|
||||
@@ -655,25 +705,22 @@ class _ReplacePage(NFixedPage):
|
||||
|
||||
# List Controls
|
||||
self.addButton = NIconToolButton(self, iSz, "add")
|
||||
self.addButton.clicked.connect(self._addEntry)
|
||||
self.addButton.clicked.connect(self._onEntryCreated)
|
||||
|
||||
self.delButton = NIconToolButton(self, iSz, "remove")
|
||||
self.delButton.clicked.connect(self._delEntry)
|
||||
self.delButton.clicked.connect(self._onEntryDeleted)
|
||||
|
||||
# Edit Form
|
||||
self.editKey = QLineEdit(self)
|
||||
self.editKey.setPlaceholderText(self.tr("Select item to edit"))
|
||||
self.editKey.setEnabled(False)
|
||||
self.editKey.setMaxLength(40)
|
||||
self.editKey.textEdited.connect(self._onKeyEdit)
|
||||
|
||||
self.editValue = QLineEdit(self)
|
||||
self.editValue.setEnabled(False)
|
||||
self.editValue.setMaxLength(80)
|
||||
|
||||
self.applyButton = QToolButton(self)
|
||||
self.applyButton.setText(self.tr("Apply"))
|
||||
self.applyButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
|
||||
self.applyButton.clicked.connect(self._applyChanges)
|
||||
self.editValue.setMaxLength(250)
|
||||
self.editValue.textEdited.connect(self._onValueEdit)
|
||||
|
||||
# Assemble
|
||||
self.listControls = QVBoxLayout()
|
||||
@@ -684,7 +731,6 @@ class _ReplacePage(NFixedPage):
|
||||
self.editBox = QHBoxLayout()
|
||||
self.editBox.addWidget(self.editKey, 4)
|
||||
self.editBox.addWidget(self.editValue, 5)
|
||||
self.editBox.addWidget(self.applyButton, 0)
|
||||
|
||||
self.mainBox = QVBoxLayout()
|
||||
self.mainBox.addWidget(self.listBox, 1)
|
||||
@@ -716,7 +762,7 @@ class _ReplacePage(NFixedPage):
|
||||
new = {}
|
||||
for n in range(self.listBox.topLevelItemCount()):
|
||||
if item := self.listBox.topLevelItem(n):
|
||||
if key := self._stripNotAllowed(item.text(self.C_KEY)):
|
||||
if key := self._stripKey(item.text(self.C_KEY)):
|
||||
new[key] = item.text(self.C_REPL)
|
||||
return new
|
||||
|
||||
@@ -728,13 +774,29 @@ class _ReplacePage(NFixedPage):
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _onKeyEdit(self, text: str) -> None:
|
||||
"""Update the key text."""
|
||||
if (item := self._getSelectedItem()) and (key := self._stripKey(text)):
|
||||
item.setText(self.C_KEY, f"<{key}>")
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _onValueEdit(self, text: str) -> None:
|
||||
"""Update the value text."""
|
||||
if item := self._getSelectedItem():
|
||||
item.setText(self.C_REPL, text)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectionChanged(self) -> None:
|
||||
def _onSelectionChanged(self) -> None:
|
||||
"""Extract the details from the selected item and populate the
|
||||
edit form.
|
||||
"""
|
||||
if item := self._getSelectedItem():
|
||||
self.editKey.setText(self._stripNotAllowed(item.text(self.C_KEY)))
|
||||
self.editKey.setText(self._stripKey(item.text(self.C_KEY)))
|
||||
self.editValue.setText(item.text(self.C_REPL))
|
||||
self.editKey.setEnabled(True)
|
||||
self.editValue.setEnabled(True)
|
||||
@@ -748,26 +810,14 @@ class _ReplacePage(NFixedPage):
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _applyChanges(self) -> None:
|
||||
"""Save the form data into the list widget."""
|
||||
if item := self._getSelectedItem():
|
||||
key = self._stripNotAllowed(self.editKey.text())
|
||||
value = self.editValue.text()
|
||||
if key and value:
|
||||
item.setText(self.C_KEY, f"<{key}>")
|
||||
item.setText(self.C_REPL, value)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _addEntry(self) -> None:
|
||||
def _onEntryCreated(self) -> None:
|
||||
"""Add a new list entry."""
|
||||
key = f"<keyword{self.listBox.topLevelItemCount() + 1:d}>"
|
||||
self.listBox.addTopLevelItem(QTreeWidgetItem([key, ""]))
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _delEntry(self) -> None:
|
||||
def _onEntryDeleted(self) -> None:
|
||||
"""Delete the selected entry."""
|
||||
if item := self._getSelectedItem():
|
||||
self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(item))
|
||||
@@ -784,6 +834,6 @@ class _ReplacePage(NFixedPage):
|
||||
return items[0]
|
||||
return None
|
||||
|
||||
def _stripNotAllowed(self, key: str) -> str:
|
||||
def _stripKey(self, key: str) -> str:
|
||||
"""Clean up the replace key string."""
|
||||
return "".join(c for c in key if c.isalnum())
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2020-06-18 [0.9.0] GuiQuoteSelect
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2021 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2021-02-12 [1.2rc1] GuiWordList
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2021 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -96,9 +96,11 @@ class GuiWordList(NDialog):
|
||||
self.newEntry = QLineEdit(self)
|
||||
|
||||
self.addButton = NIconToolButton(self, iSz, "add")
|
||||
self.addButton.setToolTip(self.tr("Add Word"))
|
||||
self.addButton.clicked.connect(self._doAdd)
|
||||
|
||||
self.delButton = NIconToolButton(self, iSz, "remove")
|
||||
self.delButton.setToolTip(self.tr("Remove Word"))
|
||||
self.delButton.clicked.connect(self._doDelete)
|
||||
|
||||
self.editBox = QHBoxLayout()
|
||||
@@ -184,11 +186,10 @@ class GuiWordList(NDialog):
|
||||
SHARED.info(self.tr(
|
||||
"Note: The import file must be a plain text file with UTF-8 or ASCII encoding."
|
||||
))
|
||||
ffilter = formatFileFilter(["*.txt", "*"])
|
||||
path, _ = QFileDialog.getOpenFileName(
|
||||
self, self.tr("Import File"), str(CONFIG.homePath()), filter=ffilter
|
||||
)
|
||||
if path:
|
||||
if path := QFileDialog.getOpenFileName(
|
||||
self, self.tr("Import File"), str(CONFIG.homePath()),
|
||||
filter=formatFileFilter(["*.txt", "*"]),
|
||||
)[0]:
|
||||
try:
|
||||
with open(path, mode="r", encoding="utf-8") as fo:
|
||||
words = set(w.strip() for w in fo.read().split())
|
||||
@@ -202,10 +203,10 @@ class GuiWordList(NDialog):
|
||||
@pyqtSlot()
|
||||
def _exportWords(self) -> None:
|
||||
"""Export words to file."""
|
||||
path, _ = QFileDialog.getSaveFileName(
|
||||
self, self.tr("Export File"), str(CONFIG.homePath())
|
||||
)
|
||||
if path:
|
||||
name = f"{SHARED.project.data.fileSafeName} - {self.windowTitle()}.txt"
|
||||
if path := QFileDialog.getSaveFileName(
|
||||
self, self.tr("Export File"), str(CONFIG.homePath() / name),
|
||||
)[0]:
|
||||
try:
|
||||
path = Path(path).with_suffix(".txt")
|
||||
with open(path, mode="w", encoding="utf-8") as fo:
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2018-11-02 [0.0.1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2020-08-02 [0.10.2]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -76,7 +76,7 @@ class NWErrorMessage(QDialog):
|
||||
|
||||
font = QFont()
|
||||
font.setPointSize(round(0.9*self.font().pointSize()))
|
||||
font.setFamily(QFontDatabase.systemFont(QFontDatabase.FixedFont).family())
|
||||
font.setFamily(QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont).family())
|
||||
|
||||
self.msgBody = QPlainTextEdit()
|
||||
self.msgBody.setFont(font)
|
||||
|
||||
@@ -10,7 +10,7 @@ Created: 2024-01-26 [2.3b1] NFixedPage
|
||||
Created: 2024-03-12 [2.4b1] NWrappedWidgetBox
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2023-08-31 [2.1rc1] WheelEventFilter
|
||||
Created: 2023-11-28 [2.2] StatusTipFilter
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -10,7 +10,7 @@ Created: 2024-05-01 [2.5b1] NToolDialog
|
||||
Created: 2024-05-01 [2.5b1] NNonBlockingDialog
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -30,14 +30,15 @@ from __future__ import annotations
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import QSize, Qt, pyqtSlot
|
||||
from PyQt5.QtGui import QWheelEvent
|
||||
from PyQt5.QtCore import QSize, Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QMouseEvent, QWheelEvent
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QComboBox, QDialog, QDoubleSpinBox, QSpinBox, QToolButton,
|
||||
QWidget
|
||||
QApplication, QComboBox, QDialog, QDoubleSpinBox, QLabel, QSpinBox,
|
||||
QToolButton, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.types import QtMouseLeft
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.guimain import GuiMain
|
||||
@@ -196,3 +197,14 @@ class NIconToggleButton(QToolButton):
|
||||
iconSize = self.iconSize()
|
||||
self.setIcon(SHARED.theme.getToggleIcon(iconKey, (iconSize.width(), iconSize.height())))
|
||||
return
|
||||
|
||||
|
||||
class NClickableLabel(QLabel):
|
||||
|
||||
mouseClicked = pyqtSignal()
|
||||
|
||||
def mousePressEvent(self, event: QMouseEvent) -> None:
|
||||
"""Capture a left mouse click and emit its signal."""
|
||||
if event.button() == QtMouseLeft:
|
||||
self.mouseClicked.emit()
|
||||
return super().mousePressEvent(event)
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2022-11-17 [2.0] NovelSelector
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -90,12 +90,13 @@ class NovelSelector(QComboBox):
|
||||
@pyqtSlot()
|
||||
def refreshNovelList(self) -> None:
|
||||
"""Rebuild the list of novel items."""
|
||||
cHandle = self.currentData()
|
||||
|
||||
self._blockSignal = True
|
||||
self._firstHandle = None
|
||||
self.clear()
|
||||
|
||||
icon = SHARED.theme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
|
||||
handle = self.currentData()
|
||||
for tHandle, nwItem in SHARED.project.tree.iterRoots(nwItemClass.NOVEL):
|
||||
if self._listFormat:
|
||||
name = self._listFormat.format(nwItem.itemName)
|
||||
@@ -110,7 +111,7 @@ class NovelSelector(QComboBox):
|
||||
self.insertSeparator(self.count())
|
||||
self.addItem(icon, self.tr("All Novel Folders"), "")
|
||||
|
||||
self.setHandle(handle)
|
||||
self.setHandle(cHandle)
|
||||
self.setEnabled(self.count() > 1)
|
||||
self._blockSignal = False
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Created: 2023-02-21 [2.1b1] NPagedToolButton
|
||||
Created: 2023-02-21 [2.1b1] NPagedToolLabel
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -33,7 +33,7 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter.types import (
|
||||
QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen, QtPaintAnitAlias,
|
||||
QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen, QtPaintAntiAlias,
|
||||
QtSizeExpanding, QtSizeFixed
|
||||
)
|
||||
|
||||
@@ -146,7 +146,7 @@ class _PagedToolButton(QToolButton):
|
||||
opt.initFrom(self)
|
||||
|
||||
paint = QPainter(self)
|
||||
paint.setRenderHint(QtPaintAnitAlias, True)
|
||||
paint.setRenderHint(QtPaintAntiAlias, True)
|
||||
paint.setPen(QtNoPen)
|
||||
paint.setBrush(QtNoBrush)
|
||||
|
||||
@@ -213,7 +213,7 @@ class _NPagedToolLabel(QLabel):
|
||||
label that matches the button style.
|
||||
"""
|
||||
paint = QPainter(self)
|
||||
paint.setRenderHint(QtPaintAnitAlias, True)
|
||||
paint.setRenderHint(QtPaintAntiAlias, True)
|
||||
paint.setPen(QtNoPen)
|
||||
|
||||
width = self.width()
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2023-06-07 [2.1b1] NProgressCircle
|
||||
Created: 2023-06-09 [2.1b1] NProgressSimple
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -31,7 +31,7 @@ from PyQt5.QtGui import QBrush, QColor, QPainter, QPaintEvent, QPen
|
||||
from PyQt5.QtWidgets import QProgressBar, QWidget
|
||||
|
||||
from novelwriter.types import (
|
||||
QtAlignCenter, QtPaintAnitAlias, QtRoundCap, QtSizeFixed, QtSolidLine,
|
||||
QtAlignCenter, QtPaintAntiAlias, QtRoundCap, QtSizeFixed, QtSolidLine,
|
||||
QtTransparent
|
||||
)
|
||||
|
||||
@@ -91,7 +91,7 @@ class NProgressCircle(QProgressBar):
|
||||
progress = 100.0*self.value()/self.maximum()
|
||||
angle = ceil(16*3.6*progress)
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QtPaintAnitAlias, True)
|
||||
painter.setRenderHint(QtPaintAntiAlias, True)
|
||||
painter.setPen(self._dPen)
|
||||
painter.setBrush(self._dBrush)
|
||||
painter.drawEllipse(self._dRect)
|
||||
@@ -119,7 +119,7 @@ class NProgressSimple(QProgressBar):
|
||||
if (value := self.value()) > 0:
|
||||
progress = ceil(self.width()*float(value)/self.maximum())
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QtPaintAnitAlias, True)
|
||||
painter.setRenderHint(QtPaintAntiAlias, True)
|
||||
painter.setPen(self.palette().highlight().color())
|
||||
painter.setBrush(self.palette().highlight())
|
||||
painter.drawRect(0, 0, progress, self.height())
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2020-05-17 [0.5.1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -30,7 +30,7 @@ from PyQt5.QtWidgets import QAbstractButton, QWidget
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.enum import nwTrinary
|
||||
from novelwriter.types import QtBlack, QtPaintAnitAlias
|
||||
from novelwriter.types import QtBlack, QtPaintAntiAlias
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -81,7 +81,7 @@ class StatusLED(QAbstractButton):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Draw the LED."""
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QtPaintAnitAlias, True)
|
||||
painter.setRenderHint(QtPaintAntiAlias, True)
|
||||
painter.setPen(self.palette().windowText().color())
|
||||
painter.setBrush(self._color)
|
||||
painter.setOpacity(1.0)
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2020-05-03 [0.4.5]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -28,7 +28,7 @@ from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
|
||||
from PyQt5.QtWidgets import QAbstractButton, QWidget
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.types import QtMouseLeft, QtNoPen, QtPaintAnitAlias, QtSizeFixed
|
||||
from novelwriter.types import QtMouseLeft, QtNoPen, QtPaintAntiAlias, QtSizeFixed
|
||||
|
||||
|
||||
class NSwitch(QAbstractButton):
|
||||
@@ -90,7 +90,7 @@ class NSwitch(QAbstractButton):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Drawing the switch itself."""
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QtPaintAnitAlias, True)
|
||||
painter.setRenderHint(QtPaintAntiAlias, True)
|
||||
painter.setPen(QtNoPen)
|
||||
|
||||
palette = self.palette()
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2023-04-16 [2.1b1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2024-02-14 [2.3b1] VersionInfoWidget
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2024-10-21 [2.6b1]
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -104,17 +104,18 @@ class BlockTyp(IntEnum):
|
||||
|
||||
EMPTY = 1 # Empty line (new paragraph)
|
||||
TITLE = 2 # Title
|
||||
HEAD1 = 3 # Heading 1
|
||||
HEAD2 = 4 # Heading 2
|
||||
HEAD3 = 5 # Heading 3
|
||||
HEAD4 = 6 # Heading 4
|
||||
TEXT = 7 # Text line
|
||||
SEP = 8 # Scene separator
|
||||
SKIP = 9 # Paragraph break
|
||||
SUMMARY = 10 # Synopsis/short comment
|
||||
NOTE = 11 # Note
|
||||
COMMENT = 12 # Comment
|
||||
KEYWORD = 13 # Tag/reference keywords
|
||||
PART = 3 # Partition
|
||||
HEAD1 = 4 # Heading 1 or Chapter
|
||||
HEAD2 = 5 # Heading 2 or Scene
|
||||
HEAD3 = 6 # Heading 3 or Section
|
||||
HEAD4 = 7 # Heading 4
|
||||
TEXT = 8 # Text line
|
||||
SEP = 9 # Scene separator
|
||||
SKIP = 10 # Paragraph break
|
||||
SUMMARY = 11 # Synopsis/short comment
|
||||
NOTE = 12 # Note
|
||||
COMMENT = 13 # Comment
|
||||
KEYWORD = 14 # Tag/reference keywords
|
||||
|
||||
|
||||
class BlockFmt(Flag):
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2024-10-18 [2.6b1] ToDocX
|
||||
Created: 2024-10-18 [2.6b1] DocXParagraph
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -271,7 +271,7 @@ class ToDocX(Tokenizer):
|
||||
if tType == BlockTyp.TEXT:
|
||||
self._processFragments(par, S_NORM, tText, tFormat)
|
||||
|
||||
elif tType == BlockTyp.TITLE:
|
||||
elif tType in (BlockTyp.TITLE, BlockTyp.PART):
|
||||
self._processFragments(par, S_TITLE, tText, tFormat)
|
||||
|
||||
elif tType == BlockTyp.HEAD1:
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2019-05-07 [0.0.1] ToHtml
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -30,7 +30,7 @@ from pathlib import Path
|
||||
from time import time
|
||||
|
||||
from novelwriter.common import formatTimeStamp
|
||||
from novelwriter.constants import nwHtmlUnicode
|
||||
from novelwriter.constants import nwHtmlUnicode, nwStyles
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt, stripEscape
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
@@ -130,20 +130,6 @@ class ToHtml(Tokenizer):
|
||||
|
||||
def doConvert(self) -> None:
|
||||
"""Convert the list of text tokens into an HTML document."""
|
||||
if self._isNovel:
|
||||
# For story files, we bump the titles one level up
|
||||
h1Cl = " class='title'"
|
||||
h1 = "h1"
|
||||
h2 = "h1"
|
||||
h3 = "h2"
|
||||
h4 = "h3"
|
||||
else:
|
||||
h1Cl = ""
|
||||
h1 = "h1"
|
||||
h2 = "h2"
|
||||
h3 = "h3"
|
||||
h4 = "h4"
|
||||
|
||||
lines = []
|
||||
for tType, tMeta, tText, tFmt, tStyle in self._blocks:
|
||||
|
||||
@@ -213,25 +199,25 @@ class ToHtml(Tokenizer):
|
||||
if tType == BlockTyp.TEXT:
|
||||
lines.append(f"<p{hStyle}>{self._formatText(tText, tFmt)}</p>\n")
|
||||
|
||||
elif tType == BlockTyp.TITLE:
|
||||
elif tType in (BlockTyp.TITLE, BlockTyp.PART):
|
||||
tHead = tText.replace("\n", "<br>")
|
||||
lines.append(f"<h1 class='title'{hStyle}>{aNm}{tHead}</h1>\n")
|
||||
|
||||
elif tType == BlockTyp.HEAD1:
|
||||
tHead = tText.replace("\n", "<br>")
|
||||
lines.append(f"<{h1}{h1Cl}{hStyle}>{aNm}{tHead}</{h1}>\n")
|
||||
lines.append(f"<h1{hStyle}>{aNm}{tHead}</h1>\n")
|
||||
|
||||
elif tType == BlockTyp.HEAD2:
|
||||
tHead = tText.replace("\n", "<br>")
|
||||
lines.append(f"<{h2}{hStyle}>{aNm}{tHead}</{h2}>\n")
|
||||
lines.append(f"<h2{hStyle}>{aNm}{tHead}</h2>\n")
|
||||
|
||||
elif tType == BlockTyp.HEAD3:
|
||||
tHead = tText.replace("\n", "<br>")
|
||||
lines.append(f"<{h3}{hStyle}>{aNm}{tHead}</{h3}>\n")
|
||||
lines.append(f"<h3{hStyle}>{aNm}{tHead}</h3>\n")
|
||||
|
||||
elif tType == BlockTyp.HEAD4:
|
||||
tHead = tText.replace("\n", "<br>")
|
||||
lines.append(f"<{h4}{hStyle}>{aNm}{tHead}</{h4}>\n")
|
||||
lines.append(f"<h4{hStyle}>{aNm}{tHead}</h4>\n")
|
||||
|
||||
elif tType == BlockTyp.SEP:
|
||||
lines.append(f"<p class='sep'{hStyle}>{tText}</p>\n")
|
||||
@@ -310,9 +296,7 @@ class ToHtml(Tokenizer):
|
||||
"</style>\n"
|
||||
"</head>\n"
|
||||
"<body>\n"
|
||||
"<article>\n"
|
||||
"{body:s}\n"
|
||||
"</article>\n"
|
||||
"</body>\n"
|
||||
"</html>\n"
|
||||
).format(
|
||||
@@ -359,6 +343,12 @@ class ToHtml(Tokenizer):
|
||||
mtSP = self._marginSep[0]
|
||||
mbSP = self._marginSep[1]
|
||||
|
||||
fSz0 = nwStyles.H_SIZES[0]
|
||||
fSz1 = nwStyles.H_SIZES[1]
|
||||
fSz2 = nwStyles.H_SIZES[2]
|
||||
fSz3 = nwStyles.H_SIZES[3]
|
||||
fSz4 = nwStyles.H_SIZES[4]
|
||||
|
||||
font = self._textFont
|
||||
fFam = font.family()
|
||||
fSz = font.pointSize()
|
||||
@@ -379,12 +369,25 @@ class ToHtml(Tokenizer):
|
||||
styles.append(f"a {{color: {lColor};}}")
|
||||
styles.append(f"mark {{background: {mColor};}}")
|
||||
styles.append(f"h1, h2, h3, h4 {{color: {hColor}; page-break-after: avoid;}}")
|
||||
styles.append(f"h1 {{margin-top: {mtH1:.2f}em; margin-bottom: {mbH1:.2f}em;}}")
|
||||
styles.append(f"h2 {{margin-top: {mtH2:.2f}em; margin-bottom: {mbH2:.2f}em;}}")
|
||||
styles.append(f"h3 {{margin-top: {mtH3:.2f}em; margin-bottom: {mbH3:.2f}em;}}")
|
||||
styles.append(f"h4 {{margin-top: {mtH4:.2f}em; margin-bottom: {mbH4:.2f}em;}}")
|
||||
styles.append(
|
||||
f".title {{font-size: 2.5em; margin-top: {mtH0:.2f}em; margin-bottom: {mbH0:.2f}em;}}"
|
||||
f"h1 {{font-size: {fSz1:.2f}em; "
|
||||
f"margin-top: {mtH1:.2f}em; margin-bottom: {mbH1:.2f}em;}}"
|
||||
)
|
||||
styles.append(
|
||||
f"h2 {{font-size: {fSz2:.2f}em; "
|
||||
f"margin-top: {mtH2:.2f}em; margin-bottom: {mbH2:.2f}em;}}"
|
||||
)
|
||||
styles.append(
|
||||
f"h3 {{font-size: {fSz3:.2f}em; "
|
||||
f"margin-top: {mtH3:.2f}em; margin-bottom: {mbH3:.2f}em;}}"
|
||||
)
|
||||
styles.append(
|
||||
f"h4 {{font-size: {fSz4:.2f}em; "
|
||||
f"margin-top: {mtH4:.2f}em; margin-bottom: {mbH4:.2f}em;}}"
|
||||
)
|
||||
styles.append(
|
||||
f".title {{font-size: {fSz0:.2f}em; "
|
||||
f"margin-top: {mtH0:.2f}em; margin-bottom: {mbH0:.2f}em;}}"
|
||||
)
|
||||
styles.append(
|
||||
f".sep {{text-align: center; margin-top: {mtSP:.2f}em; margin-bottom: {mbSP:.2f}em;}}"
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2019-05-05 [0.0.1] Tokenizer
|
||||
Created: 2023-05-23 [2.1b1] HeadingFormatter
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -68,11 +68,11 @@ COMMENT_STYLE = {
|
||||
nwComment.COMMENT: ComStyle(),
|
||||
nwComment.STORY: ComStyle("", "modifier", "note"),
|
||||
}
|
||||
HEADINGS = [BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4]
|
||||
SKIP_INDENT = [
|
||||
BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD2, BlockTyp.HEAD3,
|
||||
BlockTyp.HEAD4, BlockTyp.SEP, BlockTyp.SKIP,
|
||||
HEADINGS = [
|
||||
BlockTyp.TITLE, BlockTyp.PART, BlockTyp.HEAD1,
|
||||
BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4,
|
||||
]
|
||||
SKIP_INDENT = HEADINGS + [BlockTyp.SEP, BlockTyp.SKIP]
|
||||
B_EMPTY: T_Block = (BlockTyp.EMPTY, "", "", [], BlockFmt.NONE)
|
||||
|
||||
|
||||
@@ -654,6 +654,7 @@ class Tokenizer(ABC):
|
||||
if not (isPlain or isNovel and sHide):
|
||||
tStyle |= self._titleStyle
|
||||
if isNovel:
|
||||
tType = BlockTyp.PART if isPlain else BlockTyp.TITLE
|
||||
if sHide:
|
||||
tText = ""
|
||||
tType = BlockTyp.EMPTY
|
||||
@@ -687,6 +688,7 @@ class Tokenizer(ABC):
|
||||
sHide = self._hideChapter if isPlain else self._hideUnNum
|
||||
tFormat = self._fmtChapter if isPlain else self._fmtUnNum
|
||||
if isNovel:
|
||||
tType = BlockTyp.HEAD1 # Promote
|
||||
if isPlain:
|
||||
self._hFormatter.incChapter()
|
||||
if sHide:
|
||||
@@ -721,6 +723,7 @@ class Tokenizer(ABC):
|
||||
sHide = self._hideScene if isPlain else self._hideHScene
|
||||
tFormat = self._fmtScene if isPlain else self._fmtHScene
|
||||
if isNovel:
|
||||
tType = BlockTyp.HEAD2 # Promote
|
||||
self._hFormatter.incScene()
|
||||
if sHide:
|
||||
tText = ""
|
||||
@@ -752,6 +755,7 @@ class Tokenizer(ABC):
|
||||
tText = aLine[5:].strip()
|
||||
tType = BlockTyp.HEAD4
|
||||
if isNovel:
|
||||
tType = BlockTyp.HEAD3 # Promote
|
||||
if self._hideSection:
|
||||
tText = ""
|
||||
tType = BlockTyp.EMPTY
|
||||
@@ -927,12 +931,14 @@ class Tokenizer(ABC):
|
||||
for tType, tKey, tText, _, _ in self._blocks:
|
||||
if tType == BlockTyp.TITLE:
|
||||
prefix = "TT"
|
||||
elif tType == BlockTyp.PART:
|
||||
prefix = "PT"
|
||||
elif tType == BlockTyp.HEAD1:
|
||||
prefix = "PT" if isNovel else "H1"
|
||||
prefix = "CH" if isNovel else "H1"
|
||||
elif tType == BlockTyp.HEAD2:
|
||||
prefix = "CH" if isNovel else "H2"
|
||||
elif tType == BlockTyp.HEAD3:
|
||||
prefix = "SC" if isNovel else "H3"
|
||||
prefix = "SC" if isNovel else "H2"
|
||||
elif tType == BlockTyp.HEAD3 and not isNovel:
|
||||
prefix = "H3"
|
||||
else:
|
||||
continue
|
||||
|
||||
@@ -946,11 +952,11 @@ class Tokenizer(ABC):
|
||||
titleCount = self._counts.get(nwStats.TITLES, 0)
|
||||
paragraphCount = self._counts.get(nwStats.PARAGRAPHS, 0)
|
||||
|
||||
allWords = self._counts.get(nwStats.WORDS_ALL, 0)
|
||||
allWords = self._counts.get(nwStats.WORDS, 0)
|
||||
textWords = self._counts.get(nwStats.WORDS_TEXT, 0)
|
||||
titleWords = self._counts.get(nwStats.WORDS_TITLE, 0)
|
||||
|
||||
allChars = self._counts.get(nwStats.CHARS_ALL, 0)
|
||||
allChars = self._counts.get(nwStats.CHARS, 0)
|
||||
textChars = self._counts.get(nwStats.CHARS_TEXT, 0)
|
||||
titleChars = self._counts.get(nwStats.CHARS_TITLE, 0)
|
||||
|
||||
@@ -1004,11 +1010,11 @@ class Tokenizer(ABC):
|
||||
self._counts[nwStats.TITLES] = titleCount
|
||||
self._counts[nwStats.PARAGRAPHS] = paragraphCount
|
||||
|
||||
self._counts[nwStats.WORDS_ALL] = allWords
|
||||
self._counts[nwStats.WORDS] = allWords
|
||||
self._counts[nwStats.WORDS_TEXT] = textWords
|
||||
self._counts[nwStats.WORDS_TITLE] = titleWords
|
||||
|
||||
self._counts[nwStats.CHARS_ALL] = allChars
|
||||
self._counts[nwStats.CHARS] = allChars
|
||||
self._counts[nwStats.CHARS_TEXT] = textChars
|
||||
self._counts[nwStats.CHARS_TITLE] = titleChars
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2021-02-06 [1.2b1] ToMarkdown
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2021 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -113,9 +113,10 @@ class ToMarkdown(Tokenizer):
|
||||
tTemp = self._formatText(tText, tFormat, mTags).replace("\n", " \n")
|
||||
lines.append(f"{tTemp}\n\n")
|
||||
|
||||
elif tType == BlockTyp.TITLE:
|
||||
elif tType in (BlockTyp.TITLE, BlockTyp.PART):
|
||||
tHead = tText.replace("\n", " - ")
|
||||
lines.append(f"# {tHead}\n\n")
|
||||
lines.append(f"{tHead}\n")
|
||||
lines.append("="*len(tHead) + "\n\n")
|
||||
|
||||
elif tType == BlockTyp.HEAD1:
|
||||
tHead = tText.replace("\n", " - ")
|
||||
|
||||
@@ -9,7 +9,7 @@ Created: 2021-01-27 [1.2b1] ODTTextStyle
|
||||
Created: 2021-08-14 [1.5b1] XMLParagraph
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2021 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -363,7 +363,7 @@ class ToOdt(Tokenizer):
|
||||
else:
|
||||
self._addTextPar(xText, S_TEXT, oStyle, tText, tFmt=tFormat)
|
||||
|
||||
elif tType == BlockTyp.TITLE:
|
||||
elif tType in (BlockTyp.TITLE, BlockTyp.PART):
|
||||
# Title must be text:p
|
||||
self._addTextPar(xText, S_TITLE, oStyle, tText, isHead=False)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2024-05-21 [2.5b1] ToQTextDocument
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -157,6 +157,7 @@ class ToQTextDocument(Tokenizer):
|
||||
|
||||
self._mHead = {
|
||||
BlockTyp.TITLE: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]),
|
||||
BlockTyp.PART: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]),
|
||||
BlockTyp.HEAD1: (fPx * self._marginHead1[0], fPx * self._marginHead1[1]),
|
||||
BlockTyp.HEAD2: (fPx * self._marginHead2[0], fPx * self._marginHead2[1]),
|
||||
BlockTyp.HEAD3: (fPx * self._marginHead3[0], fPx * self._marginHead3[1]),
|
||||
@@ -166,6 +167,7 @@ class ToQTextDocument(Tokenizer):
|
||||
hScale = self._scaleHeads
|
||||
self._sHead = {
|
||||
BlockTyp.TITLE: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt,
|
||||
BlockTyp.PART: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt,
|
||||
BlockTyp.HEAD1: (nwStyles.H_SIZES.get(1, 1.0) * fPt) if hScale else fPt,
|
||||
BlockTyp.HEAD2: (nwStyles.H_SIZES.get(2, 1.0) * fPt) if hScale else fPt,
|
||||
BlockTyp.HEAD3: (nwStyles.H_SIZES.get(3, 1.0) * fPt) if hScale else fPt,
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2024-10-15 [2.6b1] ToRaw
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -14,7 +14,7 @@ Created: 2023-11-06 [2.2b1] MetaCompleter
|
||||
Created: 2023-11-07 [2.2b1] GuiDocToolBar
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -1104,10 +1104,10 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
else:
|
||||
self._completer.setVisible(False)
|
||||
|
||||
if self._doReplace and added == 1:
|
||||
cursor = self.textCursor()
|
||||
if self._autoReplace.process(text, cursor):
|
||||
self._qDocument.syntaxHighlighter.rehighlightBlock(cursor.block())
|
||||
if self._doReplace and added == 1:
|
||||
cursor = self.textCursor()
|
||||
if self._autoReplace.process(text, cursor):
|
||||
self._qDocument.syntaxHighlighter.rehighlightBlock(cursor.block())
|
||||
|
||||
return
|
||||
|
||||
@@ -1217,7 +1217,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
# Execute the context menu
|
||||
ctxMenu.exec(self.viewport().mapToGlobal(pos))
|
||||
ctxMenu.deleteLater()
|
||||
ctxMenu.setParent(None)
|
||||
|
||||
return
|
||||
|
||||
@@ -1253,7 +1253,9 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self._nwItem.setParaCount(pCount)
|
||||
if needsRefresh:
|
||||
self._nwItem.notifyToRefresh()
|
||||
self.docFooter.updateWordCount(wCount, False)
|
||||
if not self.textCursor().hasSelection():
|
||||
# Selection counter should take precedence (#2155)
|
||||
self.docFooter.updateWordCount(wCount, False)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
|
||||
@@ -7,7 +7,7 @@ Created: 2019-04-06 [0.0.1] GuiDocHighlighter
|
||||
Created: 2023-09-10 [2.2b1] TextBlockData
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -9,7 +9,7 @@ Created: 2020-06-09 [0.8] GuiDocViewFooter
|
||||
Created: 2020-09-08 [1.0b1] GuiDocViewHistory
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -424,7 +424,7 @@ class GuiDocViewer(QTextBrowser):
|
||||
|
||||
# Open the context menu
|
||||
ctxMenu.exec(self.viewport().mapToGlobal(point))
|
||||
ctxMenu.deleteLater()
|
||||
ctxMenu.setParent(None)
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2023-11-14 [2.2rc1] GuiDocViewerPanel
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2023-09-07 [2.2b1] GuiTextDocument
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@ File History:
|
||||
Created: 2019-04-24 [0.0.1] GuiItemDetails
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
||||
|
||||
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
|
||||
@@ -65,8 +65,8 @@ class GuiItemDetails(QWidget):
|
||||
fntValue = self.font()
|
||||
fntValue.setPointSizeF(0.9*fPt)
|
||||
|
||||
trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS_ALL])
|
||||
trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS_ALL])
|
||||
trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
|
||||
trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS])
|
||||
trStats3 = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
|
||||
|
||||
# Label
|
||||
@@ -93,6 +93,7 @@ class GuiItemDetails(QWidget):
|
||||
self.statusData = QLabel("", self)
|
||||
self.statusData.setFont(fntValue)
|
||||
self.statusData.setAlignment(QtAlignLeft)
|
||||
self.statusData.setWordWrap(True)
|
||||
|
||||
# Class
|
||||
self.className = QLabel(self.tr("Class"), self)
|
||||
|
||||