Merge branch 'main' into features/footnotes

This commit is contained in:
Veronica Berglyd Olsen
2024-04-14 22:17:23 +02:00
120 changed files with 5019 additions and 4672 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
[flake8]
ignore = E133,E221,E226,E228,E241,W503
ignore = E133,E221,E226,E228,E241,W503,ANN101,ANN102,ANN401
per-file-ignores=tests/*:ANN
max-line-length = 99
exclude = docs/*
+4 -4
View File
@@ -4,11 +4,11 @@ on:
push:
branches:
- main
- releases/**
- release
pull_request:
branches:
- main
- releases/**
- release
jobs:
checkSyntax:
@@ -22,9 +22,9 @@ jobs:
- name: Checkout Source
uses: actions/checkout@v4
- name: Install flake8
run: pip install flake8 flake8-pep585
run: pip install -r requirements-dev.txt
- name: Syntax Check
run: |
flake8 --version
flake8 novelwriter --count --show-source --statistics
flake8 tests --count --show-source --statistics
flake8 tests --count --show-source --statistics --extend-ignore ANN
+5 -3
View File
@@ -4,11 +4,11 @@ on:
push:
branches:
- main
- releases/**
- release
pull_request:
branches:
- main
- releases/**
- release
jobs:
testLinux:
@@ -38,4 +38,6 @@ jobs:
export QT_QPA_PLATFORM=offscreen
pytest -v --cov=novelwriter --timeout=60
- name: Upload to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+5 -3
View File
@@ -4,11 +4,11 @@ on:
push:
branches:
- main
- releases/**
- release
pull_request:
branches:
- main
- releases/**
- release
jobs:
testMac:
@@ -32,4 +32,6 @@ jobs:
export QT_QPA_PLATFORM=offscreen
pytest -v --cov=novelwriter --timeout=60
- name: Upload to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+5 -3
View File
@@ -4,11 +4,11 @@ on:
push:
branches:
- main
- releases/**
- release
pull_request:
branches:
- main
- releases/**
- release
jobs:
testWin:
@@ -28,4 +28,6 @@ jobs:
run: |
pytest -v --cov=novelwriter --timeout=60
- name: Upload to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+6 -7
View File
@@ -22,14 +22,13 @@ just make a pull request directly.
## Picking the Correct Branch for a Pull Request
As of April 2024, pre-releases and point releases (like 2.x) are made from the `main` branch. The
`main` branch is the default branch. For general changes, please make a new branch in your own fork
from the current `main` branch. Do not make pull requests from your copy of the `main` branch.
The `main` branch is the default branch. For general changes, please make a new branch in your own
fork from the current `main` branch. Do not make pull requests from your copy of the `main` branch.
If you are submitting a fix to a current release, say 2.4, you must do so from the correct release
branch. For 2.4 this is `releases/v2.4`. If you make such a fix on the `main` branch, **it cannot
be included in a 2.4.x release**. This also applies to the current documentation published on the
main website.
As of April 2024, releases are made from the `release` branch. If you are submitting a fix to a
current release you must do so from the `release` branch. If you make such a fix on the `main`
branch, **it cannot be included in a patch release**. This also applies to the documentation for
the latest release published on the main website.
**Also check the following:**
+3 -3
View File
@@ -49,9 +49,9 @@ code, please also read the full
Project credits are available in [CREDITS.md](https://github.com/vkbo/novelWriter/blob/main/CREDITS.md).
**Note:** As of April 2024, pre-releases and point releases (2.x) are made from the `main` branch.
Patches are made from `releases/v2.x` branches. So if you're submitting a fix to a current release,
**including changes to documentation**, they must be made to the correct branch.
**Note:** As of April 2024 only pre-releases are made from the `main` branch. Full releases are
made from the `release` branch. So if you're submitting a fix to a current release, **including
changes to documentation**, they must be made to the `release` branch.
### Translations
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 KiB

After

Width:  |  Height:  |  Size: 530 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

+6 -8
View File
@@ -17,14 +17,12 @@ storage for robustness.
:width: 500
The project storage is suitable for version control software, and also well suited for file
synchronisation tools. All text is saved as plain text files with a meta data header. The core
project structure is stored in a single project XML file. Other meta data is saved as JSON files.
See the :ref:`a_breakdown_storage` section for more details.
synchronisation tools. All text is saved as plain text files, and your project data as standard
data formats in XML and JSON. See :ref:`a_storage` for more details.
Any operating system that can run Python 3 and has the Qt 5 libraries should be able to run
novelWriter. It runs fine on Linux, Windows and MacOS, and users have tested it on other platforms
as well. novelWriter can be run directly from the Python source, or installed from packages or with
pip. See :ref:`a_started` for more details.
Any operating system that has Python 3 and the Qt 5 libraries should be able to run novelWriter.
It runs fine on Linux, Windows and MacOS, and users have tested it on other platforms as well.
See :ref:`a_started` for more details.
**Useful Links**
@@ -53,7 +51,6 @@ pip. See :ref:`a_started` for more details.
int_overview
int_started
int_howto
int_customise
int_glossary
.. toctree::
@@ -83,6 +80,7 @@ pip. See :ref:`a_started` for more details.
:caption: Additional Details
:hidden:
more_customise
more_projectformat
more_counting
+9 -14
View File
@@ -19,9 +19,9 @@ Managing the Project
.. dropdown:: Merge Multiple Documents Into One
:animate: fade-in-slide-down
If you need to merge a set of documents in your project into a single document, you can achieve
this by first making a new folder for just that purpose, and drag all the files you want merged
into this folder. Then you can right click the folder, select :guilabel:`Transform` and
If you need to merge a selection of documents in your project into a single document, you can
achieve this by first making a new folder for just that purpose, and drag all the files you want
merged into this folder. Then you can right click the folder, select :guilabel:`Transform` and
:guilabel:`Merge Documents in Folder`.
In the dialog that pops up, the documents will be in the same order as in the folder, but you
@@ -36,7 +36,7 @@ Layout Tricks
The formatting tools available in novelWriter don't allow for complex structures like tables.
However, the editor does render tabs in a similar way that regular word processors do. You can
set the width of a tab in :guilabel:`Preferences`.
set the width of a tab in **Preferences**.
The tab key should have the same distance in the editor as in the viewer, so you can align text
in columns using the tab key, and it should look the same when viewed next to the editor.
@@ -66,18 +66,13 @@ Organising Your Text
Depending on your writing style, you may need to separate between soft and hard scene breaks
within chapters. Like for instance if you switch point-of-view character often.
In such cases you may want to use a scene heading for hard scene breaks and a section heading
for soft scene breaks. The :guilabel:`Build Manuscript` tool will let you add separate
formatting for the two when you generate your manuscript. You can for instance add the common
"``* * *``" for hard breaks and select to hide section breaks, which will just insert an empty
paragraph in their place. See :ref:`a_manuscript_settings` for more details.
Keep in mind that this is not what the section heading is intended for, so the app will not
understand the section heading as a scene, but it will be formatted correctly in the manuscript.
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.
.. versionadded:: 2.4
You can now distinguish between soft and hard scene breaks with a modified scene header. See
:ref:`a_manuscript_settings_head_hard` for more details.
Other Tools
+49 -34
View File
@@ -1,15 +1,21 @@
.. _a_intro:
************
Key Features
************
********
Overview
********
.. _Snowflake: https://www.advancedfictionwriting.com/articles/snowflake-method/
.. _Markdown: https://en.wikipedia.org/wiki/Markdown
At its core, novelWriter is a multi-document plain text editor. It uses a markup syntax inspired by
Markdown_ to apply simple formatting to the text. It also allows for some extended formatting codes
using a shortcode format. See :ref:`a_fmt_shortcodes` for more details.
At its core, novelWriter is a multi-document plain text editor. The idea is to let you edit your
text without having to deal with formatting until you generate a draft document or manuscript.
Instead, you can focus on the writing right from the start.
Of course, you probably need *some* formatting for your text. At the very least you need emphasis.
Most people are familiar with adding emphasis using underscores and asterisks. This formatting
standard comes from Markdown_ and is supported by novelWriter. It also uses Markdown formatting for
defining document headings. If you need more specialised formatting, additional formatting options
are available using a shortcode format. See :ref:`a_fmt_shortcodes` for more details.
.. admonition:: Limitations
@@ -17,22 +23,28 @@ using a shortcode format. See :ref:`a_fmt_shortcodes` for more details.
those relevant for this purpose. It is **not** suitable for technical writing, and it is **not**
a full-featured Markdown editor.
It is also not intended as a tool to organise research for writing, and therefore lacks
It is also not intended as a tool for organising research for writing, and therefore lacks
formatting features you may need for this purpose. The notes feature in novelWriter is mainly
intended for character profiles and plot outlines.
Your novel project is organised as a collection of separate plain text documents instead of a
single, large document. The idea is to make it easier to reorganise your project structure without
having to cut and paste text between chapters.
Your novel project in novelWriter is organised as a collection of separate plain text documents
instead of a single, large document. The idea is to make it easier to reorganise your project
structure without having to cut and paste text between chapters and scenes.
There are two kinds of documents in your project: :term:`Novel Documents` are documents that are
part of your story. The other kind of documents are :term:`Project Notes`. These are intended for
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 single documents. This makes it easier to use variations of the
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
one per act for instance, and later effortlessly split these up into chapters or scenes.
for instance one document per act, and later effortlessly split these up into chapters or scenes.
.. _a_intro_features:
Key Features
============
Below are some key features of novelWriter.
@@ -40,12 +52,12 @@ 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. When you really want to focus on just writing, you can
switch the editor into :guilabel:`Focus Mode` where only the text editor panel itself is
visible, and the project structure view is hidden away.
switch the editor into **Focus Mode** where only the text editor panel itself is visible, and
the project structure view is hidden away.
**Keep an eye on your notes**
The main window can optionally show a document viewer to the right of the editor. This view
panel is intended for displaying another scene document, your character notes, plot notes, or any
The main window can optionally show a document viewer to the right of the editor. The viewer
is intended for displaying another scene document, your character notes, plot notes, or any
other document you may need to reference while writing. It is not intended as a preview panel
for the document you're editing, but if you wish, you can also use it for this purpose.
@@ -58,32 +70,35 @@ Below are some key features of novelWriter.
later split them into multiple documents based on chapter and scene headings.
**Multi-novel project support**
You can have multiple Novel type root folders in a project. 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.
The main parts of your project is split up into top level special folders called "Root" folders.
Your main story text lives in the "Novel" root folder. You can have multiple such folders in a
project. 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.
**Keep track of your story elements**
All notes in your project can be assigned a :term:`tag` that you can :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.
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.
**Get an overview of your story**
In the :guilabel:`Outline View` on the main window you can see an outline of all the chapters,
scenes, and sections of your project. If they have any references in them, 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 the option to add or remove columns of information from this outline. A
subset of the outline information is also available in the :guilabel:`Novel View` as an
alternative view to the project tree.
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 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
the option to add or remove columns of information from this outline. A subset of the outline
information is also available in the **Novel View** as an alternative view to the project tree.
**Get an overview of your story elements**
Under the document viewer panel you will find a series of tabs that shows the different story
elements you have created tags for. The tabs are sorted into Characters, Plots, etc, depending
on which categories you are using in your story. This panel can be hidden to free up space when
you don't need it.
Under the document viewer panel you will find a series of tabs that show the different story
elements you have created tags for. The tabs are sorted into **Characters**, **Plots**, etc,
depending on which categories you are using in your story. This panel can be hidden to free up
space when you don't need it.
**Assembling your manuscript**
Whether you want to assemble a manuscript, or export all your notes, or generate an outline of
your chapters and scenes with a synopsis, you can use the :guilabel:`Build Manuscript` tool to
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, a PDF, or to an Open Document
file that can be opened by most office type word processors. You can also generate the result
@@ -95,7 +110,7 @@ Below are some key features of novelWriter.
Screenshots
===========
.. figure:: images/screenshot_default.png
.. figure:: images/screenshot_light.png
:class: dark-light
novelWriter with light colour theme
+16 -22
View File
@@ -1,28 +1,22 @@
.. _a_overview:
.. _a_reading:
********
Overview
********
******************
What to Read First
******************
.. only:: html
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.
.. image:: images/python_powered.png
:align: right
:width: 220
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
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 project.
novelWriter is built as a cross-platform application using `Python 3 <https://www.python.org/>`_ as
the programming language, and `Qt 5 <https://www.qt.io/>`_ framework for the user interface.
The chapters labelled "Recommended Reading" includes additional information on how the different
parts if the application work and what the features do.
novelWriter is built for Linux first, so this is where it works best. However, it also runs fine
on Windows and MacOS due to the cross-platform framework it's built on. The author of the
application doesn't own a Mac, so on-going Mac support is dependent on user feedback and user
contributions.
Spell checking in novelWriter is provided by a third party library called
`Enchant <https://abiword.github.io/enchant/>`_. Please see the section on :ref:`a_custom_dict` for
how to install spell checking languages.
For install instructions for novelWriter, see :ref:`a_started`.
The "Optional" and "Lookup" chapters contain additional information or lookup tables that are not
essential for using the application.
Using novelWriter
@@ -82,8 +76,8 @@ meta data for it to extract.
the application interface.
:ref:`a_manuscript` - Recommended Reading
This chapter explains how the :guilabel:`Manuscript Build` tool works, how you can control the
way chapter titles are formatted, and how scene and section breaks are handled.
This chapter explains how the **Manuscript Build** tool works, how you can control the way
chapter titles are formatted, and how scene and section breaks are handled.
Additional Details & Technical Topics
+7 -6
View File
@@ -1,8 +1,8 @@
.. _a_started:
***************
Getting Started
***************
**********************
Setup and Installation
**********************
.. _Enchant: https://abiword.github.io/enchant/
.. _GitHub: https://github.com/vkbo/novelWriter
@@ -15,8 +15,8 @@ Getting Started
.. _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 instructions for each
platform.
Linux, Windows and MacOS, from the `Downloads page`_. See below for install additional instructions
for each platform.
You can also install novelWriter from the Python Package Index (PyPi_). See :ref:`a_started_pip`.
Installing from PyPi does not set up icon launchers, so you will either have to do this yourself,
@@ -44,7 +44,7 @@ multiple installations has been known to cause problems.
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 the installer.
see an additional warning about this when you download and run the installer.
.. _a_started_linux:
@@ -56,6 +56,7 @@ A Debian package can be downloaded from the `Downloads page`_, or from the Relea
GitHub_. This package should work on both Debian, Ubuntu and Linux Mint, at least.
If you prefer, you can also add the novelWriter repository on Launchpad to your package manager.
The Launchpad packages `are signed by the author <https://launchpad.net/~vkbo>`__.
Ubuntu
+22 -22
View File
@@ -8,8 +8,8 @@ This is an overview of how words and other counts of your text are performed. Th
should be relatively standard, and are compared to Libre Office Writer rules.
The counts provided in the app on the raw text is meant to be approximate. For more accurate
counts, you need to build your manuscript in the :guilabel:`Manuscript Tool` and check the counts
on the generated preview.
counts, you need to build your manuscript in the **Manuscript Tool** and check the counts on the
generated preview.
Text Word Counts and Stats
@@ -31,11 +31,11 @@ After the above preparation of the text, the following counts are available.
**Character Count**
The character count is the sum of characters per line, including leading and in-text white space
characters, but excluding trailing white space characters. Shortcodes in the text are not
included, but Markdown codes are. Only headers and text are counted.
included, but Markdown codes are. Only headings and text are counted.
**Word Count**
The words count is the sum of blocks of continuous character per line separated by any number of
white space characters or dashes. Only headers and text are counted.
white space characters or dashes. Only headings and text are counted.
**Paragraph Count**
The paragraph count is the number of text blocks separated by one or more empty line. A line
@@ -45,10 +45,10 @@ After the above preparation of the text, the following counts are available.
Manuscript Counts
=================
These are the rules for the counts available for a manuscript in the :guilabel:`Manuscript Tool`.
The rules have been tuned to agree with LibreOffice Writer, but will vary slightly depending on the
content of your text. LibreOffice Writer also counts the text in the page header, which the
Manuscript Tool does not.
These are the rules for the counts available for a manuscript in the **Manuscript Tool**. The rules
have been tuned to agree with LibreOffice Writer, but will vary slightly depending on the content
of your text. LibreOffice Writer also counts the text in the page header, which the **Manuscript
Tool** does not.
The content of each line is counted after all formatting has been processed, so the result will be
more accurate than the counts for text documents elsewhere in the app. The following rules apply:
@@ -63,36 +63,36 @@ more accurate than the counts for text documents elsewhere in the app. The follo
The following counts are available:
**Header Count**
The number of headers in the manuscript.
**Headings**
The number of headings in the manuscript.
**Paragraph Count**
**Paragraphs**
The number of body text paragraphs in the manuscript.
**Total Word Count**
**Words**
The number of words in the manuscript, including any comments and meta data text.
**Text Word Count**
**Words in Text**
The number of words in body text paragraphs, excluding all other text.
**Header Word Count**
The number of words in headers, including inserted formatting like chapter numbers, etc.
**Words in Headings**
The number of words in headings, including inserted formatting like chapter numbers, etc.
**Total Character Count**
The number of characters on all lines, including any comments and meta data text. Paragraph
**Characters**
The number of characters in all lines, including any comments and meta data text. Paragraph
breaks are not counted, but in-paragraph hard line breaks are.
**Text Character Count**
**Character in Text**
The number of characters in body text paragraphs. Paragraph breaks are not counted, but
in-paragraph hard line breaks are.
**Header Character Count**
**Characters in Headings**
The number of characters in headings.
**Text Words Character Count**
**Character in Text, No Spaces**
The number of characters in body text paragraphs considered part of a word or punctuation. That
is, white space characters are not counted.
**Header Words Character Count**
The number of characters in headers considered part of a word or punctuation. That is, white
**Character in Headings, No Spaces**
The number of characters in headings considered part of a word or punctuation. That is, white
space characters are not counted.
@@ -34,10 +34,10 @@ and add dictionaries yourself.
**Install Tool**
A small tool to assist with this can be found under :guilabel:`Tools > Add Dictionaries`. It will
import spell checking dictionaries from Free Office or Libre Office extensions. The dictionaries
are then installed in the install location for the Enchant library and should thus work for any
application that uses Enchant for spell checking.
A small tool to assist with this can be found under **Tools > Add Dictionaries**. It will import
spell checking dictionaries from Free Office or Libre Office extensions. The dictionaries are then
installed in the install location for the Enchant library and should thus work for any application
that uses Enchant for spell checking.
**Manual Install**
@@ -81,14 +81,14 @@ modify it as you like.
`novelwriter/assets/icons <https://github.com/vkbo/novelWriter/tree/main/novelwriter/assets/icons>`_.
Remember to also change the name of your theme by modifying the ``name`` setting at the top of the
file, otherwise you may not be able to distinguish them in :guilabel:`Preferences`.
file, otherwise you may not be able to distinguish them in **Preferences**.
For novelWriter to be able to locate the custom theme files, you must copy them to the
:ref:`a_locations_data` location in your home or user area. There should be a folder there named
``syntax`` for syntax themes, just ``themes`` for GUI themes, and ``icons`` for icon themes. These
folders are created the first time you start novelWriter.
Once the files are copied there, they should show up in :guilabel:`Preferences` with the label you
Once the files are copied there, they should show up in **Preferences** with the label you
set as ``name`` inside the file.
.. versionadded:: 2.0
@@ -190,10 +190,10 @@ Omitted syntax colours default to black, except ``background`` which defaults to
``texthighlight`` which defaults to white with half transparency.
.. versionadded:: 2.2
The `shortcode` syntax colour entry was added.
The ``shortcode`` syntax colour entry was added.
.. versionadded:: 2.3
The `optional` syntax colour entry was added.
The ``optional`` syntax colour entry was added.
.. versionadded:: 2.4
The `texthighlight` syntax colour entry was added.
The ``texthighlight`` syntax colour entry was added.
+57 -35
View File
@@ -4,9 +4,11 @@
Building the Manuscript
***********************
.. _Pandoc: https://pandoc.org/
You can at any time build a manuscript, an outline of your notes, or any other type of document
from the text in your project. All of this is handled by the :guilabel:`Manuscript Build` tool.
You can activate it from the sidebar, the :guilabel:`Tools` menu, or by pressing :kbd:`F5`.
from the text in your project. All of this is handled by the **Manuscript Build** tool. You can
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
@@ -20,40 +22,60 @@ The Manuscript Build Tool
=========================
.. figure:: images/fig_manuscript_build.png
:width: 80%
The :guilabel:`Manuscript Build` tool main window.
The **Manuscript Build** tool main window.
The main window of the :guilabel:`Manuscript Build` tool contains a list of all the builds you have
The main window of the **Manuscript Build** tool contains a list of all the builds you have
defined, a selection of settings, and a few buttons to generate preview, open the print dialog, or
run the build to create a manuscript document.
Outline and Word Counts
-----------------------
.. figure:: images/fig_manuscript_build_outline.png
:width: 80%
The **Manuscript Build** tool main window with the **Outline** visible.
The **Outline** tab on the left lets you navigate the headings in the preview document. It will
show up to scene level headings for novel documents, and level 2 headings for notes.
A collapsible panel of word and character counts are also available below the preview document.
These are calculated from the text you have included in the document, and are more accurate counts
than what's available in the project tree since they are counted *after formatting*.
For a detailed description on how they are counted, see :ref:`a_counting`.
.. _a_manuscript_settings:
Build Settings
==============
Each build definition can be edited by opening it in the :guilabel:`Manuscript Build Settings`
dialog, either by double-clicking or by selecting it and pressing the edit button in the toolbar.
Each build definition can be edited by opening it in the **Manuscript Build Settings** dialog,
either by double-clicking or by selecting it and pressing the edit button in the toolbar.
.. tip::
You can keep the :guilabel:`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 :guilabel:`Manuscript Build` window.
When you're happy with the result, you can close the settings.
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
the result, you can close the settings.
Document Selection
------------------
.. figure:: images/fig_build_settings_selections.png
:width: 80%
The :guilabel:`Selections` page of the :guilabel:`Manuscript Build Settings` dialog.
The **Selections** page of the **Manuscript Build Settings** dialog.
The :guilabel:`Selections` page of the :guilabel:`Manuscript Build Settings` dialog allows you to
fine tune which documents are included in the build. They are indicated by a green arrow icon in
the last column. On the right you have some filter options for selecting content of a specific
type, and a set of switches for which root folders to include.
The **Selections** page of the **Manuscript Build Settings** dialog allows you to fine tune which
documents are included in the build. They are indicated by a green arrow icon in the last column.
On the right you have some filter options for selecting content of a specific type, and a set of
switches for which root folders to include.
You can override the result of these filters by marking one or more documents and selecting to
explicitly include or exclude them by using the buttons below the tree view. The last button can be
@@ -69,13 +91,14 @@ Formatting Headings
-------------------
.. figure:: images/fig_build_settings_headings.png
:width: 80%
The :guilabel:`Headings` page of the :guilabel:`Manuscript Build Settings` dialog.
The **Headings** page of the **Manuscript Build Settings** dialog.
The :guilabel:`Headings` page of the :guilabel:`Manuscript Build Settings` dialog allows you to set
how the headings in your :term:`Novel Documents` are formatted. By default, the title is just
copied as-is, indicated by the ``{Title}`` format. You can change this to for instance add chapter
numbers and scene numbers, or insert character names, like shown in the figure above.
The **Headings** page of the **Manuscript Build Settings** dialog allows you to set how the
headings in your :term:`Novel Documents` are formatted. By default, the title is just copied as-is,
indicated by the ``{Title}`` format. You can change this to for instance add chapter numbers and
scene numbers, or insert character names, like shown in the figure above.
Clicking the edit button next to a format will copy the formatting string into the edit box where
it can be modified, and where a syntax highlighter will help indicate which parts are automatically
@@ -86,7 +109,7 @@ Any text you add that isn't highlighted in colours will remain in your formatted
``{Title}`` will always be replaced by the text in the heading from your documents.
You can preview the result of these format strings by clicking :guilabel:`Apply`, and then clicking
:guilabel:`Preview` in the :guilabel:`Manuscript Build` tool main window.
:guilabel:`Preview` in the **Manuscript Build** tool main window.
Scene Separators
@@ -107,10 +130,9 @@ be treated as a separator.
Hard and Soft Scenes
^^^^^^^^^^^^^^^^^^^^
If you wish to distinguish between so-called soft and hard scene breaks, where a hard scene break
is understood as a scene break that changes point-of-view character, you can use the modified scene
heading format in your text. You can then give these headings a different formatting in the
:guilabel:`Headings` settings.
If you wish to distinguish between so-called soft and hard scene breaks, you can use the
alternative scene heading format in your text. You can then give these headings a different
formatting in the **Headings** settings.
See :ref:`a_fmt_head` for more info on how to format headings in your text.
@@ -118,10 +140,9 @@ See :ref:`a_fmt_head` for more info on how to format headings in your text.
Output Settings
---------------
The :guilabel:`Content`, :guilabel:`Format` and :guilabel:`Output` pages of the
:guilabel:`Manuscript Build Settings` dialog control a number of other settings for the output.
Some of these only apply to specific output formats, which is indicated by the section headings on
the settings pages.
The **Content**, **Format** and **Output** pages of the **Manuscript Build Settings** dialog
control a number of other settings for the output. Some of these only apply to specific output
formats, which is indicated by the section headings on the settings pages.
.. _a_manuscript_build:
@@ -130,12 +151,13 @@ Building Manuscript Documents
=============================
.. figure:: images/fig_build_build.png
:width: 80%
The :guilabel:`Manuscript Build` dialog used for writing the actual manuscript documents.
The **Manuscript Build** dialog used for writing the actual manuscript documents.
When you press the :guilabel:`Build` button on the :guilabel:`Build Manuscript` tool main window, a
special file dialog opens up. This is where you pick your desired output format and where to write
the file.
When you press the :guilabel:`Build` button on the **Build Manuscript** tool main window, a special
file dialog opens up. This is where you pick your desired output format and where to write the
file.
On the left side of the dialog is a list of all the available file formats, and on the right, a
list of the documents which are included based on the build definition you selected. You can choose
@@ -157,7 +179,7 @@ Open Document Format
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
is suitable for further processing by document conversion tools like Pandoc_, for importing in
word processors, or for printing from browser.
novelWriter Markup
@@ -198,4 +220,4 @@ 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 :guilabel:`Print Preview` dialog.
change it, you have to select it from the **Print Preview** dialog.
+122 -113
View File
@@ -4,25 +4,27 @@
Novel Projects
**************
New projects can be created from the :guilabel:`Project` menu by selecting
:guilabel:`Create or Open Project`. This will open the :guilabel:`Welcome` dialog, where you can
select the :guilabel:`New` button that will assist you in creating a new project.
New projects can be created from the **Project** menu by selecting **Create or Open Project**. This
will open the **Welcome** dialog, where you can select the :guilabel:`New` button that will assist
you in creating a new project. This dialog is also displayed when you start novelWriter.
A novelWriter project requires a dedicated folder for storing its files on the local file system.
If you're interested in the details, you can have a look at the chapter :ref:`a_storage`.
A list of recently opened projects is maintained, and displayed in the :guilabel:`Welcome`
dialog. A project can be removed from this list by selecting it and pressing the :kbd:`Del` key or
by right-clicking it and selecting the :guilabel:`Remove Project` option.
A list of recently opened projects is maintained, and displayed in the **Welcome** dialog. A
project can be removed from this list by selecting it and pressing the :kbd:`Del` key or by
right-clicking it and selecting the **Remove Project** option.
.. figure:: images/fig_welcome.jpg
The project list (left) and new project form (right) of the :guilabel:`Welcome` dialog.
Project-specific settings are available in :guilabel:`Project Settings` in the :guilabel:`Project`
menu. See further details below in the :ref:`a_proj_settings` section. Details about the project's
novel text, including word counts, and a table of contents with word and page counts, is available
through the :guilabel:`Novel Details` dialog.
Project-specific settings are available in **Project Settings** in the **Project** menu. See
further details below in the :ref:`a_proj_settings` section.
Details about the project's novel text, including word counts, and a table of contents with word
and page counts, is available through the **Novel Details** dialog. Statistics about the project
is also available in the **Manuscript Build** tool.
.. _a_proj_roots:
@@ -33,64 +35,70 @@ Project Roots
Projects are structured into a set of top level folders called "Root Folders". They are visible in
the project tree at the left side of the main window.
The :term:`novel documents` go into a root folder of type :guilabel:`Novel`. :term:`Project notes`
go into the other root folders. These other root folder types are intended for your notes on the
various elements of your story. Using them is of course entirely optional.
The :term:`novel documents` go into a root folder of type **Novel**. :term:`Project notes` go into
the other root folders. These other root folder types are intended for your notes on the various
elements of your story. Using them is of course entirely optional.
A new project may not have all of the root folders present, but you can add the ones you want from
the project tree tool bar.
Each root folder has one or more :term:`reference` :term:`keyword` associated with it that is used
to reference them from other documents and notes. The intended usage of each type of root folder is
listed below. However, aside from the :guilabel:`Novel` folder, no restrictions are applied by the
listed below. However, aside from the **Novel** folder, no restrictions are applied by the
application on what you put in them. You can use them however you want.
The root folder system is closely connected to how the Tags and References system works. For more
details, see the :ref:`a_references` chapter.
:guilabel:`Novel`
Root Folder Types
-----------------
**Novel**
This is the root folder type for text that goes into the final novel or novels. This class of
documents have other rules and features than the project notes. See :ref:`a_struct` for more
details.
:guilabel:`Plot`
**Plot**
This is the root folder type where main plots can be outlined. It is optional, but adding at
least brief notes can be useful in order to tag plot elements for the :guilabel:`Outline View`.
Tags in this folder can be references using the ``@plot`` keyword.
least brief notes can be useful in order to tag plot elements for the **Outline View**. Tags in
this folder can be references using the ``@plot`` keyword.
:guilabel:`Characters`
**Characters**
Character notes go in this root folder type. These are especially important if you want to use
the :guilabel:`Outline View` to see which character appears where, which part of the story is
told from a specific character's point-of-view, or focusing on a particular character's
storyline. The character names can also be inserted into for instance chapter titles when you
create your manuscript. Tags in this type of folder can be referenced using the ``@pov`` keyword
for point-of-view characters, ``@focus`` for a focus character, or the ``@char`` keyword for any
the **Outline View** to see which character appears where, which part of the story is told from
a specific character's point-of-view, or focusing on a particular character's storyline.
The character names can also be inserted into for instance chapter titles when you create your
manuscript. Tags in this type of folder can be referenced using the ``@pov`` keyword for
point-of-view characters, ``@focus`` for a focus character, or the ``@char`` keyword for any
other character present.
:guilabel:`Locations`
**Locations**
The locations folder type is for various scene locations that you want to track. Tags in this
folder can be references using the ``@location`` keyword.
:guilabel:`Timeline`
**Timeline**
If the story has multiple plot timelines or jumps in time within the same plot, this folder type
can be used to track this. Tags in this type of folder can be references using the ``@time``
keyword.
:guilabel:`Objects`
Important objects in the story, for instance objects that change hands often, can be tracked
here. Tags in this type of folder can be references using the ``@object`` keyword.
**Objects**
Important objects in the story, for instance physical objects that change hands often, can be
tracked here. Tags in this type of folder can be references using the ``@object`` keyword.
:guilabel:`Entities`
**Entities**
Does your plot have many powerful organisations or companies? Or other entities that are part of
the plot? They can be organised here. Tags in this type of folder can be references using the
``@entity`` keyword.
:guilabel:`Custom`
**Custom**
The custom root folder type can be used for tracking anything else not covered by the above
options. Tags in this folder type can be references using the ``@custom`` keyword.
The root folders correspond to the categories of tags that can be used to reference them. For more
information about the tags listed, see :ref:`a_references_references`.
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`.
.. note::
You can rename root folders to whatever you want. However, this doesn't change the reference
@@ -105,12 +113,11 @@ information about the tags listed, see :ref:`a_references_references`.
Deleted Documents
-----------------
Deleted documents will be moved into a special :guilabel:`Trash` root folder. Documents in the
trash folder can then be deleted permanently, either individually, or by emptying the trash from
the menu. Documents in the trash folder are removed from the :term:`project index` and cannot be
referenced.
Deleted documents are moved into a special **Trash** root folder. Documents in the trash folder can
then be deleted permanently, either individually, or by emptying the trash from the menu. Documents
in the trash folder are removed from the :term:`project index` and cannot be referenced.
A document or a folder can be moved to trash from the :guilabel:`Project` menu, or by pressing
A document or a folder can be moved to trash from the **Project** menu, or by pressing
:kbd:`Ctrl+Shift+Del`. Root folders can only be removed when they are empty.
@@ -119,13 +126,34 @@ A document or a folder can be moved to trash from the :guilabel:`Project` menu,
Archived Documents
------------------
If you don't want to delete a document, or put it in the :guilabel:`Trash` folder where it may be
deleted accidentally, but still want it out of your main project tree, you can create an
:guilabel:`Archive` root folder and move it there.
If you don't want to delete a document, or put it in the **Trash** folder where it may be deleted
accidentally, but still want it out of your main project tree, you can create an **Archive** root
folder instead and move it there. It has the same effect as moving it to **Trash**, but it is safe
from deletion.
You can drag any document to this folder and preserve its settings. The document will always be
excluded from the :guilabel:`Build Manuscript` tool. It is also removed from the
:term:`project index`, so the tags and references defined in it will not show up anywhere else.
excluded from the **Build Manuscript** tool. It is also removed from the :term:`project index`, so
the tags and references defined in it will not show up anywhere else.
.. _a_proj_roots_dirs:
Using Folders in the Project Tree
---------------------------------
Regular folders, those that are not root folders, have no structural significance to the project.
When novelWriter is processing the documents in a project, like for instance when you create a
manuscript from it, these folders are ignored. Only the order of the documents themselves matter.
The folders are there purely as a way for you to organise the documents in meaningful sections and
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.
.. _a_proj_roots_orphaned:
@@ -143,8 +171,8 @@ previously have been located in the project. The project loading routine will tr
as close as possible to this location, if it still exists. Generally, it will be appended to the
end of the folder where it previously was located. If that folder doesn't exist, it will try to add
it to the correct root folder type. If it cannot figure out which root folder is correct, the
document will be added to the :guilabel:`Novel` root folder. Finally, if the :guilabel:`Novel`
folder is missing, one will be created.
document will be added to the **Novel** root folder. Finally, if a **Novel** does not exist, one
will be created.
If the title of the document can be recovered, the word "Recovered:" will be added as a prefix to
indicate that it may need further attention. If the title cannot be determined, the document will
@@ -157,15 +185,16 @@ 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. If you try
to open a project which 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.
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 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.
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
@@ -175,52 +204,31 @@ option to ignore this warning, and continue opening the project at your own risk
novelWriter will try to resolve project inconsistencies the next time you open the project.
.. _a_proj_roots_dirs:
Using Folders in the Project Tree
---------------------------------
Folders, aside from root folders, have no structural significance to the project. When novelWriter
is processing the documents in a project, like for instance when you create a manuscript from it,
these folders are ignored. Only the order of the documents themselves matter.
The folders are there purely as a way for you to organise the documents in meaningful sections and
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.
.. _a_proj_files:
Project Documents
=================
New documents can be created from the toolbar in the :guilabel:`Project Tree`, or by pressing
:kbd:`Ctrl+N`. This will open the create new item menu and let you choose between a number of
pre-defined documents and folders. You will be prompted for a label for the new item.
New documents can be created from the toolbar in the project tree, or by pressing :kbd:`Ctrl+N`.
This will open the create new item menu and let you choose between a number of pre-defined
documents and folders. You will be prompted for a label for the new item.
You can always rename an item by selecting :guilabel:`Rename Item` from the :guilabel:`Project`
menu, or by pressing :kbd:`F2`.
You can always rename an item by selecting **Rename Item** from the **Project** menu, or by
pressing :kbd:`F2` when a document or folder is selected.
Other settings for project items are available from the context menu that you can activate by
right-clicking on an item in the tree. The :guilabel:`Transform` submenu includes options for
converting, splitting, or merging items. See :ref:`a_ui_tree_split_merge` for more details on the
latter two.
Other settings for project documents and folders are available from the context menu that you can
activate by right-clicking on an it in the tree. The **Transform** submenu includes options for
converting, splitting, or merging documents. See :ref:`a_ui_tree_split_merge` for more details on
the latter two.
Document Templates
------------------
If you wish to create template documents to be used when creating new project documents, like for
instance a character note template, you can add a :guilabel:`Templates` root folder to your
project. Any document added to this root folder will show up in the :guilabel:`Add Item` menu in
the project tree toolbar. When selected, a new document is created with its content copied from the
chosen template.
instance a character note template, you can add a **Templates** root folder to your project. Any
document added to this root folder will show up in the **Add Item** menu in the project tree
toolbar. When selected, a new document is created with its content copied from the chosen template.
.. versionadded:: 2.3
@@ -233,8 +241,8 @@ Word Counts
A character, word and paragraph count is maintained for each document, as well as for each section
of a document following a :term:`heading<headings>`. The word count and change of words in the
current session is displayed in the footer of any document open in the editor, and all stats are
shown in the details panel below the :guilabel:`Project Tree` for any document selected in the
project or novel trees.
shown in the details panel below the project tree for any document selected in the project or novel
trees.
The word counts are not updated in real time, but run in the background every few seconds for as
long as the document is being actively edited.
@@ -242,7 +250,7 @@ long as the document is being actively edited.
A total project word count is displayed in the status bar. The total count depends on the sum of
the values in the project tree, which again depend on an up to date :term:`project index`. If the
counts seem wrong, a full project word recount can be initiated by rebuilding the project's index.
Either from the :guilabel:`Tools` menu, or by pressing :kbd:`F9`.
Either from the **Tools** menu, or by pressing :kbd:`F9`.
The rules for how the counts are made is covered in more detail in :ref:`a_counting`.
@@ -252,33 +260,35 @@ The rules for how the counts are made is covered in more detail in :ref:`a_count
Project Settings
================
The :guilabel:`Project Settings` can be accessed from the :guilabel:`Project` menu, or by pressing
The **Project Settings** can be accessed from the **Project** menu, or by pressing
:kbd:`Ctrl+Shift+,`. This will open a dialog box, with a set of tabs.
Settings Tab
------------
The :guilabel:`Settings` tab holds the project name, title, and author settings.
The **Settings** tab holds the project name, author, and language settings.
The :guilabel:`Project Name` can be edited here. It is used for the GUI (main window title) and for
generating backup files. So keep in mind that if you do change this setting, the backup file names
will change too.
The **Project Name** can be edited here. It is used for the main window title and for generating
backup files. So keep in mind that if you do change this setting, the backup file names will change
too.
You can also change the :guilabel:`Authors` and :guilabel:`Project Language` setting. These are
only used when building the manuscript, for some formats.
You can also change the **Authors** and **Project Language** setting. These are only used when
building the manuscript, for some formats. The language setting is also used when inserting text
into documents in the viewer, like for instance labels for keywords and special comments.
If your project is in a different language than your main spell checking language is set to, you
can override the default setting here. The project language can also be changed from the
:guilabel:`Tools` menu. You can also override the automatic backup setting if you wish.
can override the default setting here. The project language can also be changed from the **Tools**
menu.
You can also override the automatic backup setting for the project if you wish.
Status and Importance Tabs
--------------------------
Each document or folder of type :guilabel:`Novel` can be given a "Status" label accompanied by a
coloured icon, and each document or folder of the remaining types can be given an "Importance"
label.
Each document or folder of type **Novel** can be given a "Status" label accompanied by a coloured
icon, and each document or folder of the remaining types can be given an "Importance" label.
These labels are there purely for your convenience, and you are not required to use them for any
other features to work. No other part of novelWriter accesses this information. The intention is to
@@ -316,22 +326,22 @@ Backup
======
An automatic backup system is built into novelWriter. In order to use it, a backup path to where
the backup files are to be stored must be provided in :guilabel:`Preferences`.
the backup files are to be stored must be provided in **Preferences**. The path defaults to a
folder named "Backups" in your home directory.
Backups can be run automatically when a project is closed, which also implies it is run when the
application itself is closed. Backups are date stamped zip files of the project files in the
project folder (files not strictly a part of the project are ignored). The zip archives are stored
in a subfolder of the backup path. The subfolder will have the same name as the
:guilabel:`Project Name` as defined in :ref:`a_proj_settings`.
in a subfolder of the backup path. The subfolder will have the same name as the **Project Name** as
defined in :ref:`a_proj_settings`.
The backup feature, when configured, can also be run manually from the :guilabel:`Tools` menu.
It is also possible to disable automated backups for a given project in
:guilabel:`Project Settings`.
The backup feature, when configured, can also be run manually from the **Tools** menu. It is also
possible to disable automated backups for a given project in **Project Settings**.
.. note::
For the backup to be able to run, the :guilabel:`Project Name` must be set in
:guilabel:`Project Settings`. This value is used to generate the name and path of the backups.
Without it, the backup will not run at all, but it will produce a warning message.
For the backup to be able to run, the **Project Name** must be set in **Project Settings**. This
value is used to generate the name and path of the backups. Without it, the backup will not run
at all, but it will produce a warning message.
.. _a_proj_stats:
@@ -344,9 +354,8 @@ total word counts of your novel documents and notes at the end of the session, p
session lasted either more than 5 minutes, or that the total word count changed. For more details
about the log file, see :ref:`a_storage`.
A tool to view the content of the log file is available in the :guilabel:`Tools` menu under
:guilabel:`Writing Statistics`. You can also launch it by pressing :kbd:`F6`, or find it on the
sidebar.
A tool to view the content of the log file is available in the **Tools** menu under **Writing
Statistics**. You can also launch it by pressing :kbd:`F6`, or find it on the sidebar.
The tool will show a list of all your sessions, and a set of filters to apply to the data. You can
also export the filtered data to a JSON file or to a CSV file that can be opened by a spreadsheet
@@ -356,4 +365,4 @@ application like for instance Libre Office Calc or Excel.
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 :guilabel:`Preferences`.
in **Preferences**.
+34 -35
View File
@@ -16,9 +16,9 @@ this chapter hopes to explain in more detail how to use this tags and references
.. 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 :guilabel:`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.
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.
.. _a_references_metadata:
@@ -68,7 +68,7 @@ You can only set **one** tag per heading, and the tag has to be unique across **
the project.
After a tag has been defined, it can be referenced in novel documents, or cross-referenced in other
notes. Tags will also show up in the :guilabel:`Outline View` and in the references panel under the
notes. Tags will also show up in the **Outline View** and in the references panel under the
document viewer when a document is open in the viewer.
The syntax highlighter will indicate to you that the keyword is correctly used and that the tag is
@@ -79,7 +79,7 @@ that valid tags do.
The tag is the only part of these notes that novelWriter uses. The rest of the document content is
there for you to use in whatever way you wish. Of course, the content of the documents can be added
to the manuscript, or an outline document. If you want to compile a single document of all your
notes, you can do this from the :guilabel:`Manuscript Build` tool.
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
@@ -117,8 +117,8 @@ How to Use References
=====================
Each heading of any level in your project can contain references to tags set in project notes. The
references are gathered by the indexer and used to generate the :guilabel:`Outline View`, among
other things.
references are gathered by the indexer and used to generate the **Outline View**, among other
things.
References are set as a :term:`keyword` and a list of corresponding tags. The valid keywords are
listed below. The format of a reference line is ``@keyword: value1, [value2] ... [valueN]``. All
@@ -126,70 +126,69 @@ reference keywords allow multiple values.
``@pov``
The point-of-view character for the current section. The target must be a note tag in a
:guilabel:`Character` type root folder.
**Character** type root folder.
``@focus``
The character that has the focus for the current section. This can be used in cases where the
focus is not a point-of-view character. The target must be a note tag in a :guilabel:`Character`
type root folder.
focus is not a point-of-view character. The target must be a note tag in a **Character** type
root folder.
``@char``
Other characters in the current section. The target must be a note tag in a
:guilabel:`Character` type root folder. This should not include the point-of-view or focus
character if those references are used.
Other characters in the current section. The target must be a note tag in a **Character** type
root folder. This should not include the point-of-view or focus character if those references
are used.
``@plot``
The plot or subplot advanced in the current section. The target must be a note tag in a
:guilabel:`Plot` type root folder.
The plot or subplot advanced in the current section. The target must be a note tag in a **Plot**
type root folder.
``@time``
The timelines touched by the current section. The target must be a note tag in a
:guilabel:`Timeline` type root folder.
The timelines touched by the current section. The target must be a note tag in a **Timeline**
type root folder.
``@location``
The location the current section takes place in. The target must be a note tag in a
:guilabel:`Locations` type root folder.
**Locations** type root folder.
``@object``
Objects present in the current section. The target must be a note tag in a :guilabel:`Object`
type root folder.
Objects present in the current section. The target must be a note tag in a **Object** type root
folder.
``@entity``
Entities present in the current section. The target must be a note tag in a
:guilabel:`Entities` type root folder.
Entities present in the current section. The target must be a note tag in an **Entities** type
root folder.
``@custom``
Custom references in the current section. The target must be a note tag in a :guilabel:`Custom`
type root folder. The custom folder are for any other category of notes you may want to use.
Custom references in the current section. The target must be a note tag in a **Custom** type
root folder. The custom folder are for any other category of notes you may want to use.
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 :guilabel:`Rebuild Index` from the :guilabel:`Tools` menu.
In general, the index for a document is regenerated when it is saved, so this shouldn't normally
be necessary.
: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 :guilabel:`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 must already exist.
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
must already exist.
One note can also reference another note in the same way novel documents do. When the note is
opened in the document viewer, the references become clickable links, making it easier to follow
connections in the plot. You can follow links in the document editor by clicking them with the
mouse while holding down the :kbd:`Ctrl` key. Clicked links are always opened in the view panel.
Project notes don't show up in the :guilabel:`Outline View`, so referencing between notes is only
Project notes don't show up in the **Outline View**, so referencing between notes is only
meaningful if you want to be able to click-navigate between them, or of course if you just want to
highlight that two notes are related.
.. tip::
If you cross-reference between notes and export your project as an HTML document using the
:guilabel:`Manuscript Build` tool, the cross-references become clickable links in the exported
HTML document as well.
**Manuscript Build** tool, the cross-references become clickable links in the exported HTML
document as well.
Example of a novel document with references to characters and plots:
@@ -217,7 +216,7 @@ character ``@`` on a new line. It will first suggest tag or reference keywords f
after the ``:`` has been added, suggest references from the list of tags you have already defined.
You can use the auto-completer to add multiple references with a ``,`` between them, and even type
new ones. New references can be created by right-clicking on them and selecting
:guilabel:`Create Note for Tag` from the menu.
new ones. New references can be created by right-clicking on them and selecting **Create Note for
Tag** from the menu.
.. versionadded:: 2.2
+57 -39
View File
@@ -6,14 +6,13 @@ Novel Structure
This chapter covers the structure of a novel project.
There are two different types of documents in a project, :guilabel:`Novel Documents` and
:guilabel:`Project Notes`. Active novel documents can only live in a :guilabel:`Novel` type root
folder. You can also move them to :guilabel:`Archive` and :guilabel:`Trash` of course, where they
become inactive.
There are two different types of documents in a project, **Novel Documents** and **Project Notes**.
Active novel documents can only live in a **Novel** type root folder. You can also move them to
**Archive** and **Trash** of course, where they become inactive.
The :guilabel:`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
:guilabel:`Preferences`.
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.
.. _a_struct_heads:
@@ -29,40 +28,41 @@ title. See also the :ref:`a_fmt` section for more details about the markup synta
.. 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 :guilabel:`Outline View` as well as in the
:guilabel:`Novel Tree`. Each heading also starts a new region where new Tags and References
can be defined. See :ref:`a_references` for more details.
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
:ref:`a_references` for more details.
The syntax for the four basic heading types, and the two special types, is listed in section
The syntax for the four basic heading types, and the three special types, is listed in section
:ref:`a_fmt_head`. The meaning of the four levels for the structure of your novel is as follows:
**Heading Level 1: Partition**
This heading level signifies that the text refers to a top level partition. This is useful when
This heading level signifies that the text refers to a top level heading. This is useful when
you want to split the manuscript up into books, parts, or acts. These headings are not required.
The novel title itself should use the special heading level ``#!`` covered in :ref:`a_fmt_head`.
**Heading Level 2: Chapter**
This heading level signifies a chapter level partition. Each time you want to start a new
chapter, you must add such a heading. If you choose to split your manuscript up into one
document per scene, you need a single chapter document with just the heading. You can of course
also add a synopsis and reference keywords to the chapter document. If you want to open the
chapter with a quote or other introductory text that isn't part of a scene, this is also where
you'd put that text.
This heading level signifies a chapter. Each time you want to start a new chapter, you must add
such a heading. If you choose to split your manuscript up into one document per scene, you need
a single chapter document with just the heading. You can of course also add a synopsis and
reference keywords to the chapter document. If you want to open the chapter with a quote or
other introductory text that isn't part of a scene, this is also where you'd put that text.
**Heading Level 3: Scene**
This heading level signifies a scene level partition. You must provide a title text, but the
title text can be replaced with a scene separator or just skipped entirely when you build your
manuscript.
This heading level signifies a scene. You must provide a title text, but the title text can be
replaced with a scene separator or just skipped entirely when you build your manuscript. If you
need to distinguish between hard and soft scene breaks, there is an alternative format for
scenes you can use for this distinction. The formatting is covered in :ref:`a_fmt_head`. See
also :ref:`a_struct_heads_scenes`.
**Heading Level 4: Section**
This heading level signifies a sub-scene level partition, usually called a "section" in the
This heading level can be used to split up a scene, usually called a "section" in the
documentation and the user interface. These can be useful if you want to change references
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 just like with scene titles.
wish, and you can filter them out of the final manuscript.
Page breaks are automatically added before partition and chapter headings 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 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
@@ -76,9 +76,9 @@ specify them manually. See :ref:`a_fmt_break`.
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
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:
.. code-block:: md
@@ -102,7 +102,7 @@ Unnumbered Chapter Headings
If you use the automatic numbering feature for your chapters, but you want to keep some special
chapters separate from this, you can add an ``!`` to the level 2 heading formatting code to tell
the build tool to skip these chapters.
the build tool to skip these chapters when adding numbers.
.. code-block:: md
@@ -110,13 +110,31 @@ the build tool to skip these chapters.
Chapter Text
There is a separate formatting feature for such chapter titles in the :guilabel:`Manuscript Build`
tool as well. See the :ref:`a_manuscript` page for more details. When building a document of a
format that supports page breaks, also unnumbered chapters will have a page break added just like
for normal chapters.
There is a separate formatting feature for such chapter titles in the **Manuscript Build** tool as
well. See the :ref:`a_manuscript` page for more details. When building a document of a format that
supports page breaks, also unnumbered chapters can have a page break added just like for normal
chapters.
.. Note::
Previously, you could also disable the automatic numbering of a chapter by adding an ``*`` as
the first character of the chapter title itself. This feature has been dropped in favour of the
current format in order to keep level 1 and 2 headers consistent. Please update your chapter
headings if you've used this syntax.
.. _a_struct_heads_scenes:
Hard and Soft Scene Breaks
--------------------------
If you need two different ways to style scenes in your manuscript, like if you want to insert
different scene separators for soft and hard scene breaks, there is an alternative scene format
available for scene headings with a ``!`` added to the formatting code.
.. code-block:: md
### Soft Scene Transition
A soft scene break.
###! Hard Scene Transition
A hard scene break.
There is a separate formatting feature for these titles in the **Manuscript Build** tool.
.. versionadded:: 2.4
+14 -7
View File
@@ -15,10 +15,9 @@ file locations are described in this chapter.
Configuration
=============
The general configuration of novelWriter, including everything that is in :guilabel:`Preferences`,
is saved in one central configuration file. The location of this file depends on your operating
system. The system paths are provided by the Qt QStandardPaths_ class and its ``ConfigLocation``
value.
The general configuration of novelWriter, including everything that is in **Preferences**, is saved
in one central configuration file. The location of this file depends on your operating system. The
system paths are provided by the Qt QStandardPaths_ class and its ``ConfigLocation`` value.
The standard paths are:
@@ -40,9 +39,8 @@ Application Data
================
novelWriter also stores a bit of data that is generated by the user's actions. This includes the
list of recent projects form the :guilabel:`Open Project` dialog. Custom themes should also be
saved here. The system paths are provided by the Qt QStandardPaths_ class and its
``AppDataLocation`` value.
list of recent projects form the **Welcome** dialog. Custom themes should also be saved here. The
system paths are provided by the Qt QStandardPaths_ class and its ``AppDataLocation`` value.
The standard paths are:
@@ -56,3 +54,12 @@ user's username on Windows.
.. note::
These are the standard operating system defined locations. If your system has been set up in a
different way, these locations may also be different.
The Application Data location also holds several folders:
``cache``
This folder is used to save the preview data for the **Manuscript Build** tool.
``icons``, ``syntax`` and ``themes``
These folders are empty by default, but this is where the user can store custom theme files.
See :ref:`a_custom` for more details.
+2 -3
View File
@@ -159,6 +159,5 @@ You can also build a PDF manual from the documentation using the ``pkgutils.py``
python pkgutils.py manual
This will build the documentation as a PDF using LaTeX. The file will then be copied into the
assets folder and made available in the :guilabel:`Help` menu in novelWriter. The Sphinx build
system has a few extra dependencies when building the PDF. Please check the `Sphinx Docs`_ for more
details.
assets folder and made available in the **Help** menu in novelWriter. The Sphinx build system has a
few extra dependencies when building the PDF. Please check the `Sphinx Docs`_ for more details.
+12 -12
View File
@@ -55,10 +55,10 @@ string. The documents are saved with a filename assembled from this handle and t
``.nwd``.
If you wish to find the file system location of a document in the project, you can either look it
up in the project XML file, select :guilabel:`Show File Details` from the :guilabel:`Document` menu
when having the document open in the editor, or look in the ``ToC.txt`` file in the root of the
project folder. The ``ToC.txt`` file has a list of all documents in the project, referenced by
their label, and where they are saved.
up in the project XML file, select **Show File Details** from the **Document** menu when having the
document open in the editor, or look in the ``ToC.txt`` file in the root of the project folder. The
``ToC.txt`` file has a list of all documents in the project, referenced by their label, and where
they are saved.
The reason for this cryptic file naming is to avoid issues with file naming conventions and
restrictions on different operating systems, and also to have a file name that does not depend on
@@ -109,7 +109,7 @@ The Project Index
Between writing sessions, the project index is saved in a JSON file in ``meta/index.json``.
This file is not critical. If it is lost, it can be completely rebuilt from within novelWriter from
the :guilabel:`Tools` menu.
the **Tools** menu.
The index is maintained and updated whenever a document or note is saved in the editor. It contains
all references and tags in documents and notes, as well as the location of all headers in the
@@ -125,8 +125,8 @@ the index. If this too fails, you have likely encountered a bug.
Build Definitions
-----------------
The build definitions from the :guilabel:`Manuscript Build` tool are kept in the
``meta/builds.json`` file. If this file is lost, all custom build definitions are lost too.
The build definitions from the **Manuscript Build** tool are kept in the ``meta/builds.json`` file.
If this file is lost, all custom build definitions are lost too.
Cached GUI Options
@@ -144,17 +144,17 @@ Custom Word List
----------------
A file named ``meta/userdict.json`` contains all the custom words you've added to the project for
spell checking purposes. The content of the file can be edited from the :guilabel:`Tools` menu. If
you lose this file, all your custom spell check words will be lost too.
spell checking purposes. The content of the file can be edited from the **Tools** menu. If you lose
this file, all your custom spell check words will be lost too.
Session Stats
-------------
The writing progress is saved in the ``meta/sessions.jsonl`` file. This file records the length
and word counts of each writing session on the given project. The file is used by the
:guilabel:`Writing Statistics` tool. If this file is lost, the history it contains is also lost,
but it has otherwise no impact on the project.
and word counts of each writing session on the given project. The file is used by the **Writing
Statistics** tool. If this file is lost, the history it contains is also lost, but it has otherwise
no impact on the project.
Each session is recorded as a JSON object on a single line of the file. Each session record is
appended tot he file.
+64 -50
View File
@@ -21,14 +21,15 @@ GUI Layout and Design
The user interface of novelWriter is intended to be as minimalistic as practically possible, while
at the same time provide useful features needed for writing a novel.
The main window does not have an editor toolbar like many other applications do. This reduces
clutter, and since the documents are formatted with style tags, it is more or less redundant.
Still, a small formatting toolbar can be popped out by clicking the three dots in the header of the
document editor to give quick access to standard formatting codes.
The main window does not by default have an editor toolbar like many other applications do. This
reduces clutter, and since the documents are formatted with style tags, it is not needed most of
the time. Still, a small formatting toolbar can be popped out by clicking the left-most button in
the header of the document editor. It gives quick access to standard formatting codes.
Most formatting features supported are available through convenient keyboard shortcuts. They are
also available in the main menu, so you don't have to look up formatting codes every time you need
them. For reference, a list of all shortcuts can be found in the :ref:`a_kb` chapter.
also available in the main menu under **Format**, so you don't have to look up formatting codes
every time you need them. For reference, a list of all shortcuts can be found in the :ref:`a_kb`
chapter.
.. note::
novelWriter is not intended to be a full office type word processor. It doesn't support images,
@@ -37,13 +38,13 @@ them. For reference, a list of all shortcuts can be found in the :ref:`a_kb` cha
simple features.
On the left side of the main window, you will find a sidebar. This bar has buttons for the standard
views you can switch between, a quick link to the :guilabel:`Build Manuscript` tool, and a set of
views you can switch between, a quick link to the **Build Manuscript** tool, and a set of
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 in the editor. It is hidden by default,
but can be opened by pressing the three dots icon in the top right corner.
but can be opened by pressing the icon button in the top right corner.
Project Tree and Editor View
@@ -53,19 +54,19 @@ Project Tree and Editor View
A screenshot of the Project Tree and Editor View.
When in :guilabel:`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 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.
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
preview window, although you can use it for this purpose if you wish if you need to check that the
formatting tags behave as you expected. The main purpose of the viewer is for viewing your notes
next to your editor while you're writing.
preview window, although you can use it for this purpose if you wish. For instance if you need to
check that the formatting tags behave as you expect. However, the main purpose of the viewer is for
viewing your notes next to your editor while you're writing.
The editor also has a :guilabel:`Focus Mode` you can toggle either from the menu, from the icon in
the editor's header, or by pressing :kbd:`F8`. When :guilabel:`Focus Mode` is enabled, all the user
interface elements other than the document editor itself are hidden away.
The editor also has a **Focus Mode** you can toggle either from the menu, from the icon in the
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.
Novel View and Editor View
@@ -73,31 +74,32 @@ Novel View and Editor View
.. figure:: images/fig_novel_tree_view.png
A screenshot of the Novel Tree View.
A screenshot of the Novel Tree and Editor View.
When in :guilabel:`Novel Tree View` mode, the project tree is replaced by an overview of your novel
structure for a specific Novel :term:`root folder`. Instead of showing individual documents, the
tree now shows all headings of your novel text. This includes multiple headings within the same
document.
When the application is in **Novel Tree View** mode, the project tree is replaced by an overview of
your novel structure for a specific Novel :term:`root folder`. Instead of showing individual
documents, the tree now shows all headings of your novel text. This includes multiple headings
within the same document.
Each heading is indented according to the heading level. You can open and edit your novel documents
from this view as well. All headings contained in the currently open document should be highlighted
in the view to indicate which ones belong together in the same document.
Each heading is indented according to the heading level, not its parent/child relationship to other
elements of your project. You can open and edit your novel documents from this view as well. All
headings contained in the currently open document should be highlighted in the view to indicate
which ones belong together in the same document.
If you have multiple "Novel" type root folders, the header of the novel view becomes a dropdown
If you have multiple **Novel** type root folders, the header of the novel view becomes a dropdown
box. You can then switch between them by clicking the :guilabel:`Outline of ...` text. You can also
click the novel icon button next to it.
Generally, the novel view should update when you make changes to the novel structure, including
edits of the current document in the editor. The information is only updated when the automatic
save of the document is triggered, or you manually press :kbd:`Ctrl+S` to save changes. (You can
adjust the auto-save interval in :guilabel:`Preferences`.) You can also regenerate the whole novel
view by pressing the refresh button in the novel view header.
adjust the auto-save interval in **Preferences**.) You can also regenerate the whole novel view by
pressing the refresh button in the novel view header.
It is possible to show an optional third column in the novel view. The settings are available from
the menu button in the toolbar.
If you click the arrow icon to the right of each item, a tooltip will pop out showing you all the
If you click the triangular icon to the right of each item, a tooltip will pop out showing all the
meta data collected for that heading.
@@ -108,9 +110,9 @@ Novel Outline View
A screenshot of the Novel Outline View.
When in :guilabel:`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 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.
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.
@@ -122,18 +124,30 @@ 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 :guilabel:`Preferences`. Other colour themes are also available. More themes
can be contributed to novelWriter on GitHub.
neutral colours 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.
Switching the GUI colour theme does not affect the colours of the editor and viewer. They have
separate colour selectable from the "Document colour theme" setting in :guilabel:`Preferences`.
They are separated because there are a lot more options to choose from for the editor and viewer.
separate colour selectable from the "Document colour theme" setting in **Preferences**. They are
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.
Project Search
--------------
A global search tool is available from the side bar. It allows you to search through your entire
project. The tool does not provide a replace feature. There is a search and replace tool available
in the document editor that acts on the open document.
.. versionadded:: 2.4
.. _a_breakdown_project:
Project Layout
@@ -152,12 +166,12 @@ within those documents.
An illustration of how heading levels correspond to the novel structure.
The four heading levels (**H1** to **H4**) are treated as follows:
The four heading levels, **Level 1** to **Level 4**, are treated as follows:
* **H1** is used for the novel title, and for partitions.
* **H2** is used for chapter tiles.
* **H3** is used for scene titles -- optionally replaced by separators.
* **H4** is for section titles within scenes, if such granularity is needed.
* **Level 1** is used for the novel title, and for partitions.
* **Level 2** is used for chapter tiles.
* **Level 3** is used for scene titles -- optionally replaced by separators.
* **Level 4** is for section titles within scenes, if such granularity is needed.
The project tree will select an icon for the document based on the first heading in it.
@@ -178,25 +192,25 @@ Building a Manuscript
=====================
The project can at any time be assembled into a range of different formats through the
:guilabel:`Build Manuscript` tool. Natively, novelWriter supports `Open Document`_, HTML5, and
**Build Manuscript** tool. Natively, novelWriter supports `Open Document`_, HTML5, and
various flavours of Markdown.
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 supported by most office type applications. In addition, printing is also possible. Print to PDF
is available from the print dialog.
In addition, 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.
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.
See :ref:`a_manuscript` for more details.
.. versionadded:: 2.1
You can now define multiple build definitions in the :guilabel:`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.
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.
.. _a_breakdown_storage:
+56 -42
View File
@@ -10,7 +10,7 @@ values and allowing for some text formatting. The syntax is based on Markdown, b
(bold) and strike through text, as well as four levels of headings. For some further complex
formatting needs, a set of shortcodes can be used.
In addition to formatting codes, novelWriter allows for comments, a synopsis tag, and a set of
In addition to formatting codes, novelWriter allows for comments, a synopsis tag, and a number of
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.
@@ -35,7 +35,7 @@ have a distinct colour, and the references themselves will get a colour if they
references will get a squiggly error line underneath. The same applies to duplicate tags.
There are a number of syntax highlighter colour themes available, both for light and dark GUIs. You
can select them from :guilabel:`Preferences`.
can select them from **Preferences**.
.. _a_fmt_head:
@@ -54,6 +54,9 @@ correctly to produce the intended result. See :ref:`a_struct_heads` for more det
``# Title Text``
Heading level one. For novel documents, the level indicates the start of a new partition.
Partitions are for when you want to split your story into "Part 1", "Part 2", etc. You can also
choose to use them for splitting the text up into acts, and then hide these headings in your
manuscript.
``## Title Text``
Heading level two. For novel documents, the level indicates the start of a new chapter. Chapter
@@ -62,16 +65,17 @@ correctly to produce the intended result. See :ref:`a_struct_heads` for more det
``### Title Text``
Heading level three. For novel documents, the level indicates the start of a new scene. Scene
numbers or scene separators can be inserted automatically when building the manuscript, so you
can use the title field as a working title for your scenes if you wish.
can use the title field as a working title for your scenes if you wish, but you must provide a
minimal title.
``#### Title Text``
Heading level four. For novel documents, the level indicates the start of a new section. Section
titles can be replaced by separators or ignored completely when building the manuscript.
For headings level one through three, adding a ``!`` modifies its meaning:
For headings level one through three, adding a ``!`` modifies the meaning of the heading:
``#! Title Text``
This tells the build tool that the level one heading is intended to be used for the novel's or
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.
@@ -82,9 +86,10 @@ For headings level one through three, adding a ``!`` modifies its meaning:
:ref:`a_struct_heads_unnum` for more details.
``###! Title Text``
This is an alternative scene heading that can be formatted differently in the
:guilabel:`Manuscript Build` tool. It is intended for separating "soft" and "hard" scene breaks.
Otherwise, it behaves identically to a regular scene heading.
This is an alternative scene heading that can be formatted differently in the **Manuscript
Build** tool. It is intended for separating "soft" and "hard" scene breaks. Aside from this, it
behaves identically to a regular scene heading. See :ref:`a_struct_heads_scenes` for more
details.
.. note::
The space after the ``#`` or ``!`` character is mandatory. The syntax highlighter will change
@@ -106,8 +111,8 @@ In addition, the editor supports a few additional types of white spaces:
* Thin spaces are also supported, and can be inserted with :kbd:`Ctrl+K`, :kbd:`Shift+Space`.
* Non-breaking thin space can be inserted with :kbd:`Ctrl+K`, :kbd:`Ctrl+Space`.
These are all insert features, and the :guilabel:`Insert` menu has more. The keyboard shortcuts for
them are also listed in :ref:`a_kb_ins`.
These are all insert features, and the **Insert** menu has more. The keyboard shortcuts for them
are also listed in :ref:`a_kb_ins`.
Non-breaking spaces are highlighted by the syntax highlighter with an alternate coloured
background, depending on the selected theme.
@@ -129,12 +134,12 @@ A minimal set of Markdown text emphasis styles are supported for text paragraphs
The text is rendered as emphasised text (italicised).
``**text**``
The text is rendered as strongly important text (bold).
The text is rendered as strongly emphasised text (bold).
``~~text~~``
Strike through text.
In Markdown guides it is often recommended to differentiate between strong importance and emphasis
In Markdown guides it is often recommended to differentiate between strong emphasis and emphasis
by using ``**`` for strong and ``_`` for emphasis, although Markdown generally also supports ``__``
for strong and ``*`` for emphasis. However, since the differentiation makes the highlighting and
conversion significantly simpler and faster, in novelWriter this is a rule, not just a
@@ -182,14 +187,15 @@ solved with simple Markdown-like formatting codes. Available shortcodes are list
"``[i]text[/i]``", "Text is rendered as italicised text."
"``[s]text[/s]``", "Text is rendered as strike through text."
"``[u]text[/u]``", "Text is rendered as underlined text."
"``[m]text[/m]``", "Text is rendered as highlighted text."
"``[sup]text[/sup]``", "Text is rendered as superscript text."
"``[sub]text[/sub]``", "Text is rendered as subscript text."
Unlike Markdown style codes, these can be used anywhere within a paragraph. Even in the middle of a
word if you need to. You can also freely combine them to form more complex formatting.
The shortcodes are available from the :guilabel:`Format` menu and in the editor toolbar, which can
be activated by clicking the three dots in the editor header.
The shortcodes are available from the **Format** menu and in the editor toolbar, which can be
activated by clicking the left-most icon button in the editor header.
.. versionadded:: 2.2
@@ -199,30 +205,39 @@ be activated by clicking the three dots in the editor header.
Comments and Synopsis
=====================
In addition to these standard Markdown features, novelWriter also allows for comments in documents.
The text of a comment is ignored by the word counter. The text can also be filtered out when
building the manuscript or viewing the document.
In addition to the above formatting features, novelWriter also allows for comments in documents.
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.
If the first word of a comment is ``Synopsis:`` (with the colon included), 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.
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
``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.
``% text ...``
The different styles of comments are as follows:
``% Comment text ...``
This is a comment. The text is not rendered by default (this can be overridden), seen in the
document viewer, or counted towards word counts.
document viewer, or counted towards word counts. It is intended for you to make notes in your
text for your own sake, whatever that may be, that isn't part of the story text. This is the
general format of a comment.
``%Synopsis: text ...``
``%Synopsis: Comment text ...``
This is a synopsis comment. It is generally treated in the same way as a regular comment, except
that it is also captured by the indexing algorithm and displayed in the :ref:`a_ui_outline`. It
can also be filtered separately when building the project to for instance generate an outline
document of the whole project.
``%Short: text ...``
``%Short: Comment text ...``
This is a short description comment. It is identical to the synopsis comment (they are
interchangeable), but is intended to be used for project notes. The text shows up in the
Reference panel below the document viewer in the last column labelled
:guilabel:`Short Description`.
Reference panel below the document viewer in the last column labelled **Short Description**.
``%~ Comment text ...``
This can be used to exclude story text from your manuscript without having to delete it from
your text. Comments with the ``~`` will *never* be included in the manuscript, even if you have
chosen to include comments in it. That is the main difference between these two formats.
.. note::
Only one comment can be flagged as a synopsis or short comment for each heading. If multiple
@@ -245,14 +260,14 @@ heading. Setting it multiple times under the same heading will just override the
A tag keyword followed by the tag value, like for instance the name of a character.
References can be set anywhere within a section, and are collected according to their category.
References are in the form:
References are on the form:
``@keyword: value``
``@keyword: value1, value2, ..., valueN``
A reference keyword followed by a value, or a comma separated list of values.
Tags and references are covered in detail in the :ref:`a_references` chapter. The keywords can be
inserted at the cursor position in the editor via the :guilabel:`Insert` menu. If you start typing
an ``@`` on a new line, and auto-complete menu will also pop up suggesting keywords.
inserted at the cursor position in the editor via the **Insert** menu. If you start typing an ``@``
on a new line, and auto-complete menu will also pop up suggesting keywords.
.. _a_fmt_align:
@@ -260,8 +275,8 @@ an ``@`` on a new line, and auto-complete menu will also pop up suggesting keywo
Paragraph Alignment and Indentation
===================================
All documents have the text by default aligned to the left or justified, depending on your
settings in :guilabel:`Preferences`.
All documents have the text by default aligned to the left or justified, depending on your setting
in **Preferences**.
You can override the default text alignment on individual paragraphs by specifying alignment tags.
These tags are double angle brackets. Either ``>>`` or ``<<``. You put them either before or after
@@ -296,6 +311,10 @@ Examples:
Vertical Space and Page Breaks
==============================
You can apply page breaks to partition, chapter and scene headings for novel documents from the
**Manuscript Build** tool. If you need to add a page break or additional vertical spacing in other
places, there are special codes available for this purpose.
Adding more than one line break between paragraphs will **not** increase the space between those
paragraphs when building the project. To add additional space between paragraphs, add the text
``[vspace]`` on a line of its own, and the build tool will insert a blank paragraph in its place.
@@ -303,13 +322,8 @@ paragraphs when building the project. To add additional space between paragraphs
If you need multiple blank paragraphs just add a colon and a number to the above code. For
instance, writing ``[vspace:3]`` will insert three blank paragraphs.
Normally, the manuscript build tool will insert a page break before all headings of level one and
for all headings of level two for novel documents, i.e. chapters, but not for project notes.
If you need to add a page break somewhere else, put the text ``[new page]`` on a line by itself
before the text you wish to start on a new page.
If you want page breaks for scenes and sections, you must add them manually.
If you need to add a page break somewhere, put the text ``[new page]`` on a line by itself before
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
@@ -325,8 +339,8 @@ If you want page breaks for scenes and sections, you must add them manually.
[vspace:2]
This is another text paragraph, but there will be two empty paragraphs
in-between them.
between them.
[new page]
This text will always start on a new page if the build format has pages.
This text will start on a new page if the build format has pages.
+47 -47
View File
@@ -8,7 +8,7 @@ This chapter covers in more detail the different project views available in nove
.. figure:: images/fig_project_tree_detailed.png
The Project Tree as it appears when loading a sample project.
The **Project Content** tree as it appears when loading a sample project.
.. _a_ui_tree:
@@ -21,33 +21,32 @@ the project, and has four columns.
**Column 1**
The first column shows the icon and label of each folder, document, or note in your project. The
label is not the same as the title you set inside the document. However, the document's label
will appear in the header above the document text itself so you know where in the project an
open document belongs. The icon is selected based on the type of item, and for novel documents,
the level of the first header in the document text.
label is not the same as the heading title you set inside the document. However, the document's
label will appear in the header above the document text itself so you know where in the project
an open document belongs. The icon is selected based on the type of item, and for novel
documents, the level of the first heading in the document text.
**Column 2**
The second column shows the word count of the document, or the sum of words of the child items
for folders and documents with sub-documents. If the counts seem incorrect, they can be updated
by rebuilding the :term:`project index` from the :guilabel:`Tools` menu, or by pressing
:kbd:`F9`.
by rebuilding the :term:`project index` from the **Tools** menu, or by pressing :kbd:`F9`.
**Column 3**
The third column indicates whether the document is considered active or inactive in the project.
You can use this flag to indicate that a document is still in the project, but should not be
considered an active part of it. When you run the :guilabel:`Build Manuscript` tool, you can
include or exclude documents based on this flag. You can change this value from the
considered an active part of it. When you run the **Build Manuscript** tool, you can include or
exclude documents based on this flag. You can change this value from the right-click
:term:`context menu`.
**Column 4**
The fourth column shows the user-defined status or importance labels you've assigned to each
project item. See :ref:`a_ui_tree_status` for more details on how to uses these labels. You can
change these labels from the :term:`context menu`.
select these labels from the :term:`context menu`, and define them in **Project Settings**.
Right-clicking an item in the project tree will open a context menu under the cursor, displaying
a selection of actions that can be performed on the selected item.
At the top of the tree, you will find a set of buttons.
At the top of the project tree, you will find a set of buttons.
* The first button is a quick links button that will show you a dropdown menu of all the
:term:`root folders<root folder>` in your project. Selecting one will move to that position in
@@ -73,10 +72,10 @@ addition to the word count.
Splitting and Merging Documents
-------------------------------
Under the :guilabel:`Transform` submenu in the context menu of an item in the project tree, you
will find several options on how to change a document or folder. This includes changing between
document and note, but also splitting them into multiple documents, or merging child items into a
single document.
Under the **Transform** submenu in the context menu of an item in the project tree, you will find
several options on how to change a document or folder. This includes changing between document and
note, but also splitting them into multiple documents, or merging child items into a single
document.
Splitting Documents
@@ -84,12 +83,12 @@ Splitting Documents
.. figure:: images/fig_project_split_tool.png
The :guilabel:`Split Document` dialog.
The **Split Document** dialog.
The :guilabel:`Split Document by Heading` option will open a dialog that allows you to split the
selected document into multiple new documents based on the headings it contains. You can select at
which heading level the split is to be performed from the dropdown box. The list box will preview
which headings will be split into new documents.
The **Split Document by Headings** option will open a dialog that allows you to split the selected
document into multiple new documents based on the headings it contains. You can select at which
heading level the split is to be performed from the dropdown box. The list box will preview which
headings will be split into new documents.
You are given the option to create a folder for these new documents, and whether or not to create a
hierarchy of documents. That is, put sections under scenes, and scenes under chapters.
@@ -103,18 +102,18 @@ Merging Documents
.. figure:: images/fig_project_merge_tool.png
The :guilabel:`Merge Documents` dialog.
The **Merge Documents** dialog.
You have two options for merging documents that are child elements of another document. You can
either :guilabel:`Merge Child Items into Self` and :guilabel:`Merge Child Items into New`. The
first option will pull all content of child items and merge them into the parent document, while
the second option will create a new document in the process.
either **Merge Child Items into Self** and **Merge Child Items into New**. The first option will
pull all content of child items and merge them into the parent document, while the second option
will create a new document in the process.
When merging documents in a folder, you only have the latter process is possible, so only the
choice :guilabel:`Merge Documents in Folder` is available.
choice **Merge Documents in Folder** is available.
In either case, the :guilabel:`Merge Documents` dialog will let you exclude documents you don't
want to include, and it also lets you reorder them if you wish.
In either case, the **Merge Documents** dialog will let you exclude documents you don't want to
include, and it also lets you reorder them if you wish.
.. _a_ui_tree_status:
@@ -124,14 +123,14 @@ Document Importance and Status
Each document or folder in your project can have either a "Status" or "Importance" flag set. These
are flags that you control and define yourself, and novelWriter doesn't use them for anything. To
modify the labels, go to their respective tabs in :guilabel:`Project Settings`.
modify the labels, go to their respective tabs in **Project Settings**.
The "Status" flag is intended to tag a :term:`novel document<novel documents>` as for instance a
draft or as completed, and the "Importance" flag is intended to tag character notes, or other
:term:`project notes`, as for instance a main, major, or minor character or story element.
Whether a document uses a "Status" or "Importance" flag depends on which :term:`root folder` it
lives in. If it's in a Novel type folder, it uses the "Status" flag, otherwise it uses an
lives in. If it's in a **Novel** type folder, it uses the "Status" flag, otherwise it uses an
"Importance" flag.
@@ -142,7 +141,7 @@ 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 :guilabel:`Manuscript Build` tool.
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
@@ -150,14 +149,15 @@ your manuscript in the :guilabel:`Manuscript Build` tool.
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 is due to the way drag and drop is implemented in the user
interface framework novelWriter is built upon.
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 :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.
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
: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.
Root folders in the project tree cannot be dragged and dropped at all. If you want to reorder them,
you can move them up or down with respect to each other from the arrow buttons at the top of the
@@ -175,8 +175,8 @@ The Novel Tree View
An alternative way to view the project structure is the novel view. You can switch to this view by
selecting the :guilabel:`Novel View` button in the sidebar. This view is a simplified version of
the view in the :guilabel:`Outline View`. It is convenient when you want to browse the structure
of the story itself rather than the document files.
the view in the **Outline View**. It is convenient when you want to browse the structure of the
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
@@ -194,14 +194,14 @@ The Novel Outline View
A screenshot of the Novel Outline View.
The project's :guilabel:`Novel Outline View` is available as another view option from the sidebar.
The outline provides an overview of the novel structure, displaying a tree hierarchy of the
elements of the novel, that is, the level 1 to 4 headings representing partitions, chapters, scenes
and sections.
The project's **Novel Outline View** is available as another view option from the sidebar. The
outline provides an overview of the novel structure, displaying a tree hierarchy of the elements of
the novel, that is, the level 1 to 4 headings representing partitions, chapters, scenes and
sections.
The document containing the heading can also be displayed as a separate column, as well as the line
number where the heading is defined. Double-clicking an entry will open the corresponding document
in the editor and switch to :guilabel:`Project Tree View` mode.
in the editor and switch to **Project Tree View** mode.
You can select which novel folder to display from the dropdown menu. You can optionally also choose
to show a combination of all novel folders.
@@ -217,7 +217,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 :guilabel:`Title` column cannot be disabled or moved.
The **Title** column cannot be disabled or moved.
The information viewed in the outline is based on the :term:`project index`. While novelWriter does
its best to keep the index up to date when contents change, you can always rebuild it manually by
@@ -226,5 +226,5 @@ pressing :kbd:`F9` if something isn't right.
The outline view itself can be regenerated by pressing the refresh button. By default, the content
is refreshed each time you switch to this view.
The :guilabel:`Synopsis` column of the outline view takes its information from a specially
formatted comment. See :ref:`a_fmt_comm`.
The **Synopsis** column of the outline view takes its information from a specially formatted
comment. See :ref:`a_fmt_comm`.
+18 -17
View File
@@ -20,22 +20,22 @@ Main Window Shortcuts
:header: "Shortcut", "Description"
":kbd:`F1`", "Open the online user manual"
":kbd:`F5`", "Open the :guilabel:`Build Manuscript` tool"
":kbd:`F6`", "Open the :guilabel:`Writing Statistics` tool"
":kbd:`F8`", "Toggle :guilabel:`Focus Mode`"
":kbd:`F5`", "Open the **Build Manuscript** tool"
":kbd:`F6`", "Open the **Writing Statistics** tool"
":kbd:`F8`", "Toggle **Focus Mode**"
":kbd:`F9`", "Re-build the project's index"
":kbd:`F11`", "Toggle full screen mode"
":kbd:`Ctrl+,`", "Open the :guilabel:`Preferences` dialog"
":kbd:`Ctrl+,`", "Open the **Preferences** dialog"
":kbd:`Ctrl+E`", "Switch focus to the document editor"
":kbd:`Ctrl+T`", "Switch or toggle focus for the project tree or novel view"
":kbd:`Ctrl+Q`", "Exit novelWriter"
":kbd:`Ctrl+Shift+,`", "Open the :guilabel:`Project Settings` dialog"
":kbd:`Ctrl+Shift+,`", "Open the **Project Settings** dialog"
":kbd:`Ctrl+Shift+O`", "Open the Welcome dialog to open or create a project"
":kbd:`Ctrl+Shift+S`", "Save the current project"
":kbd:`Ctrl+Shift+T`", "Switch focus to the outline view"
":kbd:`Ctrl+Shift+W`", "Close the current project"
":kbd:`Shift+F1`", "Open the local user manual (PDF) if it is available"
":kbd:`Shift+F6`", "Open the :guilabel:`Project Details` dialog"
":kbd:`Shift+F6`", "Open the **Project Details** dialog"
.. _a_kb_tree:
@@ -53,8 +53,8 @@ Project Tree Shortcuts
":kbd:`Alt+Left`", "Jump to the parent item in the tree"
":kbd:`Alt+Right`", "Jump to the first child item in the project tree"
":kbd:`Ctrl+.`", "Open the context menu on the selected item"
":kbd:`Ctrl+L`", "Open the :guilabel:`Quick Links` menu"
":kbd:`Ctrl+N`", "Open the :guilabel:`Create New Item` menu"
":kbd:`Ctrl+L`", "Open the **Quick Links** menu"
":kbd:`Ctrl+N`", "Open the **Create New Item** menu"
":kbd:`Ctrl+O`", "Open the selected document in the editor"
":kbd:`Ctrl+R`", "Open the selected document in the viewer"
":kbd:`Ctrl+Up`", "Move selected item one step up in the tree"
@@ -75,11 +75,12 @@ Text Search Shortcuts
:header: "Shortcut", "Description"
":kbd:`F3`", "Find the next occurrence of the search word"
":kbd:`Ctrl+F`", "Open the search bar and search for the selected word, if any is selected"
":kbd:`Ctrl+F`", "Open search and look for the selected word"
":kbd:`Ctrl+G`", "Find the next occurrence of the search word"
":kbd:`Ctrl+H`", "Open the search tool and populate with the selected word (Mac :kbd:`Cmd+=`)"
":kbd:`Ctrl+Shift+1`", "Replace selected occurrence of the search word, and move to the next"
":kbd:`Ctrl+H`", "Open replace and look for the selected word (Mac :kbd:`Cmd+=`)"
":kbd:`Ctrl+Shift+1`", "Replace selected occurrence, and move to the next"
":kbd:`Ctrl+Shift+G`", "Find the previous occurrence of the search word"
":kbd:`Ctrl+Shift+F`", "Open project search and look for the selected word"
":kbd:`Shift+F3`", "Find the previous occurrence of the search word"
@@ -91,8 +92,8 @@ Text Formatting Shortcuts
":kbd:`Ctrl+'`", "Wrap selected text, or word under cursor, in single quotes"
":kbd:`Ctrl+""`", "Wrap selected text, or word under cursor, in double quotes"
":kbd:`Ctrl+/`", "Toggle block format as comment for block under cursor, or selected text"
":kbd:`Ctrl+0`", "Remove block formatting for block under cursor, or selected text"
":kbd:`Ctrl+/`", "Toggle comment format for block or selected text"
":kbd:`Ctrl+0`", "Remove format for block or selected text"
":kbd:`Ctrl+1`", "Change block format to heading level 1"
":kbd:`Ctrl+2`", "Change block format to heading level 2"
":kbd:`Ctrl+3`", "Change block format to heading level 3"
@@ -102,11 +103,11 @@ Text Formatting Shortcuts
":kbd:`Ctrl+7`", "Change block alignment to right-aligned"
":kbd:`Ctrl+8`", "Add a left margin to the block"
":kbd:`Ctrl+9`", "Add a right margin to the block"
":kbd:`Ctrl+B`", "Format selected text, or word under cursor, with strong emphasis (bold)"
":kbd:`Ctrl+B`", "Format selected text, or word under cursor, with bold"
":kbd:`Ctrl+D`", "Format selected text, or word under cursor, with strike through"
":kbd:`Ctrl+I`", "Format selected text, or word under cursor, with emphasis (italic)"
":kbd:`Ctrl+Shift+/`", "Remove block formatting for block under cursor, or selected text"
":kbd:`Ctrl+Shift+D`", "Toggle block format as ignored text for block under cursor, or selected text"
":kbd:`Ctrl+I`", "Format selected text, or word under cursor, with italic"
":kbd:`Ctrl+Shift+/`", "Remove format for block or selected text"
":kbd:`Ctrl+Shift+D`", "Toggle ignored text format for block or selected text"
Other Editor Shortcuts
+6 -6
View File
@@ -11,7 +11,7 @@ Typographical Notes
novelWriter has some support for typographical symbols that are not usually easily available in
many text editors. This includes for instance the proper unicode quotation marks, dashes, ellipsis,
thin spaces, etc. All these symbols are available from the :guilabel:`Insert` menu, and via
thin spaces, etc. All these symbols are available from the **Insert** menu, and via
keyboard shortcuts. See :ref:`a_kb_ins`.
This chapter provides some additional information on how novelWriter handles these symbols.
@@ -43,22 +43,22 @@ Single and Double Quotes
All the different quotation marks listed on the `Quotation Mark`_ Wikipedia page are available, and
can be selected as auto-replaced symbols for straight single and double quote key strokes. The
settings can be found in :guilabel:`Preferences`.
settings can be found in **Preferences**.
Ordinarily, text wrapped in quotes are highlighted by the editor. This is meant as a convenience
for highlighting dialogue between characters. This feature can be disabled in
:guilabel:`Preferences` if this feature isn't wanted.
**Preferences** if this feature isn't wanted.
The editor distinguishes between text wrapped in regular straight double quotes and the
user-selected double quote symbols. This is to help the writer recognise which parts of the text
are not using the chosen quote symbols. Two convenience functions in the :guilabel:`Format` menu
are not using the chosen quote symbols. Two convenience functions in the **Format** menu
can be used to re-format a selected section of text with the correct quote symbols.
Single and Double Prime
------------------------
Both single and double prime symbols are available in the :guilabel:`Insert` menu. These symbols
Both single and double prime symbols are available in the **Insert** menu. These symbols
are the correct symbols to use for unit symbols for feet, inches, minutes, and seconds. The usage
of these is described in more detail on the Wikipedia Prime_ page. They look very similar to single
and double straight quotes, and may be rendered similarly by the font, but they have different
@@ -79,7 +79,7 @@ right single quotation marks, depending on the font. There is a Wikipedia articl
`Modifier letter apostrophe`_ with more details.
.. note::
On export with the :guilabel:`Build Manuscript` tool, these apostrophes will be replaced
On export with the **Build Manuscript** tool, these apostrophes will be replaced
automatically with the corresponding right hand single quote symbol as is generally recommended.
Therefore it doesn't really matter if you only use them to correct syntax highlighting.
+23 -22
View File
@@ -23,13 +23,14 @@ having it selected. This will open the document in the document editor. The edit
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 (toggles the :guilabel:`Focus Mode`) and a close button in the
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
few buttons for applying text formatting, and a search button to open the search dialog.
few buttons for applying text formatting, a drop down menu for navigating between headings, and a
search button to open the search dialog.
Both the document editor and viewer will show the label of the currently open document in the
header at the top of the edit or view panel. Optionally, the full project path to the document can
be shown. This can be set in :guilabel:`Preferences`.
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
@@ -42,10 +43,10 @@ the label and pressing :kbd:`Ctrl+Return`. You can also control-click them with
Editor Auto-Completer
---------------------
If you type the character ``@`` on a new line, a menu will appear showing the different available
keywords. The list will shorten as you type. Once a keyword command has been selected or typed, the
editor may suggest further content based on your project content. See :ref:`a_references_completer`
for more details.
If you type the character ``@`` on a new line, a pop-up menu will appear showing the different
available keywords. The list will shorten as you type. Once a keyword command has been selected or
typed, the editor may suggest further options based on your project content. See
:ref:`a_references_completer` for more details.
.. versionadded:: 2.2
@@ -60,9 +61,9 @@ 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 :guilabel:`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`, 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.
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
@@ -75,19 +76,20 @@ content of the viewer with the content of the document the reference points to.
The document viewer keeps a history of viewed documents, which you can navigate with the arrow
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.
browser. The left-most button is a dropdown menu for quickly navigation between headings in the
document.
At the bottom of the view panel there is a :guilabel:`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 to all documents referring back to the one you're currently viewing, if any has been
defined. If you have created root folders and tags for various story elements like characters and
plot points, these will appear as additional tabs in this panel.
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
to all documents referring back to the one you're currently viewing, if any has been defined. If
you have created root folders and tags for various story elements like characters and plot points,
these will appear as additional tabs in this panel.
.. note::
The :guilabel:`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 :guilabel:`Rebuild Index` from the
:guilabel:`Tools` menu, or by pressing :kbd:`F9`.
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.
@@ -131,8 +133,7 @@ Auto-Replace as You Type
========================
A few auto-replace features are supported by the editor. You can control every aspect of the
auto-replace feature from :guilabel:`Preferences`. You can also disable this feature entirely if
you wish.
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
+54 -54
View File
@@ -50,7 +50,7 @@
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="113" />
<source>Hard Scene Format</source>
<source>Alt. Scene Format</source>
<translation type="unfinished" />
</message>
<message>
@@ -791,22 +791,22 @@
<context>
<name>GuiDocEditFooter</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3005" />
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
<source>Line: {0} ({1})</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3006" />
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
<source>Words: {0} ({1})</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
<source>Words: {0} selected</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3019" />
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
<source>Status</source>
<translation type="unfinished" />
</message>
@@ -814,27 +814,27 @@
<context>
<name>GuiDocEditHeader</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2803" />
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
<source>Toggle Tool Bar</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2808" />
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
<source>Outline</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2813" />
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
<source>Search</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2818" />
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
<source>Toggle Focus Mode</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2823" />
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
<source>Close</source>
<translation type="unfinished" />
</message>
@@ -842,62 +842,62 @@
<context>
<name>GuiDocEditSearch</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2411" />
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
<source>Search for</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2416" />
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
<source>Replace with</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2424" />
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
<source>Search</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2432" />
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
<source>Case Sensitive</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2438" />
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
<source>Whole Words Only</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2444" />
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
<source>RegEx Mode</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2450" />
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
<source>Loop Search</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2456" />
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
<source>Search Next File</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2464" />
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
<source>Preserve Case</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2472" />
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
<source>Close Search</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2483" />
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
<source>Find in current document</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2487" />
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
<source>Find and replace in current document</source>
<translation type="unfinished" />
</message>
@@ -920,107 +920,107 @@
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="517" />
<location filename="../novelwriter/gui/doceditor.py" line="518" />
<source>Saved Document: {0}</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="686" />
<location filename="../novelwriter/gui/doceditor.py" line="687" />
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="712" />
<location filename="../novelwriter/gui/doceditor.py" line="713" />
<source>Spell check complete</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="832" />
<location filename="../novelwriter/gui/doceditor.py" line="833" />
<source>Document Details</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="834" />
<location filename="../novelwriter/gui/doceditor.py" line="835" />
<source>Created: {0}</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="835" />
<location filename="../novelwriter/gui/doceditor.py" line="836" />
<source>Updated: {0}</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="837" />
<location filename="../novelwriter/gui/doceditor.py" line="838" />
<source>File Location: {0}</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1111" />
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
<source>Set as Document Name</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1117" />
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
<source>Follow Tag</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1121" />
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
<source>Create Note for Tag</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1127" />
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
<source>Cut</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
<source>Copy</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1132" />
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
<source>Paste</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1137" />
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
<source>Select All</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
<source>Select Word</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1143" />
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
<source>Select Paragraph</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1159" />
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
<source>Spelling Suggestion(s)</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1166" />
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
<source>No Suggestions</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1169" />
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
<source>Add Word to Dictionary</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1594" />
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
<source>Please select some text before calling replace quotes.</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1901" />
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
<source>Do you want to create a new project note for the tag '{0}'?</source>
<translation type="unfinished" />
</message>
@@ -1104,52 +1104,52 @@
<context>
<name>GuiDocToolBar</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2268" />
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
<source>Markdown Bold</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2274" />
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
<source>Markdown Italic</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2280" />
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
<source>Markdown Strikethrough</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2286" />
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
<source>Shortcode Bold</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2292" />
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
<source>Shortcode Italic</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2298" />
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
<source>Shortcode Strikethrough</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2304" />
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
<source>Shortcode Underline</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2310" />
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
<source>Shortcode Highlight</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2316" />
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
<source>Shortcode Superscript</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2322" />
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
<source>Shortcode Subscript</source>
<translation type="unfinished" />
</message>
@@ -1898,7 +1898,7 @@
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="740" />
<source>Hard Scene</source>
<source>Alternative Scene</source>
<translation type="unfinished" />
</message>
<message>
+984 -984
View File
File diff suppressed because it is too large Load Diff
+109 -109
View File
@@ -31,32 +31,32 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="109" />
<source>Partition Format</source>
<translation type="unfinished" />
<translation>Formato para Particiones</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="110" />
<source>Chapter Format</source>
<translation type="unfinished" />
<translation>Formato para Capítulos</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="111" />
<source>Unnumbered Format</source>
<translation type="unfinished" />
<translation>Formato Sin Numeración</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="112" />
<source>Scene Format</source>
<translation type="unfinished" />
<translation>Formato para Escenas</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="113" />
<source>Hard Scene Format</source>
<translation type="unfinished" />
<source>Alt. Scene Format</source>
<translation>Formato Alternativo para Escenas</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="114" />
<source>Section Format</source>
<translation type="unfinished" />
<translation>Formato para Secciones</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="116" />
@@ -86,7 +86,7 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="121" />
<source>Ignore These Keywords</source>
<translation type="unfinished" />
<translation>Ignorar estas palabras clave</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="122" />
@@ -206,17 +206,17 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="147" />
<source>First Line Indent</source>
<translation type="unfinished" />
<translation>Sangría en Línea Inicial</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="149" />
<source>Markdown (.md)</source>
<translation type="unfinished" />
<translation>Markdown (.md)</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="150" />
<source>Preserve Hard Line Breaks</source>
<translation type="unfinished" />
<translation>Conservar Saltos de Línea Forzados</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="152" />
@@ -231,7 +231,7 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="154" />
<source>Preserve Tab Characters</source>
<translation type="unfinished" />
<translation>Preservar Caracteres de Tabulación</translation>
</message>
</context>
<context>
@@ -791,22 +791,22 @@
<context>
<name>GuiDocEditFooter</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3005" />
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
<source>Line: {0} ({1})</source>
<translation>Línea: {0} ({1})</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3006" />
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
<source>Words: {0} ({1})</source>
<translation>Palabras: {0} ({1})</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
<source>Words: {0} selected</source>
<translation>Palabras: {0} seleccionadas</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3019" />
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
<source>Status</source>
<translation>Estado</translation>
</message>
@@ -814,27 +814,27 @@
<context>
<name>GuiDocEditHeader</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2803" />
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
<source>Toggle Tool Bar</source>
<translation>Alternar Barra de Herramientas</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2808" />
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
<source>Outline</source>
<translation type="unfinished" />
<translation>Estructura</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2813" />
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
<source>Search</source>
<translation>Buscar</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2818" />
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
<source>Toggle Focus Mode</source>
<translation>Alternar el Modo Enfocado</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2823" />
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
<source>Close</source>
<translation>Cerrar</translation>
</message>
@@ -842,62 +842,62 @@
<context>
<name>GuiDocEditSearch</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2411" />
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
<source>Search for</source>
<translation type="unfinished" />
<translation>Buscar</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2416" />
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
<source>Replace with</source>
<translation type="unfinished" />
<translation>Reemplazar con</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2424" />
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
<source>Search</source>
<translation>Buscar</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2432" />
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
<source>Case Sensitive</source>
<translation>Sensibilidad a Mayúsculas y Minúsculas</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2438" />
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
<source>Whole Words Only</source>
<translation>Sólo Palabras Enteras</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2444" />
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
<source>RegEx Mode</source>
<translation>Modo ExReg</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2450" />
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
<source>Loop Search</source>
<translation>Reiniciar la Búsqueda</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2456" />
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
<source>Search Next File</source>
<translation>Buscar en el Siguiente Archivo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2464" />
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
<source>Preserve Case</source>
<translation>Conservar Mayúsculas y Minúsculas</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2472" />
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
<source>Close Search</source>
<translation>Cerrar la Búsqueda</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2483" />
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
<source>Find in current document</source>
<translation>Buscar en el documento actual</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2487" />
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
<source>Find and replace in current document</source>
<translation>Buscar y reemplazar en el documento actual</translation>
</message>
@@ -920,107 +920,107 @@
<translation>No se puedo guardar el documento.</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="517" />
<location filename="../novelwriter/gui/doceditor.py" line="518" />
<source>Saved Document: {0}</source>
<translation>Documento Guardado: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="686" />
<location filename="../novelwriter/gui/doceditor.py" line="687" />
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
<translation>Para la corrección ortográfica se requiere del paquete PyEnchant. Parece que no se encuentra instalado.</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="712" />
<location filename="../novelwriter/gui/doceditor.py" line="713" />
<source>Spell check complete</source>
<translation>Se completó la comprobación ortográfica</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="832" />
<location filename="../novelwriter/gui/doceditor.py" line="833" />
<source>Document Details</source>
<translation>Detalles del Documento</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="834" />
<location filename="../novelwriter/gui/doceditor.py" line="835" />
<source>Created: {0}</source>
<translation>Creación: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="835" />
<location filename="../novelwriter/gui/doceditor.py" line="836" />
<source>Updated: {0}</source>
<translation>Actualizado en: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="837" />
<location filename="../novelwriter/gui/doceditor.py" line="838" />
<source>File Location: {0}</source>
<translation>Ubicación del Archivo: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1111" />
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
<source>Set as Document Name</source>
<translation>Elegir como Nombre del Documento</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1117" />
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
<source>Follow Tag</source>
<translation>Continuar a Etiqueta</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1121" />
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
<source>Create Note for Tag</source>
<translation>Crear Nota para la Etiqueta</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1127" />
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
<source>Cut</source>
<translation>Cortar</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
<source>Copy</source>
<translation>Copiar</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1132" />
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
<source>Paste</source>
<translation>Pegar</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1137" />
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
<source>Select All</source>
<translation>Seleccionar Todo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
<source>Select Word</source>
<translation>Seleccionar Palabra</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1143" />
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
<source>Select Paragraph</source>
<translation>Seleccionar Párrafo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1159" />
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
<source>Spelling Suggestion(s)</source>
<translation>Sugerencia(s) de Ortografía</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1166" />
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
<source>No Suggestions</source>
<translation>No Hay Sugerencias</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1169" />
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
<source>Add Word to Dictionary</source>
<translation>Añadir Palabra al Diccionario</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1594" />
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
<source>Please select some text before calling replace quotes.</source>
<translation>Por favor seleccione algo del texto antes de intentar reemplazar las comillas.</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1901" />
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
<source>Do you want to create a new project note for the tag '{0}'?</source>
<translation>¿Desea crear una nueva nota del proyecto para la etiqueta '{0}'?</translation>
</message>
@@ -1058,7 +1058,7 @@
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="61" />
<source>Document Headings</source>
<translation type="unfinished" />
<translation>Títulación de Documentos</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="64" />
@@ -1068,22 +1068,22 @@
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="86" />
<source>Split on Heading Level 1 (Partition)</source>
<translation type="unfinished" />
<translation>Separar por el Nivel de Título 1 (Partición)</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="87" />
<source>Split up to Heading Level 2 (Chapter)</source>
<translation type="unfinished" />
<translation>Separar hasta el Nivel de Título 2 (Capítulo)</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="88" />
<source>Split up to Heading Level 3 (Scene)</source>
<translation type="unfinished" />
<translation>Separar hasta el Nivel de Título 3 (Escena)</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="89" />
<source>Split up to Heading Level 4 (Section)</source>
<translation type="unfinished" />
<translation>Separar hasta el Nivel de Título 4 (Sección)</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="96" />
@@ -1104,52 +1104,52 @@
<context>
<name>GuiDocToolBar</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2268" />
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
<source>Markdown Bold</source>
<translation>Negrita (de Markdown)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2274" />
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
<source>Markdown Italic</source>
<translation>Cursiva (de Markdown)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2280" />
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
<source>Markdown Strikethrough</source>
<translation>Tachado (de Markdown)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2286" />
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
<source>Shortcode Bold</source>
<translation>Negrita (en código)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2292" />
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
<source>Shortcode Italic</source>
<translation>Cursiva (en código)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2298" />
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
<source>Shortcode Strikethrough</source>
<translation>Tachado (en código)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2304" />
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
<source>Shortcode Underline</source>
<translation>Subrayado (en código)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2310" />
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
<source>Shortcode Highlight</source>
<translation type="unfinished" />
<translation>Resaltado (en código)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2316" />
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
<source>Shortcode Superscript</source>
<translation>Superíndice (en código)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2322" />
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
<source>Shortcode Subscript</source>
<translation>Subíndice (en código)</translation>
</message>
@@ -1187,7 +1187,7 @@
<message>
<location filename="../novelwriter/gui/docviewer.py" line="659" />
<source>Outline</source>
<translation type="unfinished" />
<translation>Estructura</translation>
</message>
<message>
<location filename="../novelwriter/gui/docviewer.py" line="664" />
@@ -1854,7 +1854,7 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="676" />
<source>Highlight</source>
<translation type="unfinished" />
<translation>Resaltar</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="682" />
@@ -1869,22 +1869,22 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="697" />
<source>Heading 1 (Partition)</source>
<translation type="unfinished" />
<translation>Título 1 (Partición)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="704" />
<source>Heading 2 (Chapter)</source>
<translation type="unfinished" />
<translation>Título 2 (Capítulo)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="711" />
<source>Heading 3 (Scene)</source>
<translation type="unfinished" />
<translation>Título 3 (Escena)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="718" />
<source>Heading 4 (Section)</source>
<translation type="unfinished" />
<translation>Título 4 (Sección)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="728" />
@@ -1898,8 +1898,8 @@
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="740" />
<source>Hard Scene</source>
<translation type="unfinished" />
<source>Alternative Scene</source>
<translation>Escena Alternativa</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="749" />
@@ -1944,12 +1944,12 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="814" />
<source>Replace Straight Single Quotes</source>
<translation type="unfinished" />
<translation>Reemplazar Apóstrofos</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="820" />
<source>Replace Straight Double Quotes</source>
<translation type="unfinished" />
<translation>Reemplazar Comillas ASCII</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="826" />
@@ -1989,7 +1989,7 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="869" />
<source>Find in Project</source>
<translation type="unfinished" />
<translation>Buscar en el Proyecto</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="878" />
@@ -2161,12 +2161,12 @@
<message>
<location filename="../novelwriter/tools/manuscript.py" line="158" />
<source>Details</source>
<translation type="unfinished" />
<translation>Detalles</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="159" />
<source>Outline</source>
<translation type="unfinished" />
<translation>Estructura</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="173" />
@@ -2997,27 +2997,27 @@
<message>
<location filename="../novelwriter/gui/search.py" line="74" />
<source>Project Search</source>
<translation type="unfinished" />
<translation>Búsqueda en Proyecto</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="84" />
<source>Case Sensitive</source>
<translation type="unfinished">Sensibilidad a Mayúsculas y Minúsculas</translation>
<translation>Sensibilidad a Mayúsculas y Minúsculas</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="89" />
<source>Whole Words Only</source>
<translation type="unfinished">Sólo Palabras Enteras</translation>
<translation>Sólo Palabras Enteras</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="94" />
<source>RegEx Mode</source>
<translation type="unfinished">Modo ExReg</translation>
<translation>Modo ExReg</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="101" />
<source>Search for</source>
<translation type="unfinished" />
<translation>Buscar</translation>
</message>
</context>
<context>
@@ -3231,7 +3231,7 @@
<message>
<location filename="../novelwriter/gui/sidebar.py" line="73" />
<source>Project Search</source>
<translation type="unfinished" />
<translation>Búsqueda en Proyecto</translation>
</message>
<message>
<location filename="../novelwriter/gui/sidebar.py" line="77" />
@@ -4068,7 +4068,7 @@
<message>
<location filename="../novelwriter/tools/manuscript.py" line="619" />
<source>Hidden</source>
<translation type="unfinished">Ocultar</translation>
<translation>Oculto</translation>
</message>
</context>
<context>
@@ -4209,21 +4209,21 @@
<message>
<location filename="../novelwriter/tools/manussettings.py" line="758" />
<source>Additional Styling</source>
<translation type="unfinished" />
<translation>Estilos Adicionales</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="795" />
<location filename="../novelwriter/tools/manussettings.py" line="780" />
<location filename="../novelwriter/tools/manussettings.py" line="765" />
<source>Centre</source>
<translation type="unfinished" />
<translation>Centrado</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="797" />
<location filename="../novelwriter/tools/manussettings.py" line="782" />
<location filename="../novelwriter/tools/manussettings.py" line="767" />
<source>Page Break</source>
<translation type="unfinished">Salto de Página</translation>
<translation>Salto de Página</translation>
</message>
</context>
<context>
@@ -4560,58 +4560,58 @@
<location filename="../novelwriter/tools/manuscript.py" line="1097" />
<location filename="../novelwriter/tools/manuscript.py" line="1057" />
<source>Words</source>
<translation type="unfinished">Palabras</translation>
<translation>Palabras</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1124" />
<location filename="../novelwriter/tools/manuscript.py" line="1060" />
<source>Characters</source>
<translation type="unfinished">Personajes</translation>
<translation>Caracteres</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1098" />
<source>Words in Headings</source>
<translation type="unfinished" />
<translation>Palabras en Titulos</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1099" />
<source>Words in Text</source>
<translation type="unfinished" />
<translation>Palabras en el Texto</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1101" />
<source>Headings</source>
<translation type="unfinished">Títulación</translation>
<translation>Títulos</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
<source>Paragraphs</source>
<translation type="unfinished">Párrafos</translation>
<translation>Párrafos</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1125" />
<source>Characters in Headings</source>
<translation type="unfinished" />
<translation>Caracteres en los Títulos</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1126" />
<source>Characters in Text</source>
<translation type="unfinished" />
<translation>Caracteres en el Texto</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1127" />
<source>Characters, No Spaces</source>
<translation type="unfinished" />
<translation>Caracteres, Sin Espacios</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1128" />
<source>Characters in Headings, No Spaces</source>
<translation type="unfinished" />
<translation>Caracteres en los Títulos, Sin Espacios</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
<source>Characters in Text, No Spaces</source>
<translation type="unfinished" />
<translation>Caracteres en el Texto, Sin Espacios</translation>
</message>
</context>
<context>
@@ -4771,7 +4771,7 @@
<message>
<location filename="../novelwriter/gui/projtree.py" line="1932" />
<source>Split Document by Headings</source>
<translation type="unfinished" />
<translation>Separar el Documento según Titulación</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="1942" />
@@ -4786,7 +4786,7 @@
<message>
<location filename="../novelwriter/gui/projtree.py" line="1947" />
<source>Duplicate</source>
<translation type="unfinished" />
<translation>Duplicar</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="1963" />
+109 -109
View File
@@ -31,32 +31,32 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="109" />
<source>Partition Format</source>
<translation type="unfinished" />
<translation>Formato della Partizione</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="110" />
<source>Chapter Format</source>
<translation type="unfinished" />
<translation>Formato del Capitolo</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="111" />
<source>Unnumbered Format</source>
<translation type="unfinished" />
<translation>Formato non numerato</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="112" />
<source>Scene Format</source>
<translation type="unfinished" />
<translation>Formato della Scena</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="113" />
<source>Hard Scene Format</source>
<translation type="unfinished" />
<source>Alt. Scene Format</source>
<translation>Formato scena alt.</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="114" />
<source>Section Format</source>
<translation type="unfinished" />
<translation>Formato della Sezione</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="116" />
@@ -86,7 +86,7 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="121" />
<source>Ignore These Keywords</source>
<translation type="unfinished" />
<translation>Ignora queste parole chiave</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="122" />
@@ -206,17 +206,17 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="147" />
<source>First Line Indent</source>
<translation type="unfinished" />
<translation>Rientro della prima linea</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="149" />
<source>Markdown (.md)</source>
<translation type="unfinished" />
<translation>Markdown (.md)</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="150" />
<source>Preserve Hard Line Breaks</source>
<translation type="unfinished" />
<translation>Conserva le interruzioni di linea</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="152" />
@@ -231,7 +231,7 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="154" />
<source>Preserve Tab Characters</source>
<translation type="unfinished" />
<translation>Conserva gli spazi di tabulazione</translation>
</message>
</context>
<context>
@@ -791,22 +791,22 @@
<context>
<name>GuiDocEditFooter</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3005" />
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
<source>Line: {0} ({1})</source>
<translation>Riga: {0} ({1})</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3006" />
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
<source>Words: {0} ({1})</source>
<translation>Parole: {0} ({1})</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
<source>Words: {0} selected</source>
<translation>Parole: {0} selezionate</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3019" />
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
<source>Status</source>
<translation>Stato</translation>
</message>
@@ -814,27 +814,27 @@
<context>
<name>GuiDocEditHeader</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2803" />
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
<source>Toggle Tool Bar</source>
<translation>Attiva/disattiva la Barra degli strumenti</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2808" />
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
<source>Outline</source>
<translation type="unfinished" />
<translation>Struttura</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2813" />
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
<source>Search</source>
<translation>Cerca</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2818" />
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
<source>Toggle Focus Mode</source>
<translation>Attiva/Disattiva modalità Focus</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2823" />
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
<source>Close</source>
<translation>Chiudi</translation>
</message>
@@ -842,62 +842,62 @@
<context>
<name>GuiDocEditSearch</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2411" />
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
<source>Search for</source>
<translation type="unfinished" />
<translation>Ricerca</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2416" />
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
<source>Replace with</source>
<translation type="unfinished" />
<translation>Sostituisci con</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2424" />
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
<source>Search</source>
<translation>Cerca</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2432" />
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
<source>Case Sensitive</source>
<translation>Considera maiuscole/minuscole</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2438" />
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
<source>Whole Words Only</source>
<translation>Solo parole intere</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2444" />
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
<source>RegEx Mode</source>
<translation>Modalità RegEx</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2450" />
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
<source>Loop Search</source>
<translation>Ricerca a ciclo continuo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2456" />
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
<source>Search Next File</source>
<translation>Cerca nel file successivo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2464" />
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
<source>Preserve Case</source>
<translation>Non considerare maiuscole/minuscole</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2472" />
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
<source>Close Search</source>
<translation>Chiudi ricerca</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2483" />
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
<source>Find in current document</source>
<translation>Trova nel documento corrente</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2487" />
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
<source>Find and replace in current document</source>
<translation>Trova e sostituisci nel documento corrente</translation>
</message>
@@ -920,107 +920,107 @@
<translation>Impossibile salvare il documento.</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="517" />
<location filename="../novelwriter/gui/doceditor.py" line="518" />
<source>Saved Document: {0}</source>
<translation>Documento salvato: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="686" />
<location filename="../novelwriter/gui/doceditor.py" line="687" />
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
<translation>Il controllo ortografico richiede il pacchetto PyEnchant. Non sembra essere installato.</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="712" />
<location filename="../novelwriter/gui/doceditor.py" line="713" />
<source>Spell check complete</source>
<translation>Controllo ortografico completo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="832" />
<location filename="../novelwriter/gui/doceditor.py" line="833" />
<source>Document Details</source>
<translation>Dettagli del documento</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="834" />
<location filename="../novelwriter/gui/doceditor.py" line="835" />
<source>Created: {0}</source>
<translation>Creato: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="835" />
<location filename="../novelwriter/gui/doceditor.py" line="836" />
<source>Updated: {0}</source>
<translation>Aggiornato: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="837" />
<location filename="../novelwriter/gui/doceditor.py" line="838" />
<source>File Location: {0}</source>
<translation>Posizione del file: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1111" />
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
<source>Set as Document Name</source>
<translation>Imposta come nome del documento</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1117" />
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
<source>Follow Tag</source>
<translation>Segui i Tag</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1121" />
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
<source>Create Note for Tag</source>
<translation>Crea una nota per il Tag</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1127" />
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
<source>Cut</source>
<translation>Taglia</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
<source>Copy</source>
<translation>Copia</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1132" />
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
<source>Paste</source>
<translation>Incolla</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1137" />
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
<source>Select All</source>
<translation>Seleziona tutto</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
<source>Select Word</source>
<translation>Seleziona parola</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1143" />
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
<source>Select Paragraph</source>
<translation>Seleziona paragrafo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1159" />
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
<source>Spelling Suggestion(s)</source>
<translation>Suggerimento(i) ortografico(i)</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1166" />
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
<source>No Suggestions</source>
<translation>Nessun suggerimento</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1169" />
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
<source>Add Word to Dictionary</source>
<translation>Aggiungi parola al dizionario</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1594" />
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
<source>Please select some text before calling replace quotes.</source>
<translation>Per favore seleziona del testo prima di chiedere il cambio di virgolette.</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1901" />
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
<source>Do you want to create a new project note for the tag '{0}'?</source>
<translation>Vuoi creare una nuova nota di progetto per il tag '{0}'?</translation>
</message>
@@ -1058,7 +1058,7 @@
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="61" />
<source>Document Headings</source>
<translation type="unfinished" />
<translation>Intestazioni del documento</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="64" />
@@ -1068,22 +1068,22 @@
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="86" />
<source>Split on Heading Level 1 (Partition)</source>
<translation type="unfinished" />
<translation>Dividi sul livello d'intestazione 1 (Partizione)</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="87" />
<source>Split up to Heading Level 2 (Chapter)</source>
<translation type="unfinished" />
<translation>Dividi sul livello d'intestazione 2 (Capitolo)</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="88" />
<source>Split up to Heading Level 3 (Scene)</source>
<translation type="unfinished" />
<translation>Dividi sul livello d'intestazione 3 (Scena)</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="89" />
<source>Split up to Heading Level 4 (Section)</source>
<translation type="unfinished" />
<translation>Dividi sul livello d'intestazione 4 (Sezione)</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="96" />
@@ -1104,52 +1104,52 @@
<context>
<name>GuiDocToolBar</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2268" />
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
<source>Markdown Bold</source>
<translation>Markdown grassetto</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2274" />
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
<source>Markdown Italic</source>
<translation>Markdown corsivo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2280" />
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
<source>Markdown Strikethrough</source>
<translation>Markdown barrato</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2286" />
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
<source>Shortcode Bold</source>
<translation>Shortcode grassetto</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2292" />
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
<source>Shortcode Italic</source>
<translation>Shortcode corsivo</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2298" />
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
<source>Shortcode Strikethrough</source>
<translation>Shortcode barrato</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2304" />
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
<source>Shortcode Underline</source>
<translation>Shortcode sottolineato</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2310" />
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
<source>Shortcode Highlight</source>
<translation type="unfinished" />
<translation>Evidenziazione</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2316" />
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
<source>Shortcode Superscript</source>
<translation>Shortcode apice</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2322" />
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
<source>Shortcode Subscript</source>
<translation>Shortcode pendice</translation>
</message>
@@ -1187,7 +1187,7 @@
<message>
<location filename="../novelwriter/gui/docviewer.py" line="659" />
<source>Outline</source>
<translation type="unfinished" />
<translation>Struttura</translation>
</message>
<message>
<location filename="../novelwriter/gui/docviewer.py" line="664" />
@@ -1854,7 +1854,7 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="676" />
<source>Highlight</source>
<translation type="unfinished" />
<translation>Evidenzia</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="682" />
@@ -1869,22 +1869,22 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="697" />
<source>Heading 1 (Partition)</source>
<translation type="unfinished" />
<translation>Titolo 1 (Partizione)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="704" />
<source>Heading 2 (Chapter)</source>
<translation type="unfinished" />
<translation>Titolo 2 (Capitolo)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="711" />
<source>Heading 3 (Scene)</source>
<translation type="unfinished" />
<translation>Titolo 3 (Scena)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="718" />
<source>Heading 4 (Section)</source>
<translation type="unfinished" />
<translation>Titolo 4 (Sezione)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="728" />
@@ -1898,8 +1898,8 @@
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="740" />
<source>Hard Scene</source>
<translation type="unfinished" />
<source>Alternative Scene</source>
<translation>Scena alternativa</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="749" />
@@ -1944,12 +1944,12 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="814" />
<source>Replace Straight Single Quotes</source>
<translation type="unfinished" />
<translation>Sostituisci le singole virgolette dritte</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="820" />
<source>Replace Straight Double Quotes</source>
<translation type="unfinished" />
<translation>Sostituisci le doppie virgolette dritte</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="826" />
@@ -1989,7 +1989,7 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="869" />
<source>Find in Project</source>
<translation type="unfinished" />
<translation>Trova nel progetto</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="878" />
@@ -2161,12 +2161,12 @@
<message>
<location filename="../novelwriter/tools/manuscript.py" line="158" />
<source>Details</source>
<translation type="unfinished" />
<translation>Dettagli</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="159" />
<source>Outline</source>
<translation type="unfinished" />
<translation>Struttura</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="173" />
@@ -2997,27 +2997,27 @@
<message>
<location filename="../novelwriter/gui/search.py" line="74" />
<source>Project Search</source>
<translation type="unfinished" />
<translation>Ricerca nel progetto</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="84" />
<source>Case Sensitive</source>
<translation type="unfinished">Considera maiuscole/minuscole</translation>
<translation>Considera maiuscole/minuscole</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="89" />
<source>Whole Words Only</source>
<translation type="unfinished">Solo parole intere</translation>
<translation>Solo parole intere</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="94" />
<source>RegEx Mode</source>
<translation type="unfinished">Modalità RegEx</translation>
<translation>Modalità RegEx</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="101" />
<source>Search for</source>
<translation type="unfinished" />
<translation>Ricerca</translation>
</message>
</context>
<context>
@@ -3231,7 +3231,7 @@
<message>
<location filename="../novelwriter/gui/sidebar.py" line="73" />
<source>Project Search</source>
<translation type="unfinished" />
<translation>Ricerca nel progetto</translation>
</message>
<message>
<location filename="../novelwriter/gui/sidebar.py" line="77" />
@@ -4068,7 +4068,7 @@
<message>
<location filename="../novelwriter/tools/manuscript.py" line="619" />
<source>Hidden</source>
<translation type="unfinished">Nascosto</translation>
<translation>Nascosto</translation>
</message>
</context>
<context>
@@ -4209,21 +4209,21 @@
<message>
<location filename="../novelwriter/tools/manussettings.py" line="758" />
<source>Additional Styling</source>
<translation type="unfinished" />
<translation>Elementi di stile supplementari</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="795" />
<location filename="../novelwriter/tools/manussettings.py" line="780" />
<location filename="../novelwriter/tools/manussettings.py" line="765" />
<source>Centre</source>
<translation type="unfinished" />
<translation>Centro</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="797" />
<location filename="../novelwriter/tools/manussettings.py" line="782" />
<location filename="../novelwriter/tools/manussettings.py" line="767" />
<source>Page Break</source>
<translation type="unfinished">Interruzione di pagina</translation>
<translation>Interruzione di pagina</translation>
</message>
</context>
<context>
@@ -4560,58 +4560,58 @@
<location filename="../novelwriter/tools/manuscript.py" line="1097" />
<location filename="../novelwriter/tools/manuscript.py" line="1057" />
<source>Words</source>
<translation type="unfinished">Parole</translation>
<translation>Parole</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1124" />
<location filename="../novelwriter/tools/manuscript.py" line="1060" />
<source>Characters</source>
<translation type="unfinished">Caratteri</translation>
<translation>Caratteri</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1098" />
<source>Words in Headings</source>
<translation type="unfinished" />
<translation>Parole nelle intestazioni</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1099" />
<source>Words in Text</source>
<translation type="unfinished" />
<translation>Parole nel testo</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1101" />
<source>Headings</source>
<translation type="unfinished">Intestazioni</translation>
<translation>Intestazioni</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
<source>Paragraphs</source>
<translation type="unfinished">Paragrafi</translation>
<translation>Paragrafi</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1125" />
<source>Characters in Headings</source>
<translation type="unfinished" />
<translation>Caratteri nelle intestazioni</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1126" />
<source>Characters in Text</source>
<translation type="unfinished" />
<translation>Caratteri nel testo</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1127" />
<source>Characters, No Spaces</source>
<translation type="unfinished" />
<translation>Caratteri, esclusi gli spazi</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1128" />
<source>Characters in Headings, No Spaces</source>
<translation type="unfinished" />
<translation>Caratteri nelle intestazioni, esclusi gli spazi</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
<source>Characters in Text, No Spaces</source>
<translation type="unfinished" />
<translation>Caratteri nel testo, esclusi gli spazi</translation>
</message>
</context>
<context>
@@ -4771,7 +4771,7 @@
<message>
<location filename="../novelwriter/gui/projtree.py" line="1932" />
<source>Split Document by Headings</source>
<translation type="unfinished" />
<translation>Dividi il documento alle intestazioni</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="1942" />
@@ -4786,7 +4786,7 @@
<message>
<location filename="../novelwriter/gui/projtree.py" line="1947" />
<source>Duplicate</source>
<translation type="unfinished" />
<translation>Duplica</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="1963" />
+149 -149
View File
@@ -31,32 +31,32 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="109" />
<source>Partition Format</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="110" />
<source>Chapter Format</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="111" />
<source>Unnumbered Format</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="112" />
<source>Scene Format</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="113" />
<source>Hard Scene Format</source>
<translation type="unfinished" />
<source>Alt. Scene Format</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="114" />
<source>Section Format</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="116" />
@@ -86,7 +86,7 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="121" />
<source>Ignore These Keywords</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="122" />
@@ -196,7 +196,7 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="145" />
<source>Page Header</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="146" />
@@ -206,17 +206,17 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="147" />
<source>First Line Indent</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="149" />
<source>Markdown (.md)</source>
<translation type="unfinished" />
<translation> (.md)</translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="150" />
<source>Preserve Hard Line Breaks</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/core/buildsettings.py" line="152" />
@@ -231,7 +231,7 @@
<message>
<location filename="../novelwriter/core/buildsettings.py" line="154" />
<source>Preserve Tab Characters</source>
<translation type="unfinished" />
<translation></translation>
</message>
</context>
<context>
@@ -409,17 +409,17 @@
<message>
<location filename="../novelwriter/constants.py" line="215" />
<source>Novel Chapter</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/constants.py" line="216" />
<source>Novel Scene</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/constants.py" line="217" />
<source>Novel Section</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/constants.py" line="221" />
@@ -791,22 +791,22 @@
<context>
<name>GuiDocEditFooter</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3005" />
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
<source>Line: {0} ({1})</source>
<translation>: {0} ({1})</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3006" />
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
<source>Words: {0} ({1})</source>
<translation>: {0} ({1})</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
<source>Words: {0} selected</source>
<translation>: {0} </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3019" />
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
<source>Status</source>
<translation></translation>
</message>
@@ -814,27 +814,27 @@
<context>
<name>GuiDocEditHeader</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2803" />
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
<source>Toggle Tool Bar</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2808" />
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
<source>Outline</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2813" />
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
<source>Search</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2818" />
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
<source>Toggle Focus Mode</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2823" />
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
<source>Close</source>
<translation></translation>
</message>
@@ -842,62 +842,62 @@
<context>
<name>GuiDocEditSearch</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2411" />
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
<source>Search for</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2416" />
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
<source>Replace with</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2424" />
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
<source>Search</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2432" />
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
<source>Case Sensitive</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2438" />
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
<source>Whole Words Only</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2444" />
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
<source>RegEx Mode</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2450" />
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
<source>Loop Search</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2456" />
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
<source>Search Next File</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2464" />
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
<source>Preserve Case</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2472" />
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
<source>Close Search</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2483" />
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
<source>Find in current document</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2487" />
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
<source>Find and replace in current document</source>
<translation></translation>
</message>
@@ -920,107 +920,107 @@
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="517" />
<location filename="../novelwriter/gui/doceditor.py" line="518" />
<source>Saved Document: {0}</source>
<translation>: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="686" />
<location filename="../novelwriter/gui/doceditor.py" line="687" />
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
<translation>PyEnchantパッケージが必要ですが</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="712" />
<location filename="../novelwriter/gui/doceditor.py" line="713" />
<source>Spell check complete</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="832" />
<location filename="../novelwriter/gui/doceditor.py" line="833" />
<source>Document Details</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="834" />
<location filename="../novelwriter/gui/doceditor.py" line="835" />
<source>Created: {0}</source>
<translation>: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="835" />
<location filename="../novelwriter/gui/doceditor.py" line="836" />
<source>Updated: {0}</source>
<translation>: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="837" />
<location filename="../novelwriter/gui/doceditor.py" line="838" />
<source>File Location: {0}</source>
<translation>: {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1111" />
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
<source>Set as Document Name</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1117" />
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
<source>Follow Tag</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1121" />
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
<source>Create Note for Tag</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1127" />
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
<source>Cut</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
<source>Copy</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1132" />
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
<source>Paste</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1137" />
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
<source>Select All</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
<source>Select Word</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1143" />
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
<source>Select Paragraph</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1159" />
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
<source>Spelling Suggestion(s)</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1166" />
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
<source>No Suggestions</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1169" />
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
<source>Add Word to Dictionary</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1594" />
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
<source>Please select some text before calling replace quotes.</source>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="1901" />
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
<source>Do you want to create a new project note for the tag '{0}'?</source>
<translation> '{0}' </translation>
</message>
@@ -1058,7 +1058,7 @@
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="61" />
<source>Document Headings</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="64" />
@@ -1068,22 +1068,22 @@
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="86" />
<source>Split on Heading Level 1 (Partition)</source>
<translation type="unfinished" />
<translation>1 () </translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="87" />
<source>Split up to Heading Level 2 (Chapter)</source>
<translation type="unfinished" />
<translation>2 () </translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="88" />
<source>Split up to Heading Level 3 (Scene)</source>
<translation type="unfinished" />
<translation>3 () </translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="89" />
<source>Split up to Heading Level 4 (Section)</source>
<translation type="unfinished" />
<translation>4 () </translation>
</message>
<message>
<location filename="../novelwriter/dialogs/docsplit.py" line="96" />
@@ -1104,52 +1104,52 @@
<context>
<name>GuiDocToolBar</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2268" />
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
<source>Markdown Bold</source>
<translation> </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2274" />
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
<source>Markdown Italic</source>
<translation> </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2280" />
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
<source>Markdown Strikethrough</source>
<translation> </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2286" />
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
<source>Shortcode Bold</source>
<translation> </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2292" />
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
<source>Shortcode Italic</source>
<translation> </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2298" />
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
<source>Shortcode Strikethrough</source>
<translation> </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2304" />
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
<source>Shortcode Underline</source>
<translation> </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2310" />
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
<source>Shortcode Highlight</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2316" />
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
<source>Shortcode Superscript</source>
<translation> </translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2322" />
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
<source>Shortcode Subscript</source>
<translation> </translation>
</message>
@@ -1187,7 +1187,7 @@
<message>
<location filename="../novelwriter/gui/docviewer.py" line="659" />
<source>Outline</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/docviewer.py" line="664" />
@@ -1644,22 +1644,22 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="394" />
<source>Left Single Quote</source>
<translation>左シングルクォーテーション</translation>
<translation>左シングルクォー</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="401" />
<source>Right Single Quote</source>
<translation>右シングルクォーテーション</translation>
<translation>右シングルクォー</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="408" />
<source>Left Double Quote</source>
<translation>左ダブルクォーテーション</translation>
<translation>左ダブルクォー</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="415" />
<source>Right Double Quote</source>
<translation>右ダブルクォーテーション</translation>
<translation>右ダブルクォー</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="422" />
@@ -1819,12 +1819,12 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="632" />
<source>Wrap Double Quotes</source>
<translation>ダブルクォーテーションで包む</translation>
<translation>ダブルクォーで包む</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="639" />
<source>Wrap Single Quotes</source>
<translation>シングルクォーテーションで包む</translation>
<translation>シングルクォーで包む</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="649" />
@@ -1854,7 +1854,7 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="676" />
<source>Highlight</source>
<translation type="unfinished" />
<translation>ハイライト</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="682" />
@@ -1869,22 +1869,22 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="697" />
<source>Heading 1 (Partition)</source>
<translation type="unfinished" />
<translation>見出し1 (パーティション)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="704" />
<source>Heading 2 (Chapter)</source>
<translation type="unfinished" />
<translation>見出し2 (チャプター)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="711" />
<source>Heading 3 (Scene)</source>
<translation type="unfinished" />
<translation>見出し3 (シーン)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="718" />
<source>Heading 4 (Section)</source>
<translation type="unfinished" />
<translation>見出し4 (セクション)</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="728" />
@@ -1894,12 +1894,12 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="734" />
<source>Unnumbered Chapter</source>
<translation>番号のない章</translation>
<translation>番号なしチャプター</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="740" />
<source>Hard Scene</source>
<translation type="unfinished" />
<source>Alternative Scene</source>
<translation>代替シーン</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="749" />
@@ -1944,12 +1944,12 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="814" />
<source>Replace Straight Single Quotes</source>
<translation type="unfinished" />
<translation>直線シングルクォートを置き換え</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="820" />
<source>Replace Straight Double Quotes</source>
<translation type="unfinished" />
<translation>直線ダブルクォートを置換</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="826" />
@@ -1989,7 +1989,7 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="869" />
<source>Find in Project</source>
<translation type="unfinished" />
<translation>プロジェクト内を検索</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="878" />
@@ -2161,12 +2161,12 @@
<message>
<location filename="../novelwriter/tools/manuscript.py" line="158" />
<source>Details</source>
<translation type="unfinished" />
<translation>詳細</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="159" />
<source>Outline</source>
<translation type="unfinished" />
<translation>アウトライン</translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="173" />
@@ -2351,17 +2351,17 @@
<message>
<location filename="../novelwriter/gui/outline.py" line="782" />
<source>Chapter</source>
<translation></translation>
<translation>チャプター</translation>
</message>
<message>
<location filename="../novelwriter/gui/outline.py" line="783" />
<source>Scene</source>
<translation>場面</translation>
<translation>シーン</translation>
</message>
<message>
<location filename="../novelwriter/gui/outline.py" line="784" />
<source>Section</source>
<translation></translation>
<translation>セクション</translation>
</message>
<message>
<location filename="../novelwriter/gui/outline.py" line="807" />
@@ -2551,7 +2551,7 @@
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="261" />
<source>Emphasise partition and chapter labels</source>
<translation>パーティションとラベルを強調</translation>
<translation>パーティションとチャプターラベルを強調</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="262" />
@@ -2561,12 +2561,12 @@
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="269" />
<source>Show full path in document header</source>
<translation>ドキュメント見出しにフルパスを表示</translation>
<translation>ドキュメントヘッダーにフルパスを表示</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="270" />
<source>Add the parent folder names to the header.</source>
<translation>親フォルダ名を見出しに追加します。</translation>
<translation>親フォルダ名をヘッダーに追加します。</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="277" />
@@ -2821,7 +2821,7 @@
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="545" />
<source>Highlight text wrapped in quotes</source>
<translation>引用符で囲まれたテキストを強調</translation>
<translation>引用符で囲まれたテキストをハイライト</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="574" />
@@ -2833,22 +2833,22 @@
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="552" />
<source>Allow open-ended single quotes</source>
<translation>オープンエンドのシングルクォートを許可</translation>
<translation>閉じないシングルクォートを許可</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="553" />
<source>Highlight single-quoted line with no closing quote.</source>
<translation>終了引用符がないシングルクォートの行を強調表示します。</translation>
<translation>終了引用符がないシングルクォートの行をハイライト表示します。</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="559" />
<source>Allow open-ended double quotes</source>
<translation>オープンエンドのダブルクォートを許可</translation>
<translation>閉じないダブルクォートを許可</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="560" />
<source>Highlight double-quoted line with no closing quote.</source>
<translation>終了引用符がないダブルクォートの行を強調表示します。</translation>
<translation>終了引用符がないダブルクォートの行をハイライト表示します。</translation>
</message>
<message>
<location filename="../novelwriter/dialogs/preferences.py" line="566" />
@@ -2997,27 +2997,27 @@
<message>
<location filename="../novelwriter/gui/search.py" line="74" />
<source>Project Search</source>
<translation type="unfinished" />
<translation>プロジェクト検索</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="84" />
<source>Case Sensitive</source>
<translation type="unfinished">大文字と小文字を区別</translation>
<translation>大文字と小文字を区別</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="89" />
<source>Whole Words Only</source>
<translation type="unfinished">完全一致のみ</translation>
<translation>完全一致のみ</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="94" />
<source>RegEx Mode</source>
<translation type="unfinished">正規表現モード</translation>
<translation>正規表現モード</translation>
</message>
<message>
<location filename="../novelwriter/gui/search.py" line="101" />
<source>Search for</source>
<translation type="unfinished" />
<translation>検索</translation>
</message>
</context>
<context>
@@ -3132,12 +3132,12 @@
<message>
<location filename="../novelwriter/gui/projtree.py" line="666" />
<source>New Chapter</source>
<translation>新規</translation>
<translation>新規チャプター</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="669" />
<source>New Scene</source>
<translation>新規場面</translation>
<translation>新規シーン</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="672" />
@@ -3231,7 +3231,7 @@
<message>
<location filename="../novelwriter/gui/sidebar.py" line="73" />
<source>Project Search</source>
<translation type="unfinished" />
<translation>プロジェクト検索</translation>
</message>
<message>
<location filename="../novelwriter/gui/sidebar.py" line="77" />
@@ -3671,12 +3671,12 @@
<message>
<location filename="../novelwriter/core/coretools.py" line="479" />
<source>Summary of the chapter.</source>
<translation>の概要。</translation>
<translation>チャプターの概要。</translation>
</message>
<message>
<location filename="../novelwriter/core/coretools.py" line="480" />
<source>Summary of the scene.</source>
<translation>場面の概要。</translation>
<translation>シーンの概要。</translation>
</message>
<message>
<location filename="../novelwriter/core/coretools.py" line="481" />
@@ -3686,13 +3686,13 @@
<message>
<location filename="../novelwriter/core/coretools.py" line="486" />
<source>Chapter {0}</source>
<translation> {0}</translation>
<translation>チャプター {0}</translation>
</message>
<message>
<location filename="../novelwriter/core/coretools.py" line="502" />
<location filename="../novelwriter/core/coretools.py" line="494" />
<source>Scene {0}</source>
<translation>場面 {0}</translation>
<translation>シーン {0}</translation>
</message>
<message>
<location filename="../novelwriter/core/coretools.py" line="509" />
@@ -4025,7 +4025,7 @@
<message>
<location filename="../novelwriter/tools/noveldetails.py" line="387" />
<source>Chapters on odd pages</source>
<translation>奇数ページ上の</translation>
<translation>奇数ページ上のチャプター</translation>
</message>
<message>
<location filename="../novelwriter/tools/noveldetails.py" line="486" />
@@ -4068,7 +4068,7 @@
<message>
<location filename="../novelwriter/tools/manuscript.py" line="619" />
<source>Hidden</source>
<translation type="unfinished">非表示</translation>
<translation>非表示</translation>
</message>
</context>
<context>
@@ -4159,32 +4159,32 @@
<message>
<location filename="../novelwriter/tools/manussettings.py" line="716" />
<source>Chapter Number</source>
<translation>番号</translation>
<translation>チャプター番号</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="717" />
<source>Chapter Number (Word)</source>
<translation>番号 (文章)</translation>
<translation>チャプター番号 (文章)</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="718" />
<source>Chapter Number (Upper Case Roman)</source>
<translation>番号 (大文字のローマ字)</translation>
<translation>チャプター番号 (大文字のローマ字)</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="719" />
<source>Chapter Number (Lower Case Roman)</source>
<translation>番号 (小文字のローマ字)</translation>
<translation>チャプター番号 (小文字のローマ字)</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="720" />
<source>Scene Number (In Chapter)</source>
<translation>場面番号 (チャプター内)</translation>
<translation>シーン番号 (チャプター内)</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="721" />
<source>Scene Number (Absolute)</source>
<translation>場面番号 (絶対)</translation>
<translation>シーン番号 (絶対)</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="722" />
@@ -4209,21 +4209,21 @@
<message>
<location filename="../novelwriter/tools/manussettings.py" line="758" />
<source>Additional Styling</source>
<translation type="unfinished" />
<translation>追加のスタイル</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="795" />
<location filename="../novelwriter/tools/manussettings.py" line="780" />
<location filename="../novelwriter/tools/manussettings.py" line="765" />
<source>Centre</source>
<translation type="unfinished" />
<translation>中央</translation>
</message>
<message>
<location filename="../novelwriter/tools/manussettings.py" line="797" />
<location filename="../novelwriter/tools/manussettings.py" line="782" />
<location filename="../novelwriter/tools/manussettings.py" line="767" />
<source>Page Break</source>
<translation type="unfinished">改ページ</translation>
<translation>改ページ</translation>
</message>
</context>
<context>
@@ -4281,12 +4281,12 @@
<message>
<location filename="../novelwriter/tools/welcome.py" line="639" />
<source>Add {0} chapter documents</source>
<translation>{0} ドキュメントを追加</translation>
<translation>{0} チャプタードキュメントを追加</translation>
</message>
<message>
<location filename="../novelwriter/tools/welcome.py" line="648" />
<source>Add {0} scene documents (to each chapter)</source>
<translation>{0} 場面ドキュメントを追加(各に)</translation>
<translation>{0} シーンドキュメントを追加(各チャプターに)</translation>
</message>
<message>
<location filename="../novelwriter/tools/welcome.py" line="676" />
@@ -4311,7 +4311,7 @@
<message>
<location filename="../novelwriter/tools/welcome.py" line="685" />
<source>Chapters and Scenes</source>
<translation>章と場面</translation>
<translation>チャプターとシーン</translation>
</message>
<message>
<location filename="../novelwriter/tools/welcome.py" line="688" />
@@ -4427,12 +4427,12 @@
<message>
<location filename="../novelwriter/tools/noveldetails.py" line="239" />
<source>Chapters</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/noveldetails.py" line="240" />
<source>Scenes</source>
<translation></translation>
<translation></translation>
</message>
</context>
<context>
@@ -4560,58 +4560,58 @@
<location filename="../novelwriter/tools/manuscript.py" line="1097" />
<location filename="../novelwriter/tools/manuscript.py" line="1057" />
<source>Words</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1124" />
<location filename="../novelwriter/tools/manuscript.py" line="1060" />
<source>Characters</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1098" />
<source>Words in Headings</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1099" />
<source>Words in Text</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1101" />
<source>Headings</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
<source>Paragraphs</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1125" />
<source>Characters in Headings</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1126" />
<source>Characters in Text</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1127" />
<source>Characters, No Spaces</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1128" />
<source>Characters in Headings, No Spaces</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
<source>Characters in Text, No Spaces</source>
<translation type="unfinished" />
<translation></translation>
</message>
</context>
<context>
@@ -4771,7 +4771,7 @@
<message>
<location filename="../novelwriter/gui/projtree.py" line="1932" />
<source>Split Document by Headings</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="1942" />
@@ -4786,7 +4786,7 @@
<message>
<location filename="../novelwriter/gui/projtree.py" line="1947" />
<source>Duplicate</source>
<translation type="unfinished" />
<translation></translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="1963" />
+984 -984
View File
File diff suppressed because it is too large Load Diff
+13 -6
View File
@@ -23,16 +23,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import sys
import getopt
import logging
import sys
from typing import TYPE_CHECKING
from PyQt5.QtWidgets import QApplication, QErrorMessage
from novelwriter.error import exceptionHandler, logException
from novelwriter.config import Config
from novelwriter.error import exceptionHandler, logException
from novelwriter.shared import SharedData
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
# Package Meta
# ============
@@ -42,9 +47,9 @@ __license__ = "GPLv3"
__author__ = "Veronica Berglyd Olsen"
__maintainer__ = "Veronica Berglyd Olsen"
__email__ = "code@vkbo.net"
__version__ = "2.4rc1"
__hexversion__ = "0x020400c1"
__date__ = "2024-04-06"
__version__ = "2.5a1"
__hexversion__ = "0x020500a1"
__date__ = "2024-04-13"
__status__ = "Stable"
__domain__ = "novelwriter.io"
@@ -60,7 +65,7 @@ CONFIG = Config()
SHARED = SharedData()
def main(sysArgs: list | None = None):
def main(sysArgs: list | None = None) -> GuiMain | None:
"""Parse command line, set up logging, and launch main GUI."""
if sysArgs is None:
sysArgs = sys.argv[1:]
@@ -239,4 +244,6 @@ def main(sysArgs: list | None = None):
sys.exit(nwApp.exec())
return None
# END Function main
+5 -2
View File
@@ -449,7 +449,7 @@ def xmlIndent(tree: ET.Element | ET.ElementTree) -> None:
indentations = ["\n"]
def indentChildren(elem, level):
def indentChildren(elem: ET.Element, level: int) -> None:
chLevel = level + 1
try:
chIndent = indentations[chLevel]
@@ -472,6 +472,8 @@ def xmlIndent(tree: ET.Element | ET.ElementTree) -> None:
if last is not None:
last.tail = indentations[level]
return
if len(tree):
indentChildren(tree, 0)
tree.tail = "\n"
@@ -534,8 +536,9 @@ class NWConfigParser(ConfigParser):
helper functions, and support for lists.
"""
def __init__(self):
def __init__(self) -> None:
super().__init__()
return
def rdStr(self, section: str, option: str, default: str) -> str:
"""Read string value."""
+4
View File
@@ -390,6 +390,10 @@ class Config:
"""Un-scale fixed gui sizes by the screen scale factor."""
return int(value/self.guiScale)
def homePath(self) -> Path:
"""The user's home folder."""
return self._homePath
def dataPath(self, target: str | None = None) -> Path:
"""Return a path in the data folder."""
if isinstance(target, str):
+29 -1
View File
@@ -25,7 +25,7 @@ from __future__ import annotations
from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
from novelwriter.enum import nwBuildFmt, nwItemClass, nwItemLayout, nwOutline
from novelwriter.enum import nwBuildFmt, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
def trConst(text: str) -> str:
@@ -268,6 +268,34 @@ class nwLabels:
nwBuildFmt.J_HTML: ".json",
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"),
}
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"),
}
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"),
}
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"),
}
FILE_FILTERS = {
"*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
"*.md": QT_TRANSLATE_NOOP("Constant", "Markdown files"),
+7 -7
View File
@@ -56,13 +56,13 @@ SETTINGS_TEMPLATE = {
"headings.fmtChapter": (str, nwHeadFmt.TITLE),
"headings.fmtUnnumbered": (str, nwHeadFmt.TITLE),
"headings.fmtScene": (str, "* * *"),
"headings.fmtHardScene": (str, ""),
"headings.fmtAltScene": (str, ""),
"headings.fmtSection": (str, ""),
"headings.hideTitle": (bool, False),
"headings.hideChapter": (bool, False),
"headings.hideUnnumbered": (bool, False),
"headings.hideScene": (bool, False),
"headings.hideHardScene": (bool, False),
"headings.hideAltScene": (bool, False),
"headings.hideSection": (bool, True),
"headings.centerTitle": (bool, True),
"headings.centerChapter": (bool, False),
@@ -110,7 +110,7 @@ SETTINGS_LABELS = {
"headings.fmtChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Format"),
"headings.fmtUnnumbered": QT_TRANSLATE_NOOP("Builds", "Unnumbered Format"),
"headings.fmtScene": QT_TRANSLATE_NOOP("Builds", "Scene Format"),
"headings.fmtHardScene": QT_TRANSLATE_NOOP("Builds", "Hard Scene Format"),
"headings.fmtAltScene": QT_TRANSLATE_NOOP("Builds", "Alt. Scene Format"),
"headings.fmtSection": QT_TRANSLATE_NOOP("Builds", "Section Format"),
"text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"),
@@ -178,7 +178,7 @@ class BuildSettings:
def __init__(self) -> None:
self._name = ""
self._uuid = str(uuid.uuid4())
self._path = Path.home()
self._path = CONFIG.homePath()
self._build = ""
self._order = 0
self._format = nwBuildFmt.ODT
@@ -220,7 +220,7 @@ class BuildSettings:
"""The last used build path."""
if self._path.is_dir():
return self._path
return Path.home()
return CONFIG.homePath()
@property
def lastBuildName(self) -> str:
@@ -297,7 +297,7 @@ class BuildSettings:
if isinstance(path, Path) and path.is_dir():
self._path = path
else:
self._path = Path.home()
self._path = CONFIG.homePath()
self._changed = True
return
@@ -382,7 +382,7 @@ class BuildSettings:
postponed = []
def allowRoot(rHandle):
def allowRoot(rHandle: str | None) -> None:
if rHandle in postponed and rHandle in result and rHandle is not None:
result[rHandle] = (True, FilterMode.ROOT)
postponed.remove(rHandle)
+1 -1
View File
@@ -104,7 +104,7 @@ class DocMerger:
docText = self._project.storage.getDocumentText(srcHandle).rstrip("\n")
if addComment:
docInfo = srcItem.describeMe()
docSt, _ = srcItem.getImportStatus(incIcon=False)
docSt, _ = srcItem.getImportStatus()
cmtLine = f"% {cmtPrefix} {docInfo}: {srcItem.itemName} [{docSt}]\n\n"
docText = cmtLine + docText
+2 -2
View File
@@ -306,8 +306,8 @@ class NWBuildDocument:
self._build.getBool("headings.hideScene")
)
bldObj.setHardSceneFormat(
self._build.getStr("headings.fmtHardScene"),
self._build.getBool("headings.hideHardScene")
self._build.getStr("headings.fmtAltScene"),
self._build.getBool("headings.hideAltScene")
)
bldObj.setSectionFormat(
self._build.getStr("headings.fmtSection"),
+5 -15
View File
@@ -25,7 +25,7 @@ from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Any, Literal, overload
from typing import TYPE_CHECKING, Any
from PyQt5.QtGui import QIcon
@@ -308,25 +308,15 @@ class NWItem:
return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, ""))
@overload # pragma: no cover
def getImportStatus(self, incIcon: Literal[True] = True) -> tuple[str, QIcon]:
pass
@overload # pragma: no cover
def getImportStatus(self, incIcon: Literal[False]) -> tuple[str, None]:
pass
def getImportStatus(self, incIcon=True):
def getImportStatus(self) -> tuple[str, QIcon]:
"""Return the relevant importance or status label and icon for
the current item based on its class.
"""
if self.isNovelLike():
stName = self._project.data.itemStatus.name(self._status)
stIcon = self._project.data.itemStatus.icon(self._status) if incIcon else None
entry = self._project.data.itemStatus[self._status]
else:
stName = self._project.data.itemImport.name(self._import)
stIcon = self._project.data.itemImport.icon(self._import) if incIcon else None
return stName, stIcon
entry = self._project.data.itemImport[self._import]
return entry.name, entry.icon
##
# Checker Methods
+21 -52
View File
@@ -26,33 +26,32 @@ from __future__ import annotations
import json
import logging
from collections.abc import Iterable
from enum import Enum
from functools import partial
from pathlib import Path
from time import time
from typing import TYPE_CHECKING
from pathlib import Path
from functools import partial
from collections.abc import Iterable
from PyQt5.QtCore import QCoreApplication
from novelwriter import CONFIG, SHARED, __version__, __hexversion__
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout
from novelwriter.error import logException
from novelwriter.constants import trConst, nwLabels
from novelwriter.core.tree import NWTree
from novelwriter.core.index import NWIndex
from novelwriter.core.options import OptionState
from novelwriter.core.storage import NWStorage, NWStorageOpen
from novelwriter.core.sessions import NWSessionLog
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
from novelwriter.core.projectdata import NWProjectData
from novelwriter.common import (
checkStringNone, formatInt, formatTimeStamp, getFileSize, hexToInt, makeFileNameSafe, minmax
)
from novelwriter.constants import trConst, nwLabels
from novelwriter.core.index import NWIndex
from novelwriter.core.options import OptionState
from novelwriter.core.projectdata import NWProjectData
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
from novelwriter.core.sessions import NWSessionLog
from novelwriter.core.storage import NWStorage, NWStorageOpen
from novelwriter.core.tree import NWTree
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout
from novelwriter.error import logException
if TYPE_CHECKING: # pragma: no cover
from novelwriter.core.item import NWItem
from novelwriter.core.status import NWStatus
logger = logging.getLogger(__name__)
@@ -461,14 +460,14 @@ class NWProject:
def setDefaultStatusImport(self) -> None:
"""Set the default status and importance values."""
self._data.itemStatus.write(None, self.tr("New"), (100, 100, 100))
self._data.itemStatus.write(None, self.tr("Note"), (200, 50, 0))
self._data.itemStatus.write(None, self.tr("Draft"), (200, 150, 0))
self._data.itemStatus.write(None, self.tr("Finished"), (50, 200, 0))
self._data.itemImport.write(None, self.tr("New"), (100, 100, 100))
self._data.itemImport.write(None, self.tr("Minor"), (200, 50, 0))
self._data.itemImport.write(None, self.tr("Major"), (200, 150, 0))
self._data.itemImport.write(None, self.tr("Main"), (50, 200, 0))
self._data.itemStatus.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
self._data.itemStatus.add(None, self.tr("Note"), (200, 50, 0), "SQUARE", 0)
self._data.itemStatus.add(None, self.tr("Draft"), (200, 150, 0), "SQUARE", 0)
self._data.itemStatus.add(None, self.tr("Finished"), (50, 200, 0), "SQUARE", 0)
self._data.itemImport.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
self._data.itemImport.add(None, self.tr("Minor"), (200, 50, 0), "SQUARE", 0)
self._data.itemImport.add(None, self.tr("Major"), (200, 150, 0), "SQUARE", 0)
self._data.itemImport.add(None, self.tr("Main"), (50, 200, 0), "SQUARE", 0)
return
def setProjectLang(self, language: str | None) -> None:
@@ -491,14 +490,6 @@ class NWProject:
self.setProjectChanged(True)
return
def setStatusColours(self, new: list[dict], deleted: list[str]) -> bool:
"""Update the list of novel file status flags."""
return self._setStatusImport(new, deleted, self._data.itemStatus)
def setImportColours(self, new: list[dict], deleted: list[str]) -> bool:
"""Update the list of note file importance flags."""
return self._setStatusImport(new, deleted, self._data.itemImport)
def setProjectChanged(self, status: bool) -> bool:
"""Toggle the project changed flag, and propagate the
information to the GUI statusbar.
@@ -584,28 +575,6 @@ class NWProject:
# Internal Functions
##
def _setStatusImport(self, new: list[dict], delete: list[str], target: NWStatus) -> bool:
"""Update the list of novel file status or importance flags, and
delete those that have been requested deleted.
"""
if not (new or delete):
return False
order = []
for entry in new:
key = entry.get("key", None)
name = entry.get("name", "")
cols = entry.get("cols", (100, 100, 100))
if name:
order.append(target.write(key, name, cols))
for key in delete:
target.remove(key)
target.reorder(order)
return True
def _loadProjectLocalisation(self) -> bool:
"""Load the language data for the current project language."""
if self._data.language is None or CONFIG._nwLangPath is None:
+10 -7
View File
@@ -46,7 +46,7 @@ if TYPE_CHECKING: # pragma: no cover
logger = logging.getLogger(__name__)
FILE_VERSION = "1.5" # The current project file format version
FILE_REVISION = "3" # The current project file format revision
FILE_REVISION = "4" # The current project file format revision
HEX_VERSION = 0x0105
NUM_VERSION = {
@@ -109,6 +109,8 @@ class ProjectXMLReader:
Rev 2: Drops the title node from project and adds the TEMPLATE
class for items. 2.3 Beta 1.
Rev 3: Added TEMPLATE class. 2.3.
Rev 4: Added shape attribute to status and importance entry
nodes. 2.5.
"""
def __init__(self, path: str | Path) -> None:
@@ -356,8 +358,8 @@ class ProjectXMLReader:
logger.debug("Parsing <content> section (legacy format)")
# Create maps to look up name -> key for status and importance
statusMap = {entry.get("name"): key for key, entry in data.itemStatus.items()}
importMap = {entry.get("name"): key for key, entry in data.itemImport.items()}
sMap: dict[str | None, str] = {e.name: k for k, e in data.itemStatus.iterItems()}
iMap: dict[str | None, str] = {e.name: k for k, e in data.itemImport.iterItems()}
for xItem in xSection:
if xItem.tag != "item":
@@ -404,9 +406,9 @@ class ProjectXMLReader:
# Status was split into separate status/import with a key in 1.4
if item.get("class", "") in ("NOVEL", "ARCHIVE"):
name["status"] = statusMap.get(tmpStatus, None)
name["status"] = sMap.get(tmpStatus, None)
else:
name["import"] = importMap.get(tmpStatus, None)
name["import"] = iMap.get(tmpStatus, None)
# A number of layouts were removed in 1.3
if item.get("layout", "") in (
@@ -436,7 +438,8 @@ class ProjectXMLReader:
green = checkInt(xEntry.attrib.get("green", 0), 0)
blue = checkInt(xEntry.attrib.get("blue", 0), 0)
count = checkInt(xEntry.attrib.get("count", 0), 0)
sObject.write(key, xEntry.text or "", (red, green, blue), count)
shape = xEntry.attrib.get("shape", "")
sObject.add(key, xEntry.text or "", (red, green, blue), shape, count)
return
def _parseDictKeyText(self, xItem: ET.Element) -> dict:
@@ -449,7 +452,7 @@ class ProjectXMLReader:
result[xEntry.attrib["key"]] = checkString(xEntry.text, "")
return result
def _parseDictTagText(self, xItem) -> dict:
def _parseDictTagText(self, xItem: ET.Element) -> dict:
"""Parse a dictionary stored with key as the tag and the value
as the text property.
"""
+3 -3
View File
@@ -74,7 +74,7 @@ class NWSpellEnchant:
# Setters
##
def setLanguage(self, language: str | None):
def setLanguage(self, language: str | None) -> None:
"""Load a dictionary for the language specified in the config.
If that fails, we load a mock dictionary so that lookups don't
crash. Note that enchant will allow loading an empty string as
@@ -182,10 +182,10 @@ class FakeEnchant:
def check(self, word: str) -> bool:
return True
def suggest(self, word) -> list[str]:
def suggest(self, word: str) -> list[str]:
return []
def add_to_session(self, word: str):
def add_to_session(self, word: str) -> None:
return
# END Class FakeEnchant
+222 -169
View File
@@ -24,17 +24,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import random
import dataclasses
import logging
import random
from typing import TYPE_CHECKING, Literal
from collections.abc import ItemsView, Iterable, Iterator, KeysView, ValuesView
from collections.abc import Iterable
from typing import TYPE_CHECKING
from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor
from PyQt5.QtCore import QRectF
from PyQt5.QtCore import QPointF, Qt
from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor, QPolygonF
from novelwriter import CONFIG
from novelwriter.common import minmax, simplified
from novelwriter import SHARED
from novelwriter.common import simplified
from novelwriter.enum import nwStatusShape
from novelwriter.types import QtPaintAnitAlias, QtTransparent
if TYPE_CHECKING: # pragma: no cover
@@ -43,83 +45,94 @@ if TYPE_CHECKING: # pragma: no cover
logger = logging.getLogger(__name__)
@dataclasses.dataclass
class StatusEntry:
name: str
color: QColor
shape: nwStatusShape
icon: QIcon
count: int = 0
@classmethod
def duplicate(cls, source: StatusEntry) -> StatusEntry:
"""Create a deep copy of the source object."""
cls = dataclasses.replace(source)
cls.color = QColor(source.color)
cls.icon = QIcon(source.icon)
return cls
# END Class StatusEntry
NO_ENTRY = StatusEntry("", QColor(0, 0, 0), nwStatusShape.SQUARE, QIcon(), 0)
class NWStatus:
STATUS = 1
IMPORT = 2
STATUS = "s"
IMPORT = "i"
def __init__(self, kind: Literal[1, 2]) -> None:
__slots__ = ("_store", "_default", "_prefix", "_height")
self._type = kind
self._store = {}
def __init__(self, prefix: str) -> None:
self._store: dict[str, StatusEntry] = {}
self._default = None
self._iPX = CONFIG.pxInt(24)
pA = CONFIG.pxInt(2)
pB = CONFIG.pxInt(20)
pR = float(CONFIG.pxInt(4))
self._iconPath = QPainterPath()
self._iconPath.addRoundedRect(QRectF(pA, pA, pB, pB), pR, pR)
self._defaultIcon = self._createIcon(100, 100, 100)
if self._type == self.STATUS:
self._prefix = "s"
elif self._type == self.IMPORT:
self._prefix = "i"
else:
raise Exception("This is a bug!")
self._prefix = prefix[:1]
self._height = SHARED.theme.baseIconHeight
return
def write(self, key: str | None, name: str, col: tuple, count: int | None = None) -> str:
def __len__(self) -> int:
return len(self._store)
def __getitem__(self, key: str | None) -> StatusEntry:
"""Return the entry associated with a given key."""
if key and key in self._store:
return self._store[key]
elif self._default is not None:
return self._store[self._default]
return NO_ENTRY
##
# Methods
##
def add(self, key: str | None, name: str, color: tuple[int, int, int],
shape: str, count: int) -> str:
"""Add or update a status entry. If the key is invalid, a new
key is generated.
"""
if not self._isKey(key):
key = self._newKey()
if not isinstance(col, tuple):
col = (100, 100, 100)
if len(col) != 3:
col = (100, 100, 100)
if isinstance(color, tuple) and len(color) == 3:
qColor = QColor(*color)
else:
qColor = QColor(100, 100, 100)
cR = minmax(col[0], 0, 255)
cG = minmax(col[1], 0, 255)
cB = minmax(col[2], 0, 255)
try:
iShape = nwStatusShape[shape]
except KeyError:
iShape = nwStatusShape.SQUARE
key = self._checkKey(key)
name = simplified(name)
if count is None:
count = self._store.get(key, {}).get("count", 0)
self._store[key] = {
"name": name,
"icon": self._createIcon(cR, cG, cB),
"cols": (cR, cG, cB),
"count": count,
}
icon = self.createIcon(self._height, qColor, iShape)
self._store[key] = StatusEntry(name, qColor, iShape, icon, count)
if self._default is None:
self._default = key
return key
def remove(self, key: str) -> bool:
"""Remove an entry in the list, except if the count > 0."""
if key not in self._store:
return False
if self._store[key]["count"] > 0:
return False
def update(self, update: list[tuple[str | None, StatusEntry]]) -> None:
"""Update the list of statuses, and from removed list."""
self._store.clear()
for key, entry in update:
self._store[self._checkKey(key)] = entry
del self._store[key]
# Check if we need a new default
if self._default not in self._store:
self._default = next(iter(self._store)) if self._store else None
keys = list(self._store.keys())
if key == self._default:
if len(keys) > 0:
self._default = keys[0]
else:
self._default = None
return True
return
def check(self, value: str) -> str:
"""Check the key against the stored status names."""
@@ -129,93 +142,51 @@ class NWStatus:
return self._default
return ""
def name(self, key: str | None) -> str:
"""Return the name associated with a given key."""
if key and key in self._store:
return self._store[key]["name"]
elif self._default is not None:
return self._store[self._default]["name"]
return ""
def cols(self, key: str | None) -> tuple[int, int, int]:
"""Return the colours associated with a given key."""
if key and key in self._store:
return self._store[key]["cols"]
elif self._default is not None:
return self._store[self._default]["cols"]
return 100, 100, 100
def count(self, key: str | None) -> int:
"""Return the count associated with a given key."""
if key and key in self._store:
return self._store[key]["count"]
elif self._default is not None:
return self._store[self._default]["count"]
return 0
def icon(self, key: str | None) -> QIcon:
"""Return the icon associated with a given key."""
if key and key in self._store:
return self._store[key]["icon"]
elif self._default is not None:
return self._store[self._default]["icon"]
return self._defaultIcon
def reorder(self, order: list[str]) -> bool:
"""Reorder the items according to list."""
if len(order) != len(self._store):
logger.error("Length mismatch between new and old order")
return False
if order == list(self._store.keys()):
return False
store = {}
for key in order:
if key in self._store:
store[key] = self._store[key]
else:
logger.error("Unknown key '%s' in order", key)
return False
self._store = store
return True
def resetCounts(self) -> None:
"""Clear the counts of references to the status entries."""
for key in self._store:
self._store[key]["count"] = 0
for entry in self._store.values():
entry.count = 0
return
def increment(self, key: str | None) -> None:
"""Increment the counter for a given entry."""
if key and key in self._store:
self._store[key]["count"] += 1
self._store[key].count += 1
return
def pack(self) -> Iterable[tuple[str, dict]]:
"""Pack the status entries into a dictionary."""
for key, data in self._store.items():
yield (data["name"], {
for key, entry in self._store.items():
yield (entry.name, {
"key": key,
"count": str(data["count"]),
"red": str(data["cols"][0]),
"green": str(data["cols"][1]),
"blue": str(data["cols"][2]),
"count": str(entry.count),
"red": str(entry.color.red()),
"green": str(entry.color.green()),
"blue": str(entry.color.blue()),
"shape": entry.shape.name,
})
return
def unpack(self, data: dict) -> None:
"""Unpack a data dictionary and set the class values."""
self._store = {}
self._default = None
for key, entry in data.items():
label = entry.get("label", "")
colour = entry.get("colour", (100, 100, 100))
count = entry.get("count", 0)
self.write(key, label, colour, count)
return
def iterItems(self) -> Iterable[tuple[str, StatusEntry]]:
"""Yield entries from the status icons."""
yield from self._store.items()
@staticmethod
def createIcon(height: int, color: QColor, shape: nwStatusShape) -> QIcon:
"""Generate an icon for a status label."""
pixmap = QPixmap(48, 48)
pixmap.fill(QtTransparent)
painter = QPainter(pixmap)
painter.setRenderHint(QtPaintAnitAlias)
painter.fillPath(_SHAPES.getShape(shape), color)
painter.end()
return QIcon(pixmap.scaled(
height, height,
Qt.AspectRatioMode.IgnoreAspectRatio,
Qt.TransformationMode.SmoothTransformation
))
##
# Internal Functions
@@ -246,38 +217,120 @@ class NWStatus:
return False
return True
def _createIcon(self, red: int, green: int, blue: int) -> QIcon:
"""Generate an icon for a status label."""
pixmap = QPixmap(self._iPX, self._iPX)
pixmap.fill(QtTransparent)
painter = QPainter(pixmap)
painter.setRenderHint(QtPaintAnitAlias)
painter.fillPath(self._iconPath, QColor(red, green, blue))
painter.end()
return QIcon(pixmap)
##
# Iterator Bits
##
def __len__(self) -> int:
return len(self._store)
def __getitem__(self, key: str) -> dict:
return self._store[key]
def __iter__(self) -> Iterator[dict]:
return iter(self._store)
def keys(self) -> KeysView[str]:
return self._store.keys()
def items(self) -> ItemsView[str, dict]:
return self._store.items()
def values(self) -> ValuesView[dict]:
return self._store.values()
def _checkKey(self, key: str | None) -> str:
"""Check key is valid, and if not, generate one."""
return key if self._isKey(key) else self._newKey()
# END Class NWStatus
class _ShapeCache:
def __init__(self) -> None:
self._cache: dict[nwStatusShape, QPainterPath] = {}
return
def getShape(self, shape: nwStatusShape) -> QPainterPath:
"""Return a painter shape for an icon."""
if shape in self._cache:
return self._cache[shape]
path = QPainterPath()
if shape == nwStatusShape.SQUARE:
path.addRoundedRect(2.0, 2.0, 44.0, 44.0, 4.0, 4.0)
elif shape == nwStatusShape.TRIANGLE:
path.addPolygon(QPolygonF([
QPointF(24.00, 3.00),
QPointF(43.92, 37.50),
QPointF(4.08, 37.50),
]))
elif shape == nwStatusShape.NABLA:
path.addPolygon(QPolygonF([
QPointF(24.00, 48.00),
QPointF(4.08, 14.50),
QPointF(43.92, 14.50),
]))
elif shape == nwStatusShape.DIAMOND:
path.addPolygon(QPolygonF([
QPointF(24.00, 2.00),
QPointF(44.00, 24.00),
QPointF(24.00, 46.00),
QPointF(4.00, 24.00),
]))
elif shape == nwStatusShape.PENTAGON:
path.addPolygon(QPolygonF([
QPointF(24.00, 1.50),
QPointF(45.87, 17.39),
QPointF(37.52, 43.11),
QPointF(10.48, 43.11),
QPointF(2.13, 17.39),
]))
elif shape == nwStatusShape.HEXAGON:
path.addPolygon(QPolygonF([
QPointF(24.00, 1.50),
QPointF(43.92, 13.00),
QPointF(43.92, 36.00),
QPointF(24.00, 47.50),
QPointF(4.08, 36.00),
QPointF(4.08, 13.00),
]))
elif shape == nwStatusShape.STAR:
path.addPolygon(QPolygonF([
QPointF(24.00, 0.50), QPointF(31.05, 14.79),
QPointF(46.83, 17.08), QPointF(35.41, 28.21),
QPointF(38.11, 43.92), QPointF(24.00, 36.50),
QPointF(9.89, 43.92), QPointF(12.59, 28.21),
QPointF(1.17, 17.08), QPointF(15.37, 16.16),
]))
elif shape == nwStatusShape.PACMAN:
path.moveTo(24.0, 24.0)
path.arcTo(2.0, 2.0, 44.0, 44.0, 40.0, 280.0)
elif shape == nwStatusShape.CIRCLE_Q:
path.moveTo(24.0, 24.0)
path.arcTo(2.0, 2.0, 44.0, 44.0, 0.0, 90.0)
elif shape == nwStatusShape.CIRCLE_H:
path.moveTo(24.0, 24.0)
path.arcTo(2.0, 2.0, 44.0, 44.0, -90.0, 180.0)
elif shape == nwStatusShape.CIRCLE_T:
path.moveTo(24.0, 24.0)
path.arcTo(2.0, 2.0, 44.0, 44.0, -180.0, 270.0)
elif shape == nwStatusShape.CIRCLE:
path.addEllipse(2.0, 2.0, 44.0, 44.0)
elif shape == nwStatusShape.BARS_1:
path.addRoundedRect(2.0, 2.0, 8.0, 44.0, 4.0, 4.0)
elif shape == nwStatusShape.BARS_2:
path.addRoundedRect(2.0, 2.0, 8.0, 44.0, 4.0, 4.0)
path.addRoundedRect(14.0, 2.0, 8.0, 44.0, 4.0, 4.0)
elif shape == nwStatusShape.BARS_3:
path.addRoundedRect(2.0, 2.0, 8.0, 44.0, 4.0, 4.0)
path.addRoundedRect(14.0, 2.0, 8.0, 44.0, 4.0, 4.0)
path.addRoundedRect(26.0, 2.0, 8.0, 44.0, 4.0, 4.0)
elif shape == nwStatusShape.BARS_4:
path.addRoundedRect(2.0, 2.0, 8.0, 44.0, 4.0, 4.0)
path.addRoundedRect(14.0, 2.0, 8.0, 44.0, 4.0, 4.0)
path.addRoundedRect(26.0, 2.0, 8.0, 44.0, 4.0, 4.0)
path.addRoundedRect(38.0, 2.0, 8.0, 44.0, 4.0, 4.0)
elif shape == nwStatusShape.BLOCK_1:
path.addRoundedRect(2.0, 2.0, 20.0, 20.0, 4.0, 4.0)
elif shape == nwStatusShape.BLOCK_2:
path.addRoundedRect(2.0, 2.0, 20.0, 20.0, 4.0, 4.0)
path.addRoundedRect(24.0, 2.0, 20.0, 20.0, 4.0, 4.0)
elif shape == nwStatusShape.BLOCK_3:
path.addRoundedRect(2.0, 2.0, 20.0, 20.0, 4.0, 4.0)
path.addRoundedRect(2.0, 24.0, 20.0, 20.0, 4.0, 4.0)
path.addRoundedRect(24.0, 2.0, 20.0, 20.0, 4.0, 4.0)
elif shape == nwStatusShape.BLOCK_4:
path.addRoundedRect(2.0, 2.0, 20.0, 20.0, 4.0, 4.0)
path.addRoundedRect(2.0, 24.0, 20.0, 20.0, 4.0, 4.0)
path.addRoundedRect(24.0, 2.0, 20.0, 20.0, 4.0, 4.0)
path.addRoundedRect(24.0, 24.0, 20.0, 20.0, 4.0, 4.0)
self._cache[shape] = path
return path
# END Class _ShapeCache
# Create Singleton
_SHAPES = _ShapeCache()
+3 -3
View File
@@ -49,7 +49,7 @@ ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""
RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
def stripEscape(text) -> str:
def stripEscape(text: str) -> str:
"""Strip escaped Markdown characters from paragraph text."""
if "\\" in text:
return RX_ESC.sub(lambda x: ESCAPES[x.group(0)], text)
@@ -639,8 +639,8 @@ class Tokenizer(ABC):
tmpMarkdown.append(f"{aLine}\n")
elif aLine.startswith(("### ", "###! ")):
# (Hard) Scene Headings
# =====================
# (Alternative) Scene Headings
# ============================
# Scene headings in novel documents are treated as centred
# separators if the formatting does not change the text. If the
# format is empty, the scene can be hidden or a blank paragraph
+1 -1
View File
@@ -548,7 +548,7 @@ class ToOdt(Tokenizer):
oVers = _mkTag("office", "version")
xSett = ET.Element(oRoot, attrib={oVers: X_VERS})
def putInZip(name, xObj, zipObj):
def putInZip(name: str, xObj: ET.Element, zipObj: ZipFile) -> None:
with zipObj.open(name, mode="w") as fObj:
xml = ET.ElementTree(xObj)
xml.write(fObj, encoding="utf-8", xml_declaration=True)
+1 -1
View File
@@ -795,7 +795,7 @@ class GuiPreferences(QDialog):
return
@pyqtSlot()
def _selectTextFont(self):
def _selectTextFont(self) -> None:
"""Open the QFontDialog and set a font for the font style."""
current = QFont()
current.setFamily(CONFIG.textFont)
+219 -175
View File
@@ -27,20 +27,26 @@ from __future__ import annotations
import logging
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap
from PyQt5.QtGui import QCloseEvent, QColor
from PyQt5.QtWidgets import (
QApplication, QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout,
QLineEdit, QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem,
QVBoxLayout, QWidget
QAbstractItemView, QApplication, QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout,
QLineEdit, QMenu, QStackedWidget, QToolButton, QTreeWidget,
QTreeWidgetItem, QVBoxLayout, QWidget
)
from novelwriter import CONFIG, SHARED
from novelwriter.common import simplified
from novelwriter.constants import nwLabels, trConst
from novelwriter.core.status import NWStatus, StatusEntry
from novelwriter.enum import nwStatusShape
from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollableForm
from novelwriter.extensions.modified import NComboBox, NIconToolButton
from novelwriter.extensions.pagedsidebar import NPagedSideBar
from novelwriter.extensions.switch import NSwitch
from novelwriter.types import QtDialogCancel, QtDialogSave, QtUserRole
from novelwriter.types import (
QtDialogCancel, QtDialogSave, QtSizeMinimum, QtSizeMinimumExpanding,
QtUserRole
)
logger = logging.getLogger(__name__)
@@ -179,19 +185,19 @@ class GuiProjectSettings(QDialog):
rebuildTrees = False
if self.statusPage.wasChanged:
newList, delList = self.statusPage.getNewList()
project.setStatusColours(newList, delList)
if self.statusPage.changed:
logger.debug("Updating status labels")
project.data.itemStatus.update(self.statusPage.getNewList())
rebuildTrees = True
if self.importPage.wasChanged:
newList, delList = self.importPage.getNewList()
project.setImportColours(newList, delList)
if self.importPage.changed:
logger.debug("Updating importance labels")
project.data.itemImport.update(self.importPage.getNewList())
rebuildTrees = True
if self.replacePage.wasChanged:
newList = self.replacePage.getNewList()
project.data.setAutoReplace(newList)
if self.replacePage.changed:
logger.debug("Updating auto-replace settings")
project.data.setAutoReplace(self.replacePage.getNewList())
self.newProjectSettingsReady.emit(rebuildTrees)
QApplication.processEvents()
@@ -257,17 +263,17 @@ class _SettingsPage(NScrollableForm):
)
# Project Language
projLang = data.language or CONFIG.guiLocale
self.projLang = NComboBox(self)
self.projLang.setMinimumWidth(xW)
for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
self.projLang.addItem(language, tag)
self.projLang.setCurrentData(projLang, projLang)
self.addRow(
self.tr("Project language"), self.projLang,
self.tr("Only used when building the manuscript."),
stretch=(3, 2)
)
if (idx := self.projLang.findData(data.language)) != -1:
self.projLang.setCurrentIndex(idx)
# Spell Check Language
self.spellLang = NComboBox(self)
@@ -301,12 +307,12 @@ class _SettingsPage(NScrollableForm):
class _StatusPage(NFixedPage):
COL_LABEL = 0
COL_USAGE = 1
C_DATA = 0
C_LABEL = 0
C_USAGE = 1
KEY_ROLE = QtUserRole
COL_ROLE = QtUserRole + 1
NUM_ROLE = QtUserRole + 2
D_KEY = QtUserRole
D_ENTRY = QtUserRole + 1
def __init__(self, parent: QWidget, isStatus: bool) -> None:
super().__init__(parent=parent)
@@ -325,12 +331,21 @@ class _StatusPage(NFixedPage):
)
self._changed = False
self._colDeleted = []
self._selColour = QColor(100, 100, 100)
self._color = QColor(100, 100, 100)
self._shape = nwStatusShape.SQUARE
self._icons = {}
self.iPx = SHARED.theme.baseIconHeight
self._iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize
bSz = SHARED.theme.buttonIconSize
bPd = CONFIG.pxInt(4)
iColor = self.palette().text().color()
# Labels
self.trCountNone = self.tr("Not in use")
self.trCountOne = self.tr("Used once")
self.trCountMore = self.tr("Used by {0} items")
self.trSelColor = self.tr("Select Colour")
# Title
self.pageTitle = NColourLabel(
@@ -341,12 +356,14 @@ class _StatusPage(NFixedPage):
# List Box
self.listBox = QTreeWidget(self)
self.listBox.setHeaderLabels([self.tr("Label"), self.tr("Usage")])
self.listBox.itemSelectionChanged.connect(self._selectedItem)
self.listBox.setColumnWidth(self.COL_LABEL, wCol0)
self.listBox.setColumnWidth(self.C_LABEL, wCol0)
self.listBox.setIndentation(0)
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.listBox.itemSelectionChanged.connect(self._selectionChanged)
for key, entry in status.items():
self._addItem(key, entry["name"], entry["cols"], entry["count"])
for key, entry in status.iterItems():
self._addItem(key, StatusEntry.duplicate(entry))
# List Controls
self.addButton = NIconToolButton(self, iSz, "add")
@@ -367,16 +384,43 @@ class _StatusPage(NFixedPage):
self.editName.setPlaceholderText(self.tr("Select item to edit"))
self.editName.setEnabled(False)
self.colPixmap = QPixmap(self.iPx, self.iPx)
self.colPixmap.fill(QColor(100, 100, 100))
self.colButton = QPushButton(QIcon(self.colPixmap), self.tr("Colour"), self)
self.colButton.setIconSize(bSz)
self.colButton.setEnabled(False)
self.colButton.clicked.connect(self._selectColour)
buttonStyle = (
f"QToolButton {{padding: 0 {bPd}px;}} "
"QToolButton::menu-indicator {image: none;}"
)
self.saveButton = QPushButton(self.tr("Save"), self)
self.saveButton.setEnabled(False)
self.saveButton.clicked.connect(self._saveItem)
self.colorButton = NIconToolButton(self, iSz)
self.colorButton.setToolTip(self.tr("Colour"))
self.colorButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
self.colorButton.setStyleSheet(buttonStyle)
self.colorButton.setEnabled(False)
self.colorButton.clicked.connect(self._selectColour)
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))
self._icons[shape] = icon
self.shapeMenu = QMenu(self)
buildMenu(self.shapeMenu, nwLabels.SHAPES_PLAIN)
buildMenu(self.shapeMenu.addMenu(self.tr("Circles ...")), nwLabels.SHAPES_CIRCLE)
buildMenu(self.shapeMenu.addMenu(self.tr("Bars ...")), nwLabels.SHAPES_BARS)
buildMenu(self.shapeMenu.addMenu(self.tr("Blocks ...")), nwLabels.SHAPES_BLOCKS)
self.shapeButton = NIconToolButton(self, iSz)
self.shapeButton.setMenu(self.shapeMenu)
self.shapeButton.setToolTip(self.tr("Shape"))
self.shapeButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
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()
@@ -387,28 +431,30 @@ class _StatusPage(NFixedPage):
self.listControls.addStretch(1)
self.editBox = QHBoxLayout()
self.editBox.addWidget(self.editName)
self.editBox.addWidget(self.colButton)
self.editBox.addWidget(self.saveButton)
self.editBox.addWidget(self.editName, 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)
self.mainBox.addLayout(self.editBox)
self.mainBox.addWidget(self.listBox, 1)
self.mainBox.addLayout(self.editBox, 0)
self.innerBox = QHBoxLayout()
self.innerBox.addLayout(self.mainBox)
self.innerBox.addLayout(self.listControls)
self.innerBox.addLayout(self.mainBox, 1)
self.innerBox.addLayout(self.listControls, 0)
self.outerBox = QVBoxLayout()
self.outerBox.addWidget(self.pageTitle)
self.outerBox.addLayout(self.innerBox)
self.outerBox.addWidget(self.pageTitle, 0)
self.outerBox.addLayout(self.innerBox, 1)
self.setCentralLayout(self.outerBox)
self._setButtonIcons()
return
@property
def wasChanged(self) -> bool:
def changed(self) -> bool:
"""The user changed these settings."""
return self._changed
@@ -416,20 +462,17 @@ class _StatusPage(NFixedPage):
# Methods
##
def getNewList(self) -> tuple[list, list]:
def getNewList(self) -> list[tuple[str | None, StatusEntry]]:
"""Return list of entries."""
if self._changed:
newList = []
update = []
for n in range(self.listBox.topLevelItemCount()):
item = self.listBox.topLevelItem(n)
if item is not None:
newList.append({
"key": item.data(self.COL_LABEL, self.KEY_ROLE),
"name": item.text(self.COL_LABEL),
"cols": item.data(self.COL_LABEL, self.COL_ROLE),
})
return newList, self._colDeleted
return [], []
if item := self.listBox.topLevelItem(n):
key = item.data(self.C_DATA, self.D_KEY)
entry = item.data(self.C_DATA, self.D_ENTRY)
update.append((key, entry))
return update
return []
def columnWidth(self) -> int:
"""Return the size of the header column."""
@@ -442,124 +485,119 @@ class _StatusPage(NFixedPage):
@pyqtSlot()
def _selectColour(self) -> None:
"""Open a dialog to select the status icon colour."""
if self._selColour is not None:
newCol = QColorDialog.getColor(
self._selColour, self, self.tr("Select Colour")
)
if newCol.isValid():
self._selColour = newCol
pixmap = QPixmap(self.iPx, self.iPx)
pixmap.fill(newCol)
self.colButton.setIcon(QIcon(pixmap))
self.colButton.setIconSize(pixmap.rect().size())
if (color := QColorDialog.getColor(self._color, self, self.trSelColor)).isValid():
self._color = color
self._setButtonIcons()
return
@pyqtSlot()
def _newItem(self) -> None:
"""Create a new status item."""
self._addItem(None, self.tr("New Item"), (100, 100, 100), 0)
color = QColor(100, 100, 100)
shape = nwStatusShape.SQUARE
icon = NWStatus.createIcon(self._iPx, color, shape)
self._addItem(None, StatusEntry(self.tr("New Item"), color, shape, icon, 0))
self._changed = True
return
@pyqtSlot()
def _delItem(self) -> None:
"""Delete a status item."""
selItem = self._getSelectedItem()
if isinstance(selItem, QTreeWidgetItem):
iRow = self.listBox.indexOfTopLevelItem(selItem)
if selItem.data(self.COL_LABEL, self.NUM_ROLE) > 0:
if item := self._getSelectedItem():
iRow = self.listBox.indexOfTopLevelItem(item)
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
if entry.count > 0:
SHARED.error(self.tr("Cannot delete a status item that is in use."))
else:
self.listBox.takeTopLevelItem(iRow)
self._colDeleted.append(selItem.data(self.COL_LABEL, self.KEY_ROLE))
self._changed = True
return
@pyqtSlot()
def _saveItem(self) -> None:
def _applyChanges(self) -> None:
"""Save changes made to a status item."""
selItem = self._getSelectedItem()
if isinstance(selItem, QTreeWidgetItem):
selItem.setText(self.COL_LABEL, simplified(self.editName.text()))
selItem.setIcon(self.COL_LABEL, self.colButton.icon())
selItem.setData(self.COL_LABEL, self.COL_ROLE, (
self._selColour.red(), self._selColour.green(), self._selColour.blue()
))
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 _selectedItem(self) -> None:
def _selectionChanged(self) -> None:
"""Extract the info of a selected item and populate the settings
boxes and button. If no item is selected, clear the form.
"""
selItem = self._getSelectedItem()
if isinstance(selItem, QTreeWidgetItem):
cols = selItem.data(self.COL_LABEL, self.COL_ROLE)
name = selItem.text(self.COL_LABEL)
pixmap = QPixmap(self.iPx, self.iPx)
pixmap.fill(QColor(*cols))
self._selColour = QColor(*cols)
self.editName.setText(name)
self.colButton.setIcon(QIcon(pixmap))
if item := self._getSelectedItem():
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
self._color = entry.color
self._shape = entry.shape
self._setButtonIcons()
self.editName.setText(entry.name)
self.editName.selectAll()
self.editName.setFocus()
self.editName.setEnabled(True)
self.colButton.setEnabled(True)
self.saveButton.setEnabled(True)
self.colorButton.setEnabled(True)
self.shapeButton.setEnabled(True)
self.applyButton.setEnabled(True)
else:
pixmap = QPixmap(self.iPx, self.iPx)
pixmap.fill(QColor(100, 100, 100))
self._selColour = QColor(100, 100, 100)
self._color = QColor(100, 100, 100)
self._shape = nwStatusShape.SQUARE
self._setButtonIcons()
self.editName.setText("")
self.colButton.setIcon(QIcon(pixmap))
self.editName.setEnabled(False)
self.colButton.setEnabled(False)
self.saveButton.setEnabled(False)
self.colorButton.setEnabled(False)
self.shapeButton.setEnabled(False)
self.applyButton.setEnabled(False)
return
##
# Internal Functions
##
def _addItem(self, key: str | None, name: str,
colour: tuple[int, int, int], count: int) -> None:
def _selectShape(self, shape: nwStatusShape) -> None:
"""Set the current shape."""
self._shape = shape
self._setButtonIcons()
return
def _addItem(self, key: str | None, entry: StatusEntry) -> None:
"""Add a status item to the list."""
pixmap = QPixmap(self.iPx, self.iPx)
pixmap.fill(QColor(*colour))
item = QTreeWidgetItem()
item.setText(self.COL_LABEL, name)
item.setIcon(self.COL_LABEL, QIcon(pixmap))
item.setData(self.COL_LABEL, self.KEY_ROLE, key)
item.setData(self.COL_LABEL, self.COL_ROLE, colour)
item.setData(self.COL_LABEL, self.NUM_ROLE, count)
item.setText(self.COL_USAGE, self._usageString(count))
item.setText(self.C_LABEL, entry.name)
item.setIcon(self.C_LABEL, entry.icon)
item.setText(self.C_USAGE, self._usageString(entry.count))
item.setData(self.C_DATA, self.D_KEY, key)
item.setData(self.C_DATA, self.D_ENTRY, entry)
self.listBox.addTopLevelItem(item)
return
def _moveItem(self, step: int) -> None:
"""Move and item up or down step."""
selItem = self._getSelectedItem()
if selItem is None:
return
tIndex = self.listBox.indexOfTopLevelItem(selItem)
nChild = self.listBox.topLevelItemCount()
nIndex = tIndex + step
if nIndex < 0 or nIndex >= nChild:
return
cItem = self.listBox.takeTopLevelItem(tIndex)
self.listBox.insertTopLevelItem(nIndex, cItem)
self.listBox.clearSelection()
if cItem is not None:
cItem.setSelected(True)
self._changed = True
if item := self._getSelectedItem():
tIdx = self.listBox.indexOfTopLevelItem(item)
nItm = self.listBox.topLevelItemCount()
nIdx = tIdx + step
if (0 <= nIdx < nItm) and (cItem := self.listBox.takeTopLevelItem(tIdx)):
self.listBox.insertTopLevelItem(nIdx, cItem)
self.listBox.clearSelection()
cItem.setSelected(True)
self._changed = True
return
def _getSelectedItem(self) -> QTreeWidgetItem | None:
@@ -571,19 +609,26 @@ class _StatusPage(NFixedPage):
def _usageString(self, count: int) -> str:
"""Generate usage string."""
if count == 0:
return self.tr("Not in use")
return self.trCountNone
elif count == 1:
return self.tr("Used once")
return self.trCountOne
else:
return self.tr("Used by {0} items").format(count)
return self.trCountMore.format(count)
def _setButtonIcons(self) -> None:
"""Set the colour of the colour button."""
icon = NWStatus.createIcon(self._iPx, self._color, nwStatusShape.SQUARE)
self.colorButton.setIcon(icon)
self.shapeButton.setIcon(self._icons[self._shape])
return
# END Class _StatusPage
class _ReplacePage(NFixedPage):
COL_KEY = 0
COL_REPL = 1
C_KEY = 0
C_REPL = 1
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
@@ -605,15 +650,17 @@ class _ReplacePage(NFixedPage):
# List Box
self.listBox = QTreeWidget(self)
self.listBox.setHeaderLabels([self.tr("Keyword"), self.tr("Replace With")])
self.listBox.setColumnWidth(self.COL_KEY, wCol0)
self.listBox.setColumnWidth(self.C_KEY, wCol0)
self.listBox.setIndentation(0)
self.listBox.itemSelectionChanged.connect(self._selectedItem)
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.listBox.itemSelectionChanged.connect(self._selectionChanged)
for aKey, aVal in SHARED.project.data.autoReplace.items():
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
self.listBox.addTopLevelItem(newItem)
self.listBox.sortByColumn(self.COL_KEY, Qt.SortOrder.AscendingOrder)
self.listBox.sortByColumn(self.C_KEY, Qt.SortOrder.AscendingOrder)
self.listBox.setSortingEnabled(True)
# List Controls
@@ -633,8 +680,10 @@ class _ReplacePage(NFixedPage):
self.editValue.setEnabled(False)
self.editValue.setMaxLength(80)
self.saveButton = QPushButton(self.tr("Save"), self)
self.saveButton.clicked.connect(self._saveEntry)
self.applyButton = QToolButton(self)
self.applyButton.setText(self.tr("Apply"))
self.applyButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
self.applyButton.clicked.connect(self._applyChanges)
# Assemble
self.listControls = QVBoxLayout()
@@ -645,11 +694,11 @@ class _ReplacePage(NFixedPage):
self.editBox = QHBoxLayout()
self.editBox.addWidget(self.editKey, 4)
self.editBox.addWidget(self.editValue, 5)
self.editBox.addWidget(self.saveButton, 0)
self.editBox.addWidget(self.applyButton, 0)
self.mainBox = QVBoxLayout()
self.mainBox.addWidget(self.listBox)
self.mainBox.addLayout(self.editBox)
self.mainBox.addWidget(self.listBox, 1)
self.mainBox.addLayout(self.editBox, 0)
self.innerBox = QHBoxLayout()
self.innerBox.addLayout(self.mainBox)
@@ -664,7 +713,7 @@ class _ReplacePage(NFixedPage):
return
@property
def wasChanged(self) -> bool:
def changed(self) -> bool:
"""The user changed these settings."""
return self._changed
@@ -672,15 +721,13 @@ class _ReplacePage(NFixedPage):
# Methods
##
def getNewList(self) -> dict:
def getNewList(self) -> dict[str, str]:
"""Extract the list from the widget."""
new = {}
for n in range(self.listBox.topLevelItemCount()):
if tItem := self.listBox.topLevelItem(n):
aKey = self._stripNotAllowed(tItem.text(0))
aVal = tItem.text(1)
if len(aKey) > 0:
new[aKey] = aVal
if item := self.listBox.topLevelItem(n):
if key := self._stripNotAllowed(item.text(self.C_KEY)):
new[key] = item.text(self.C_REPL)
return new
def columnWidth(self) -> int:
@@ -692,51 +739,48 @@ class _ReplacePage(NFixedPage):
##
@pyqtSlot()
def _selectedItem(self) -> None:
def _selectionChanged(self) -> None:
"""Extract the details from the selected item and populate the
edit form.
"""
if selItem := self._getSelectedItem():
editKey = self._stripNotAllowed(selItem.text(0))
editVal = selItem.text(1)
self.editKey.setText(editKey)
self.editValue.setText(editVal)
if item := self._getSelectedItem():
self.editKey.setText(self._stripNotAllowed(item.text(self.C_KEY)))
self.editValue.setText(item.text(self.C_REPL))
self.editKey.setEnabled(True)
self.editValue.setEnabled(True)
self.editKey.selectAll()
self.editKey.setFocus()
else:
self.editKey.setText("")
self.editValue.setText("")
self.editKey.setEnabled(False)
self.editValue.setEnabled(False)
return
@pyqtSlot()
def _saveEntry(self) -> None:
def _applyChanges(self) -> None:
"""Save the form data into the list widget."""
if selItem := self._getSelectedItem():
newKey = self.editKey.text()
newVal = self.editValue.text()
saveKey = self._stripNotAllowed(newKey)
if len(saveKey) > 0 and len(newVal) > 0:
selItem.setText(self.COL_KEY, "<%s>" % saveKey)
selItem.setText(self.COL_REPL, newVal)
self.editKey.clear()
self.editValue.clear()
self.editKey.setEnabled(False)
self.editValue.setEnabled(False)
self.listBox.clearSelection()
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:
"""Add a new list entry."""
saveKey = "<keyword%d>" % (self.listBox.topLevelItemCount() + 1)
self.listBox.addTopLevelItem(QTreeWidgetItem([saveKey, ""]))
key = f"<keyword{self.listBox.topLevelItemCount() + 1:d}>"
self.listBox.addTopLevelItem(QTreeWidgetItem([key, ""]))
return
@pyqtSlot()
def _delEntry(self) -> None:
"""Delete the selected entry."""
if selItem := self._getSelectedItem():
self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(selItem))
if item := self._getSelectedItem():
self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(item))
self._changed = True
return
+2 -2
View File
@@ -190,7 +190,7 @@ class GuiWordList(QDialog):
))
ffilter = formatFileFilter(["*.txt", "*"])
path, _ = QFileDialog.getOpenFileName(
self, self.tr("Import File"), str(Path.home()), filter=ffilter
self, self.tr("Import File"), str(CONFIG.homePath()), filter=ffilter
)
if path:
try:
@@ -207,7 +207,7 @@ class GuiWordList(QDialog):
def _exportWords(self) -> None:
"""Export words to file."""
path, _ = QFileDialog.getSaveFileName(
self, self.tr("Export File"), str(Path.home())
self, self.tr("Export File"), str(CONFIG.homePath())
)
if path:
try:
+26
View File
@@ -210,3 +210,29 @@ class nwBuildFmt(Enum):
J_NWD = 7
# END Enum nwBuildFormat
class nwStatusShape(Enum):
SQUARE = 0
TRIANGLE = 1
NABLA = 2
DIAMOND = 3
PENTAGON = 4
HEXAGON = 5
STAR = 6
PACMAN = 7
CIRCLE_Q = 8
CIRCLE_H = 9
CIRCLE_T = 10
CIRCLE = 11
BARS_1 = 12
BARS_2 = 13
BARS_3 = 14
BARS_4 = 15
BLOCK_1 = 16
BLOCK_2 = 17
BLOCK_3 = 18
BLOCK_4 = 19
# END Enum nwStatusShape
+1 -1
View File
@@ -54,7 +54,7 @@ def logException() -> None:
return
def formatException(exc) -> str:
def formatException(exc: BaseException) -> str:
"""Format an exception as a string the same way the default
exception handler does.
"""
+4 -3
View File
@@ -27,10 +27,11 @@ from math import ceil
from PyQt5.QtCore import QRect
from PyQt5.QtGui import QBrush, QColor, QPaintEvent, QPainter, QPen
from PyQt5.QtWidgets import QProgressBar, QSizePolicy, QWidget
from PyQt5.QtWidgets import QProgressBar, QWidget
from novelwriter.types import (
QtPaintAnitAlias, QtAlignCenter, QtRoundCap, QtSolidLine, QtTransparent
QtPaintAnitAlias, QtAlignCenter, QtRoundCap, QtSizeFixed, QtSolidLine,
QtTransparent
)
@@ -59,7 +60,7 @@ class NProgressCircle(QProgressBar):
bar=self.palette().highlight().color(),
text=self.palette().text().color()
)
self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
self.setSizePolicy(QtSizeFixed, QtSizeFixed)
self.setFixedWidth(size)
self.setFixedHeight(size)
return
+3 -1
View File
@@ -25,6 +25,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
from enum import Enum
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtGui import QWheelEvent
from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QToolButton, QWidget
@@ -46,7 +48,7 @@ class NComboBox(QComboBox):
event.ignore()
return
def setCurrentData(self, data: str, default: str) -> None:
def setCurrentData(self, data: str | Enum, default: str | Enum) -> None:
"""Set the current index from data, with a fallback."""
idx = self.findData(data)
self.setCurrentIndex(self.findData(default) if idx < 0 else idx)
+8 -5
View File
@@ -28,11 +28,14 @@ from __future__ import annotations
from PyQt5.QtGui import QColor, QPaintEvent, QPainter, QPolygon
from PyQt5.QtCore import QPoint, QRectF, QSize, Qt, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import (
QAbstractButton, QAction, QButtonGroup, QLabel, QSizePolicy, QStyle,
QAbstractButton, QAction, QButtonGroup, QLabel, QStyle,
QStyleOptionToolButton, QToolBar, QToolButton, QWidget
)
from novelwriter.types import QtPaintAnitAlias, QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen
from novelwriter.types import (
QtPaintAnitAlias, QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen,
QtSizeExpanding, QtSizeFixed
)
class NPagedSideBar(QToolBar):
@@ -59,7 +62,7 @@ class NPagedSideBar(QToolBar):
self.setOrientation(Qt.Orientation.Vertical)
stretch = QWidget(self)
stretch.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
stretch.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
self._stretchAction = self.addWidget(stretch)
return
@@ -119,7 +122,7 @@ class _NPagedToolButton(QToolButton):
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.setSizePolicy(QtSizeExpanding, QtSizeFixed)
self.setCheckable(True)
fH = self.fontMetrics().height()
@@ -197,7 +200,7 @@ class _NPagedToolLabel(QLabel):
def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None:
super().__init__(parent=parent)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.setSizePolicy(QtSizeExpanding, QtSizeFixed)
fH = self.fontMetrics().height()
self._bH = round(fH * 1.7)
+3 -3
View File
@@ -25,10 +25,10 @@ from __future__ import annotations
from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
from PyQt5.QtCore import QEvent, QPropertyAnimation, Qt, pyqtProperty
from PyQt5.QtWidgets import QAbstractButton, QSizePolicy, QWidget
from PyQt5.QtWidgets import QAbstractButton, QWidget
from novelwriter import CONFIG, SHARED
from novelwriter.types import QtPaintAnitAlias, QtMouseLeft, QtNoPen
from novelwriter.types import QtPaintAnitAlias, QtMouseLeft, QtNoPen, QtSizeFixed
class NSwitch(QAbstractButton):
@@ -46,7 +46,7 @@ class NSwitch(QAbstractButton):
self._rR = self._xR - self._rB
self.setCheckable(True)
self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
self.setSizePolicy(QtSizeFixed, QtSizeFixed)
self.setFixedWidth(self._xW)
self.setFixedHeight(self._xH)
self._offset = self._xR
+6 -3
View File
@@ -25,10 +25,13 @@ from __future__ import annotations
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QSizePolicy, QWidget
from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QWidget
from novelwriter.extensions.switch import NSwitch
from novelwriter.types import QtAlignLeft, QtAlignRight, QtAlignRightMiddle
from novelwriter.types import (
QtAlignLeft, QtAlignRight, QtAlignRightMiddle, QtSizeMinimum,
QtSizeMinimumExpanding
)
class NSwitchBox(QScrollArea):
@@ -59,7 +62,7 @@ class NSwitchBox(QScrollArea):
self._content.setColumnStretch(1, 1)
self._widget = QWidget(self)
self._widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum)
self._widget.setSizePolicy(QtSizeMinimumExpanding, QtSizeMinimum)
self._widget.setLayout(self._content)
self.setWidgetResizable(True)
+22 -20
View File
@@ -381,7 +381,7 @@ class GuiDocEditor(QPlainTextEdit):
return
def loadText(self, tHandle: str, tLine=None) -> bool:
def loadText(self, tHandle: str, tLine: int | None = None) -> bool:
"""Load text from a document into the editor. If we have an I/O
error, we must handle this and clear the editor so that we don't
risk overwriting the file if it exists. This can for instance
@@ -497,6 +497,7 @@ class GuiDocEditor(QPlainTextEdit):
return False
self.setDocumentChanged(False)
self.docTextChanged.emit(self._docHandle, self._lastEdit)
oldHeader = self._nwItem.mainHeading
oldCount = SHARED.project.index.getHandleHeaderCount(tHandle)
@@ -1080,7 +1081,7 @@ class GuiDocEditor(QPlainTextEdit):
return
@pyqtSlot()
def _cursorMoved(self):
def _cursorMoved(self) -> None:
"""Triggered when the cursor moved in the editor."""
self.docFooter.updateLineCount(self.textCursor())
return
@@ -1470,7 +1471,7 @@ class GuiDocEditor(QPlainTextEdit):
# Internal Functions : Text Manipulation
##
def _toggleFormat(self, fLen: int, fChar: str) -> bool:
def _toggleFormat(self, fLen: int, fChar: str) -> None:
"""Toggle the formatting of a specific type for a piece of text.
If more than one block is selected, the formatting is applied to
the first block.
@@ -1488,12 +1489,12 @@ class GuiDocEditor(QPlainTextEdit):
posS = cursor.selectionStart()
posE = cursor.selectionEnd()
if self._qDocument.characterAt(posO - 1) == fChar:
if posS == posE and self._qDocument.characterAt(posO - 1) == fChar:
logger.warning("Format repetition, cancelling action")
cursor.clearSelection()
cursor.setPosition(posO)
self.setTextCursor(cursor)
return False
return
blockS = self._qDocument.findBlock(posS)
blockE = self._qDocument.findBlock(posE)
@@ -1519,7 +1520,6 @@ class GuiDocEditor(QPlainTextEdit):
break
if fLen == min(numA, numB):
cursor.clearSelection()
cursor.beginEditBlock()
cursor.setPosition(posS)
for i in range(fLen):
@@ -1528,17 +1528,19 @@ class GuiDocEditor(QPlainTextEdit):
for i in range(fLen):
cursor.deletePreviousChar()
cursor.endEditBlock()
cursor.clearSelection()
cursor.setPosition(posO - fLen)
self.setTextCursor(cursor)
if select != _SelectAction.KEEP_SELECTION:
cursor.clearSelection()
cursor.setPosition(posO - fLen)
self.setTextCursor(cursor)
else:
self._wrapSelection(fChar*fLen, pos=posO, select=select)
return True
return
def _wrapSelection(self, before: str, after: str | None = None, pos: int | None = None,
select: _SelectAction = _SelectAction.NO_DECISION) -> bool:
select: _SelectAction = _SelectAction.NO_DECISION) -> None:
"""Wrap the selected text in whatever is in tBefore and tAfter.
If there is no selection, the autoSelect setting decides the
action. AutoSelect will select the word under the cursor before
@@ -1578,21 +1580,21 @@ class GuiDocEditor(QPlainTextEdit):
if select == _SelectAction.MOVE_AFTER:
cursor.setPosition(posE + len(before + after))
elif select == _SelectAction.KEEP_SELECTION:
cursor.setPosition(posE + len(before), QtMoveAnchor)
cursor.setPosition(posS + len(before), QtKeepAnchor)
cursor.setPosition(posS + len(before), QtMoveAnchor)
cursor.setPosition(posE + len(before), QtKeepAnchor)
elif select == _SelectAction.KEEP_POSITION:
cursor.setPosition(posO + len(before))
self.setTextCursor(cursor)
return True
return
def _replaceQuotes(self, sQuote: str, oQuote: str, cQuote: str) -> bool:
def _replaceQuotes(self, sQuote: str, oQuote: str, cQuote: str) -> None:
"""Replace all straight quotes in the selected text."""
cursor = self.textCursor()
if not cursor.hasSelection():
SHARED.error(self.tr("Please select some text before calling replace quotes."))
return False
return
posS = cursor.selectionStart()
posE = cursor.selectionEnd()
@@ -1632,7 +1634,7 @@ class GuiDocEditor(QPlainTextEdit):
self._allowAutoReplace(True)
return True
return
def _processBlockFormat(
self, action: nwDocAction, text: str, toggle: bool = True
@@ -2185,7 +2187,7 @@ class MetaCompleter(QMenu):
# Internal Functions
##
def _emitComplete(self, pos: int, length: int, value: str):
def _emitComplete(self, pos: int, length: int, value: str) -> None:
"""Emit the signal to indicate a selection has been made."""
self.complete.emit(pos, length, value)
return
@@ -2966,7 +2968,7 @@ class GuiDocEditHeader(QWidget):
# Events
##
def mousePressEvent(self, event: QMouseEvent):
def mousePressEvent(self, event: QMouseEvent) -> None:
"""Capture a click on the title and ensure that the item is
selected in the project tree.
"""
@@ -3134,7 +3136,7 @@ class GuiDocEditFooter(QWidget):
sText = ""
else:
iPx = round(0.9*SHARED.theme.baseIconHeight)
status, icon = self._tItem.getImportStatus(incIcon=True)
status, icon = self._tItem.getImportStatus()
sIcon = icon.pixmap(iPx, iPx)
sText = f"{status} / {self._tItem.describeMe()}"
+1 -1
View File
@@ -328,7 +328,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self.setFormat(0, 3, self._hStyles["head2h"])
self.setFormat(3, len(text), self._hStyles["header2"])
elif text.startswith("###! "): # Hard Scene
elif text.startswith("###! "): # Alternative Scene
self.setFormat(0, 4, self._hStyles["head3h"])
self.setFormat(4, len(text), self._hStyles["header3"])
+1 -1
View File
@@ -450,7 +450,7 @@ class _ViewPanelKeyWords(QTreeWidget):
nwItem.itemType, nwItem.itemClass,
nwItem.itemLayout, nwItem.mainHeading
)
impLabel, impIcon = nwItem.getImportStatus(incIcon=True)
impLabel, impIcon = nwItem.getImportStatus()
iLevel = nwHeaders.H_LEVEL.get(hItem.level, 0) if nwItem.isDocumentLayout() else 5
hDec = SHARED.theme.getHeaderDecorationNarrow(iLevel)
+1 -1
View File
@@ -253,7 +253,7 @@ class GuiItemDetails(QWidget):
# Status
# ======
status, icon = nwItem.getImportStatus(incIcon=True)
status, icon = nwItem.getImportStatus()
self.statusIcon.setPixmap(icon.pixmap(iPx, iPx))
self.statusData.setText(status)
+2 -2
View File
@@ -742,8 +742,8 @@ class GuiMainMenu(QMenuBar):
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_UNN)
)
# Format > Hard Scene
self.aFmtHardSc = self.fmtMenu.addAction(self.tr("Hard Scene"))
# Format > Alternative Scene
self.aFmtHardSc = self.fmtMenu.addAction(self.tr("Alternative Scene"))
self.aFmtHardSc.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_HSC)
)
+8 -5
View File
@@ -35,8 +35,8 @@ from PyQt5.QtCore import QModelIndex, QPoint, Qt, pyqtSlot, pyqtSignal
from PyQt5.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent
from PyQt5.QtWidgets import (
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView,
QInputDialog, QMenu, QSizePolicy, QToolTip, QTreeWidget, QTreeWidgetItem,
QVBoxLayout, QWidget
QInputDialog, QMenu, QToolTip, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
QWidget
)
from novelwriter import CONFIG, SHARED
@@ -47,7 +47,10 @@ from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
from novelwriter.extensions.modified import NIconToolButton
from novelwriter.extensions.novelselector import NovelSelector
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
from novelwriter.types import QtAlignRight, QtDecoration, QtMouseLeft, QtMouseMiddle, QtUserRole
from novelwriter.types import (
QtAlignRight, QtDecoration, QtMouseLeft, QtMouseMiddle, QtSizeExpanding,
QtUserRole
)
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
@@ -215,7 +218,7 @@ class GuiNovelToolBar(QWidget):
self.novelValue.setFont(selFont)
self.novelValue.setListFormat(self.tr("Outline of {0}"))
self.novelValue.setMinimumWidth(CONFIG.pxInt(150))
self.novelValue.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
self.novelValue.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot)
self.tbNovel = NIconToolButton(self, iSz)
@@ -344,7 +347,7 @@ class GuiNovelToolBar(QWidget):
# Internal Functions
##
def _addLastColAction(self, colType, actionLabel) -> None:
def _addLastColAction(self, colType: NovelTreeColumn, actionLabel: str) -> None:
"""Add a column selection entry to the last column menu."""
aLast = self.mLastCol.addAction(actionLabel)
aLast.setCheckable(True)
+10 -11
View File
@@ -36,20 +36,19 @@ from enum import Enum
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, QT_TRANSLATE_NOOP
from PyQt5.QtWidgets import (
QAbstractItemView, QAction, QFileDialog, QFrame, QGridLayout, QGroupBox,
QHBoxLayout, QLabel, QMenu, QScrollArea, QSizePolicy, QSplitter, QToolBar,
QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
QHBoxLayout, QLabel, QMenu, QScrollArea, QSplitter, QToolBar, QToolButton,
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
)
from novelwriter import CONFIG, SHARED
from novelwriter.enum import (
nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
)
from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
from novelwriter.error import logException
from novelwriter.common import checkInt, formatFileFilter, makeFileNameSafe
from novelwriter.constants import nwHeaders, trConst, nwKeyWords, nwLabels
from novelwriter.extensions.novelselector import NovelSelector
from novelwriter.types import (
QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration, QtUserRole
QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration,
QtSizeExpanding, QtUserRole
)
@@ -190,7 +189,7 @@ class GuiOutlineView(QWidget):
return
@pyqtSlot(str)
def _rootItemChanged(self, tHandle) -> None:
def _rootItemChanged(self, tHandle: str) -> None:
"""Handle root novel changed or needs to be refreshed."""
self.outlineTree.refreshTree(rootHandle=(tHandle or None), overRide=True)
return
@@ -217,7 +216,7 @@ class GuiOutlineToolBar(QToolBar):
self.setContentsMargins(0, 0, 0, 0)
stretch = QWidget(self)
stretch.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
stretch.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
# Novel Selector
self.novelLabel = QLabel(self.tr("Outline of"), self)
@@ -428,7 +427,7 @@ class GuiOutlineTree(QTreeWidget):
##
@property
def hiddenColumns(self):
def hiddenColumns(self) -> dict[nwOutline, bool]:
return self._colHidden
##
@@ -586,7 +585,7 @@ class GuiOutlineTree(QTreeWidget):
# Internal Functions
##
def _loadHeaderState(self):
def _loadHeaderState(self) -> None:
"""Load the state of the main tree header, that is, column order
and column width.
"""
@@ -1048,7 +1047,7 @@ class GuiOutlineDetails(QScrollArea):
self.titleLabel.setText(self.tr(self.LVL_MAP.get(novIdx.level, "H1")))
self.titleValue.setText(novIdx.title)
itemStatus, _ = nwItem.getImportStatus(incIcon=False)
itemStatus, _ = nwItem.getImportStatus()
self.fileValue.setText(nwItem.itemName)
self.itemValue.setText(itemStatus)
+15 -12
View File
@@ -38,8 +38,8 @@ from PyQt5.QtGui import (
)
from PyQt5.QtWidgets import (
QAbstractItemView, QAction, QDialog, QFrame, QHBoxLayout, QHeaderView,
QLabel, QMenu, QShortcut, QSizePolicy, QTreeWidget, QTreeWidgetItem,
QVBoxLayout, QWidget
QLabel, QMenu, QShortcut, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
QWidget
)
from novelwriter import CONFIG, SHARED
@@ -54,7 +54,10 @@ from novelwriter.dialogs.projectsettings import GuiProjectSettings
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout
from novelwriter.extensions.modified import NIconToolButton
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
from novelwriter.types import QtAlignLeft, QtAlignRight, QtMouseLeft, QtMouseMiddle, QtUserRole
from novelwriter.types import (
QtAlignLeft, QtAlignRight, QtMouseLeft, QtMouseMiddle, QtSizeExpanding,
QtUserRole,
)
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
@@ -274,7 +277,7 @@ class GuiProjectToolBar(QWidget):
self.viewLabel = QLabel(self.tr("Project Content"), self)
self.viewLabel.setFont(SHARED.theme.guiFontB)
self.viewLabel.setContentsMargins(0, 0, 0, 0)
self.viewLabel.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
self.viewLabel.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
# Quick Links
self.mQuick = QMenu(self)
@@ -453,7 +456,7 @@ class GuiProjectToolBar(QWidget):
def _buildRootMenu(self) -> None:
"""Build the rood folder menu."""
def addClass(itemClass):
def addClass(itemClass: nwItemClass) -> None:
aNew = self.mAddRoot.addAction(trConst(nwLabels.CLASS_NAME[itemClass]))
aNew.setIcon(SHARED.theme.getIcon(nwLabels.CLASS_ICON[itemClass]))
aNew.triggered.connect(lambda: self.projTree.newTreeItem(nwItemType.ROOT, itemClass))
@@ -1033,7 +1036,7 @@ class GuiProjectTree(QTreeWidget):
if trItem is None or nwItem is None:
return
itemStatus, statusIcon = nwItem.getImportStatus(incIcon=True)
itemStatus, statusIcon = nwItem.getImportStatus()
hLevel = nwItem.mainHeading
itemIcon = SHARED.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
@@ -1855,11 +1858,11 @@ class _TreeContextMenu(QMenu):
if self._item.isNovelLike():
menu = self.addMenu(self.tr("Set Status to ..."))
current = self._item.itemStatus
for n, (key, entry) in enumerate(SHARED.project.data.itemStatus.items()):
name = entry["name"]
for n, (key, entry) in enumerate(SHARED.project.data.itemStatus.iterItems()):
name = entry.name
if not multi and current == key:
name += f" ({nwUnicode.U_CHECK})"
action = menu.addAction(entry["icon"], name)
action = menu.addAction(entry.icon, name)
if multi:
action.triggered.connect(lambda n, key=key: self._iterSetItemStatus(key))
else:
@@ -1872,11 +1875,11 @@ class _TreeContextMenu(QMenu):
else:
menu = self.addMenu(self.tr("Set Importance to ..."))
current = self._item.itemImport
for n, (key, entry) in enumerate(SHARED.project.data.itemImport.items()):
name = entry["name"]
for n, (key, entry) in enumerate(SHARED.project.data.itemImport.iterItems()):
name = entry.name
if not multi and current == key:
name += f" ({nwUnicode.U_CHECK})"
action = menu.addAction(entry["icon"], name)
action = menu.addAction(entry.icon, name)
if multi:
action.triggered.connect(lambda n, key=key: self._iterSetItemImport(key))
else:
+15 -5
View File
@@ -74,9 +74,9 @@ class GuiTheme:
self.isLightTheme = True
# GUI
self.statNone = QColor(120, 120, 120)
self.statUnsaved = QColor(200, 15, 39)
self.statSaved = QColor(2, 133, 37)
self.statNone = QColor(0, 0, 0)
self.statUnsaved = QColor(0, 0, 0)
self.statSaved = QColor(0, 0, 0)
self.helpText = QColor(0, 0, 0)
# Loaded Syntax Settings
@@ -227,6 +227,10 @@ class GuiTheme:
logException()
return False
# Reset Palette
self._guiPalette = QApplication.style().standardPalette()
self._resetGuiColors()
# Main
sec = "Main"
if parser.has_section(sec):
@@ -256,8 +260,6 @@ class GuiTheme:
self._setPalette(parser, sec, "highlightedtext", QPalette.ColorRole.HighlightedText)
self._setPalette(parser, sec, "link", QPalette.ColorRole.Link)
self._setPalette(parser, sec, "linkvisited", QPalette.ColorRole.LinkVisited)
else:
self._guiPalette = QApplication.style().standardPalette()
# GUI
sec = "GUI"
@@ -393,6 +395,14 @@ class GuiTheme:
# Internal Functions
##
def _resetGuiColors(self) -> None:
"""Reset GUI colours to default values."""
self.statNone = QColor(120, 120, 120)
self.statUnsaved = QColor(200, 15, 39)
self.statSaved = QColor(2, 133, 37)
self.helpText = QColor(0, 0, 0)
return
def _setGuiFont(self) -> None:
"""Update the GUI's font style from settings."""
font = QFont()
+2 -2
View File
@@ -944,7 +944,7 @@ class GuiMain(QMainWindow):
# Events
##
def closeEvent(self, event: QCloseEvent):
def closeEvent(self, event: QCloseEvent) -> None:
"""Capture the closing event of the GUI and call the close
function to handle all the close process steps.
"""
@@ -1201,7 +1201,7 @@ class GuiMain(QMainWindow):
return
@pyqtSlot()
def _toggleViewerPanelVisibility(self):
def _toggleViewerPanelVisibility(self) -> None:
"""Toggle the visibility of the document viewer panel."""
CONFIG.showViewerPanel = not CONFIG.showViewerPanel
self.docViewerPanel.setVisible(CONFIG.showViewerPanel)
+1
View File
@@ -57,6 +57,7 @@ def preProcessText(text: str, keepHeaders: bool = True) -> list[str]:
continue
if line[0] == ">":
line = line.lstrip(">").lstrip(" ")
if line: # Above block can return empty line (Issue #1816)
if line[-1] == "<":
line = line.rstrip("<").rstrip(" ")
if "[" in line:
+2 -2
View File
@@ -179,7 +179,7 @@ class GuiDictionaries(QDialog):
##
@pyqtSlot()
def _doBrowseHunspell(self):
def _doBrowseHunspell(self) -> None:
"""Browse for a Free/Libre Office dictionary."""
ffilter = formatFileFilter([
(self.tr("Free or Libre Office extension"), "*.sox *.oxt"), "*"
@@ -193,7 +193,7 @@ class GuiDictionaries(QDialog):
return
@pyqtSlot()
def _doImportHunspell(self):
def _doImportHunspell(self) -> None:
"""Import a hunspell dictionary from .sox or .oxt file."""
procErr = self.tr("Could not process dictionary file")
if self._installPath:
+8 -8
View File
@@ -60,7 +60,7 @@ class GuiManuscriptBuild(QDialog):
D_KEY = QtUserRole
def __init__(self, parent: QWidget, build: BuildSettings):
def __init__(self, parent: QWidget, build: BuildSettings) -> None:
super().__init__(parent=parent)
logger.debug("Create: GuiManuscriptBuild")
@@ -260,7 +260,7 @@ class GuiManuscriptBuild(QDialog):
##
@pyqtSlot("QAbstractButton*")
def _dialogButtonClicked(self, button: QAbstractButton):
def _dialogButtonClicked(self, button: QAbstractButton) -> None:
"""Handle button clicks from the dialog button box."""
role = self.dlgButtons.buttonRole(button)
if role == QtRoleAction:
@@ -273,7 +273,7 @@ class GuiManuscriptBuild(QDialog):
return
@pyqtSlot()
def _doSelectPath(self):
def _doSelectPath(self) -> None:
"""Select a folder for output."""
bPath = Path(self.buildPath.text())
bPath = bPath if bPath.is_dir() else self._build.lastPath
@@ -285,7 +285,7 @@ class GuiManuscriptBuild(QDialog):
return
@pyqtSlot()
def _doResetBuildName(self):
def _doResetBuildName(self) -> None:
"""Generate a default build name."""
bName = f"{SHARED.project.data.name} - {self._build.name}"
self.buildName.setText(bName)
@@ -293,7 +293,7 @@ class GuiManuscriptBuild(QDialog):
return
@pyqtSlot()
def _resetProgress(self):
def _resetProgress(self) -> None:
"""Set the progress bar back to 0."""
self.buildProgress.setValue(0)
return
@@ -350,7 +350,7 @@ class GuiManuscriptBuild(QDialog):
return items[0].data(self.D_KEY)
return None
def _saveSettings(self):
def _saveSettings(self) -> None:
"""Save the user GUI settings."""
winWidth = CONFIG.rpxInt(self.width())
winHeight = CONFIG.rpxInt(self.height())
@@ -369,7 +369,7 @@ class GuiManuscriptBuild(QDialog):
return
def _populateContentList(self):
def _populateContentList(self) -> None:
"""Build the content list."""
rootMap = {}
filtered = self._build.buildItemFilter(SHARED.project)
@@ -398,7 +398,7 @@ class GuiManuscriptBuild(QDialog):
return
def _openOutputFolder(self):
def _openOutputFolder(self) -> None:
"""Open the build folder in the system's file explorer."""
openExternalPath(Path(self.buildPath.text()))
return
+15 -24
View File
@@ -36,8 +36,8 @@ from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter
from PyQt5.QtWidgets import (
QAbstractItemView, QApplication, QDialog, QFormLayout, QGridLayout,
QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton,
QSizePolicy, QSplitter, QStackedWidget, QTabWidget, QTextBrowser,
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
QSplitter, QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget,
QTreeWidgetItem, QVBoxLayout, QWidget
)
from novelwriter import CONFIG, SHARED
@@ -54,7 +54,7 @@ from novelwriter.tools.manusbuild import GuiManuscriptBuild
from novelwriter.tools.manussettings import GuiBuildSettings
from novelwriter.types import (
QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignRight, QtAlignTop,
QtUserRole
QtSizeExpanding, QtSizeIgnored, QtUserRole
)
if TYPE_CHECKING: # pragma: no cover
@@ -303,25 +303,21 @@ class GuiManuscript(QDialog):
@pyqtSlot()
def _editSelectedBuild(self) -> None:
"""Edit the currently selected build settings entry."""
build = self._getSelectedBuild()
if build is not None:
if build := self._getSelectedBuild():
self._openSettingsDialog(build)
return
@pyqtSlot("QListWidgetItem*", "QListWidgetItem*")
def _updateBuildDetails(self, current: QListWidgetItem, previous: QListWidgetItem) -> None:
"""Process change of build selection to update the details."""
if isinstance(current, QListWidgetItem):
build = self._builds.getBuild(current.data(self.D_KEY))
if build is not None:
self.buildDetails.updateInfo(build)
if current and (build := self._builds.getBuild(current.data(self.D_KEY))):
self.buildDetails.updateInfo(build)
return
@pyqtSlot()
def _deleteSelectedBuild(self) -> None:
"""Delete the currently selected build settings entry."""
build = self._getSelectedBuild()
if build is not None:
if build := self._getSelectedBuild():
if SHARED.question(self.tr("Delete build '{0}'?".format(build.name))):
self._builds.removeBuild(build.buildID)
self._updateBuildsList()
@@ -332,8 +328,7 @@ class GuiManuscript(QDialog):
"""Process new build settings from the settings dialog."""
self._builds.setBuild(build)
self._updateBuildItem(build)
current = self.buildList.currentItem()
if isinstance(current, QListWidgetItem) and current.data(self.D_KEY) == build.buildID:
if (current := self.buildList.currentItem()) and current.data(self.D_KEY) == build.buildID:
self._updateBuildDetails(current, current)
return
@@ -342,8 +337,7 @@ class GuiManuscript(QDialog):
"""Run the document builder on the current build settings for
the preview widget.
"""
build = self._getSelectedBuild()
if build is None:
if not (build := self._getSelectedBuild()):
return
docBuild = NWBuildDocument(SHARED.project, build)
@@ -383,8 +377,7 @@ class GuiManuscript(QDialog):
@pyqtSlot()
def _buildManuscript(self) -> None:
"""Open the build dialog and build the manuscript."""
build = self._getSelectedBuild()
if isinstance(build, BuildSettings):
if build := self._getSelectedBuild():
dlgBuild = GuiManuscriptBuild(self, build)
dlgBuild.exec()
@@ -627,7 +620,7 @@ class _DetailsWidget(QWidget):
("headings.fmtChapter", "headings.hideChapter"),
("headings.fmtUnnumbered", "headings.hideUnnumbered"),
("headings.fmtScene", "headings.hideScene"),
("headings.fmtHardScene", "headings.hideHardScene"),
("headings.fmtAltScene", "headings.hideAltScene"),
("headings.fmtSection", "headings.hideSection"),
]:
sub = QTreeWidgetItem()
@@ -1030,16 +1023,14 @@ class _StatsWidget(QWidget):
@pyqtSlot(bool)
def _toggleView(self, state: bool) -> None:
"""Toggle minimal or maximal view."""
ignored = QSizePolicy.Policy.Ignored
expanded = QSizePolicy.Policy.Expanding
if state:
self.mainStack.setCurrentWidget(self.maxWidget)
self.maxWidget.setSizePolicy(expanded, expanded)
self.minWidget.setSizePolicy(ignored, ignored)
self.maxWidget.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
self.minWidget.setSizePolicy(QtSizeIgnored, QtSizeIgnored)
else:
self.mainStack.setCurrentWidget(self.minWidget)
self.maxWidget.setSizePolicy(ignored, ignored)
self.minWidget.setSizePolicy(expanded, expanded)
self.maxWidget.setSizePolicy(QtSizeIgnored, QtSizeIgnored)
self.minWidget.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
self.maxWidget.adjustSize()
self.minWidget.adjustSize()
self.mainStack.adjustSize()
+21 -21
View File
@@ -669,20 +669,20 @@ class _HeadingsTab(NScrollablePage):
self.formatBox.addWidget(self.swtScene, 3, 4)
# Alt Scene Heading
self.lblHScene = QLabel(self._build.getLabel("headings.fmtHardScene"), self)
self.fmtHScene = QLineEdit("", self)
self.fmtHScene.setReadOnly(True)
self.btnHScene = NIconToolButton(self, iSz, "edit")
self.btnHScene.clicked.connect(lambda: self._editHeading(self.EDIT_HSCENE))
self.hdeHScene = QLabel(trHide, self)
self.hdeHScene.setIndent(bSp)
self.swtHScene = NSwitch(self, height=iPx)
self.lblAScene = QLabel(self._build.getLabel("headings.fmtAltScene"), self)
self.fmtAScene = QLineEdit("", self)
self.fmtAScene.setReadOnly(True)
self.btnAScene = NIconToolButton(self, iSz, "edit")
self.btnAScene.clicked.connect(lambda: self._editHeading(self.EDIT_HSCENE))
self.hdeAScene = QLabel(trHide, self)
self.hdeAScene.setIndent(bSp)
self.swtAScene = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblHScene, 4, 0)
self.formatBox.addWidget(self.fmtHScene, 4, 1)
self.formatBox.addWidget(self.btnHScene, 4, 2)
self.formatBox.addWidget(self.hdeHScene, 4, 3)
self.formatBox.addWidget(self.swtHScene, 4, 4)
self.formatBox.addWidget(self.lblAScene, 4, 0)
self.formatBox.addWidget(self.fmtAScene, 4, 1)
self.formatBox.addWidget(self.btnAScene, 4, 2)
self.formatBox.addWidget(self.hdeAScene, 4, 3)
self.formatBox.addWidget(self.swtAScene, 4, 4)
# Section Heading
self.lblSection = QLabel(self._build.getLabel("headings.fmtSection"), self)
@@ -826,14 +826,14 @@ class _HeadingsTab(NScrollablePage):
self.fmtChapter.setText(self._build.getStr("headings.fmtChapter"))
self.fmtUnnumbered.setText(self._build.getStr("headings.fmtUnnumbered"))
self.fmtScene.setText(self._build.getStr("headings.fmtScene"))
self.fmtHScene.setText(self._build.getStr("headings.fmtHardScene"))
self.fmtAScene.setText(self._build.getStr("headings.fmtAltScene"))
self.fmtSection.setText(self._build.getStr("headings.fmtSection"))
self.swtTitle.setChecked(self._build.getBool("headings.hideTitle"))
self.swtChapter.setChecked(self._build.getBool("headings.hideChapter"))
self.swtUnnumbered.setChecked(self._build.getBool("headings.hideUnnumbered"))
self.swtScene.setChecked(self._build.getBool("headings.hideScene"))
self.swtHScene.setChecked(self._build.getBool("headings.hideHardScene"))
self.swtAScene.setChecked(self._build.getBool("headings.hideAltScene"))
self.swtSection.setChecked(self._build.getBool("headings.hideSection"))
self.centerTitle.setChecked(self._build.getBool("headings.centerTitle"))
@@ -850,7 +850,7 @@ class _HeadingsTab(NScrollablePage):
self._build.setValue("headings.hideChapter", self.swtChapter.isChecked())
self._build.setValue("headings.hideUnnumbered", self.swtUnnumbered.isChecked())
self._build.setValue("headings.hideScene", self.swtScene.isChecked())
self._build.setValue("headings.hideHardScene", self.swtHScene.isChecked())
self._build.setValue("headings.hideAltScene", self.swtAScene.isChecked())
self._build.setValue("headings.hideSection", self.swtSection.isChecked())
self._build.setValue("headings.centerTitle", self.centerTitle.isChecked())
@@ -890,8 +890,8 @@ class _HeadingsTab(NScrollablePage):
text = self.fmtScene.text()
label = self._build.getLabel("headings.fmtScene")
elif heading == self.EDIT_HSCENE:
text = self.fmtHScene.text()
label = self._build.getLabel("headings.fmtHardScene")
text = self.fmtAScene.text()
label = self._build.getLabel("headings.fmtAltScene")
elif heading == self.EDIT_SECTION:
text = self.fmtSection.text()
label = self._build.getLabel("headings.fmtSection")
@@ -928,8 +928,8 @@ class _HeadingsTab(NScrollablePage):
self.fmtScene.setText(text)
self._build.setValue("headings.fmtScene", text)
elif heading == self.EDIT_HSCENE:
self.fmtHScene.setText(text)
self._build.setValue("headings.fmtHardScene", text)
self.fmtAScene.setText(text)
self._build.setValue("headings.fmtAltScene", text)
elif heading == self.EDIT_SECTION:
self.fmtSection.setText(text)
self._build.setValue("headings.fmtSection", text)
@@ -1312,7 +1312,7 @@ class _FormatTab(NScrollableForm):
return
@pyqtSlot()
def _pageSizeValueChanged(self):
def _pageSizeValueChanged(self) -> None:
"""The user has changed the page size spin boxes, so we flip
the page size box to Custom.
"""
+4 -5
View File
@@ -560,7 +560,7 @@ class _NewProjectForm(QWidget):
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
self._basePath = CONFIG.lastPath()
self._basePath = CONFIG.homePath()
self._fillMode = self.FILL_BLANK
self._copyPath = None
@@ -632,7 +632,7 @@ class _NewProjectForm(QWidget):
self.numChapters = NSpinBox(self)
self.numChapters.setRange(0, 200)
self.numChapters.setValue(5)
self.numChapters.setValue(0)
self.numChapters.setToolTip(self.tr("Set to 0 to only add scenes"))
self.chapterBox = NWrappedWidgetBox(
@@ -642,7 +642,7 @@ class _NewProjectForm(QWidget):
self.numScenes = NSpinBox(self)
self.numScenes.setRange(0, 200)
self.numScenes.setValue(5)
self.numScenes.setValue(0)
self.sceneBox = NWrappedWidgetBox(
self.tr("Add {0} scene documents (to each chapter)"), self.numScenes
@@ -742,7 +742,6 @@ class _NewProjectForm(QWidget):
):
self._basePath = Path(projDir)
self._updateProjPath()
CONFIG.setLastPath(self._basePath)
return
@pyqtSlot()
@@ -753,7 +752,7 @@ class _NewProjectForm(QWidget):
return
@pyqtSlot()
def _syncSwitches(self):
def _syncSwitches(self) -> None:
"""Check if the add notes option should also be switched off."""
addPlot = self.addPlot.isChecked()
addChar = self.addChar.isChecked()
+9 -1
View File
@@ -25,7 +25,7 @@ from __future__ import annotations
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor, QPainter, QTextCursor
from PyQt5.QtWidgets import QDialogButtonBox, QStyle
from PyQt5.QtWidgets import QDialogButtonBox, QSizePolicy, QStyle
# Qt Alignment Flags
@@ -88,3 +88,11 @@ QtKeepAnchor = QTextCursor.MoveMode.KeepAnchor
QtMoveAnchor = QTextCursor.MoveMode.MoveAnchor
QtMoveLeft = QTextCursor.MoveOperation.Left
QtMoveRight = QTextCursor.MoveOperation.Right
# Size Policy
QtSizeExpanding = QSizePolicy.Policy.Expanding
QtSizeFixed = QSizePolicy.Policy.Fixed
QtSizeIgnored = QSizePolicy.Policy.Ignored
QtSizeMinimum = QSizePolicy.Policy.Minimum
QtSizeMinimumExpanding = QSizePolicy.Policy.MinimumExpanding
+13 -7
View File
@@ -47,7 +47,7 @@ def extractVersion(beQuiet: bool = False) -> tuple[str, str, str]:
"""Extract the novelWriter version number without having to import
anything else from the main package.
"""
def getValue(text):
def getValue(text: str) -> str:
bits = text.partition("=")
return bits[2].strip().strip('"')
@@ -176,7 +176,7 @@ def cleanBuildDirs() -> None:
print("Cleaning up build environment ...")
print("")
def removeFolder(rmDir):
def removeFolder(rmDir: str) -> None:
if os.path.isdir(rmDir):
try:
shutil.rmtree(rmDir)
@@ -320,7 +320,7 @@ def buildQtI18nTS(sysArgs: list[str]) -> None:
print("=============================")
try:
from PyQt6.lupdate import lupdate
from PyQt6.lupdate.lupdate import lupdate
except ImportError:
print("ERROR: This command requires lupdate from PyQt6")
print("On Debian/Ubuntu, install: pyqt6-dev-tools")
@@ -911,7 +911,7 @@ def makeAppImage(sysArgs: list[str]) -> list[str]:
import argparse
try:
import python_appimage # noqa F401
import python_appimage # noqa: F401 # type: ignore
except ImportError:
print(
"ERROR: Package 'python-appimage' is missing on this system.\n"
@@ -1252,12 +1252,12 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
# Clean Up Files
# ==============
def unlinkIfFound(delFile):
def unlinkIfFound(delFile: str) -> None:
if os.path.isfile(delFile):
os.unlink(delFile)
print("Deleted: %s" % delFile)
def deleteFolder(delPath):
def deleteFolder(delPath: str) -> None:
if os.path.isdir(delPath):
shutil.rmtree(delPath)
print("Deleted: %s" % delPath)
@@ -1561,6 +1561,9 @@ def xdgUninstall() -> None:
def winInstall() -> None:
"""Will attempt to install icons and make a launcher for Windows."""
if sys.platform != "win32":
raise Exception("This method only runs on Windows")
import winreg
try:
import win32com.client
@@ -1654,7 +1657,7 @@ def winInstall() -> None:
print("")
print("Creating registry keys ...")
def setKey(kPath, kName, kVal):
def setKey(kPath: str, kName: str, kVal: str) -> None:
winreg.CreateKey(winreg.HKEY_CURRENT_USER, kPath)
regKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, kPath, 0, winreg.KEY_WRITE)
winreg.SetValueEx(regKey, kName, 0, winreg.REG_SZ, kVal)
@@ -1688,6 +1691,9 @@ def winInstall() -> None:
def winUninstall() -> None:
"""Will attempt to uninstall icons previously installed."""
if sys.platform != "win32":
raise Exception("This method only runs on Windows")
import winreg
try:
import win32com.client
+1
View File
@@ -1,2 +1,3 @@
flake8
flake8-pep585
flake8-annotations
+22 -21
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.4rc1" hexVersion="0x020400c1" fileVersion="1.5" fileRevision="3" timeStamp="2024-04-06 15:52:29">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1699" autoCount="264" editTime="83349">
<novelWriterXML appVersion="2.4rc1" hexVersion="0x020400c1" fileVersion="1.5" fileRevision="4" timeStamp="2024-04-11 14:19:47">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1850" autoCount="272" editTime="86438">
<name>Sample Project</name>
<author>Jane Smith</author>
</project>
@@ -20,19 +20,20 @@
<entry key="C">D</entry>
</autoReplace>
<status>
<entry key="sf12341" count="8" red="100" green="100" blue="100">New</entry>
<entry key="sf24ce6" count="2" red="200" green="50" blue="0">Notes</entry>
<entry key="sc24b8f" count="3" red="182" green="60" blue="0">Started</entry>
<entry key="s90e6c9" count="7" red="193" green="129" blue="0">1st Draft</entry>
<entry key="sd51c5b" count="0" red="193" green="129" blue="0">2nd Draft</entry>
<entry key="s8ae72a" count="0" red="193" green="129" blue="0">3rd Draft</entry>
<entry key="s78ea90" count="1" red="58" green="180" blue="58">Finished</entry>
<entry key="sf12341" count="8" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="sf24ce6" count="2" red="200" green="50" blue="0" shape="SQUARE">Notes</entry>
<entry key="sc24b8f" count="3" red="182" green="60" blue="0" shape="BARS_1">Started</entry>
<entry key="s90e6c9" count="5" red="193" green="129" blue="0" shape="BARS_2">1st Draft</entry>
<entry key="sd51c5b" count="1" red="193" green="129" blue="0" shape="BARS_3">2nd Draft</entry>
<entry key="s8ae72a" count="1" red="193" green="129" blue="0" shape="BARS_4">3rd Draft</entry>
<entry key="s78ea90" count="1" red="58" green="180" blue="58" shape="STAR">Finished</entry>
</status>
<importance>
<entry key="ia857f0" count="5" red="100" green="100" blue="100">None</entry>
<entry key="icfb3a5" count="2" red="0" green="122" blue="188">Minor</entry>
<entry key="i2d7a54" count="2" red="21" green="0" blue="180">Major</entry>
<entry key="i56be10" count="1" red="117" green="0" blue="175">Main</entry>
<entry key="ia857f0" count="5" red="100" green="100" blue="100" shape="SQUARE">None</entry>
<entry key="i4a1d39" count="1" red="220" green="138" blue="221" shape="BLOCK_1">Background</entry>
<entry key="icfb3a5" count="1" red="220" green="138" blue="221" shape="BLOCK_2">Minor</entry>
<entry key="i2d7a54" count="2" red="220" green="138" blue="221" shape="BLOCK_3">Major</entry>
<entry key="i56be10" count="1" red="220" green="138" blue="221" shape="BLOCK_4">Main</entry>
</importance>
</settings>
<content items="31" novelWords="998" notesWords="416">
@@ -57,7 +58,7 @@
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
</item>
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H3" charCount="2937" wordCount="520" paraCount="15" cursorPos="1465" />
<meta expanded="no" heading="H3" charCount="2937" wordCount="520" paraCount="15" cursorPos="0" />
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
</item>
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
@@ -78,7 +79,7 @@
</item>
<item handle="ae7339df26ded" parent="88706ddc78b1b" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H3" charCount="189" wordCount="37" paraCount="1" cursorPos="237" />
<name status="s90e6c9" import="ia857f0" active="yes">We Found John!</name>
<name status="sd51c5b" import="ia857f0" active="yes">We Found John!</name>
</item>
<item handle="e5e47ebf63b1c" parent="None" root="e5e47ebf63b1c" order="1" type="ROOT" class="NOVEL">
<meta expanded="yes" />
@@ -90,7 +91,7 @@
</item>
<item handle="a520879ca0b45" parent="e5e47ebf63b1c" root="e5e47ebf63b1c" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H2" charCount="299" wordCount="55" paraCount="2" cursorPos="387" />
<name status="s90e6c9" import="ia857f0" active="yes">Chapter One</name>
<name status="s8ae72a" import="ia857f0" active="yes">Chapter One</name>
</item>
<item handle="f6622b4617424" parent="None" root="f6622b4617424" order="2" type="ROOT" class="CHARACTER">
<meta expanded="yes" />
@@ -102,11 +103,11 @@
</item>
<item handle="14298de4d9524" parent="f7e2d9f330615" root="f6622b4617424" order="0" type="FILE" class="CHARACTER" layout="NOTE">
<meta expanded="no" heading="H1" charCount="49" wordCount="9" paraCount="1" cursorPos="15" />
<name status="sf12341" import="icfb3a5" active="yes">John Smith</name>
<name status="sf12341" import="i2d7a54" active="yes">John Smith</name>
</item>
<item handle="bb2c23b3c42cc" parent="f7e2d9f330615" root="f6622b4617424" order="1" type="FILE" class="CHARACTER" layout="NOTE">
<meta expanded="no" heading="H1" charCount="55" wordCount="9" paraCount="1" cursorPos="31" />
<name status="sf12341" import="i2d7a54" active="yes">Jane Smith</name>
<name status="sf12341" import="i56be10" active="yes">Jane Smith</name>
</item>
<item handle="15c4492bd5107" parent="None" root="15c4492bd5107" order="3" type="ROOT" class="WORLD">
<meta expanded="yes" />
@@ -114,15 +115,15 @@
</item>
<item handle="b3e74dbc1f584" parent="15c4492bd5107" root="15c4492bd5107" order="0" type="FILE" class="WORLD" layout="NOTE">
<meta expanded="no" heading="H1" charCount="76" wordCount="15" paraCount="1" cursorPos="111" />
<name status="sf12341" import="i56be10" active="yes">Earth</name>
<name status="sf12341" import="i2d7a54" active="yes">Earth</name>
</item>
<item handle="f1471bef9f2ae" parent="15c4492bd5107" root="15c4492bd5107" order="1" type="FILE" class="WORLD" layout="NOTE">
<meta expanded="no" heading="H1" charCount="115" wordCount="24" paraCount="1" cursorPos="135" />
<name status="sf12341" import="icfb3a5" active="yes">Space</name>
<name status="sf12341" import="i4a1d39" active="yes">Space</name>
</item>
<item handle="5eaea4e8cdee8" parent="15c4492bd5107" root="15c4492bd5107" order="2" type="FILE" class="WORLD" layout="NOTE">
<meta expanded="no" heading="H1" charCount="28" wordCount="6" paraCount="1" cursorPos="62" />
<name status="sf12341" import="i2d7a54" active="yes">Mars</name>
<name status="sf12341" import="icfb3a5" active="yes">Mars</name>
</item>
<item handle="6827118336ac1" parent="None" root="6827118336ac1" order="4" type="ROOT" class="ARCHIVE">
<meta expanded="yes" />
+12 -12
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="3" timeStamp="2022-11-07 13:00:48">
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="4" timeStamp="2022-11-07 13:00:48">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="5" autoCount="10" editTime="1000">
<name>Sample Project</name>
<author>Jane Smith</author>
@@ -20,19 +20,19 @@
<entry key="C">D</entry>
</autoReplace>
<status>
<entry key="sf12341" count="4" red="100" green="100" blue="100">New</entry>
<entry key="sf24ce6" count="2" red="200" green="50" blue="0">Notes</entry>
<entry key="sc24b8f" count="3" red="182" green="60" blue="0">Started</entry>
<entry key="s90e6c9" count="7" red="193" green="129" blue="0">1st Draft</entry>
<entry key="sd51c5b" count="0" red="193" green="129" blue="0">2nd Draft</entry>
<entry key="s8ae72a" count="0" red="193" green="129" blue="0">3rd Draft</entry>
<entry key="s78ea90" count="1" red="58" green="180" blue="58">Finished</entry>
<entry key="sf12341" count="4" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="sf24ce6" count="2" red="200" green="50" blue="0" shape="SQUARE">Notes</entry>
<entry key="sc24b8f" count="3" red="182" green="60" blue="0" shape="SQUARE">Started</entry>
<entry key="s90e6c9" count="7" red="193" green="129" blue="0" shape="SQUARE">1st Draft</entry>
<entry key="sd51c5b" count="0" red="193" green="129" blue="0" shape="SQUARE">2nd Draft</entry>
<entry key="s8ae72a" count="0" red="193" green="129" blue="0" shape="SQUARE">3rd Draft</entry>
<entry key="s78ea90" count="1" red="58" green="180" blue="58" shape="SQUARE">Finished</entry>
</status>
<importance>
<entry key="ia857f0" count="5" red="100" green="100" blue="100">None</entry>
<entry key="icfb3a5" count="2" red="0" green="122" blue="188">Minor</entry>
<entry key="i2d7a54" count="2" red="21" green="0" blue="180">Major</entry>
<entry key="i56be10" count="1" red="117" green="0" blue="175">Main</entry>
<entry key="ia857f0" count="5" red="100" green="100" blue="100" shape="SQUARE">None</entry>
<entry key="icfb3a5" count="2" red="0" green="122" blue="188" shape="SQUARE">Minor</entry>
<entry key="i2d7a54" count="2" red="21" green="0" blue="180" shape="SQUARE">Major</entry>
<entry key="i56be10" count="1" red="117" green="0" blue="175" shape="SQUARE">Main</entry>
</importance>
</settings>
<content items="27" novelWords="954" notesWords="409">
+1 -1
View File
@@ -75,7 +75,7 @@ class MockStatusBar:
class MockTheme:
def __init__(self):
self.baseIconHeight = 10
self.baseIconHeight = 20
return
def getPixmap(self, *a):
+1 -1
View File
@@ -1,5 +1,5 @@
[Meta]
timestamp = 2024-03-25 11:57:35
timestamp = 2024-04-13 18:57:38
[Main]
theme = default
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.3a4" hexVersion="0x020300a4" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-08 21:34:07">
<novelWriterXML appVersion="2.4rc1" hexVersion="0x020400c1" fileVersion="1.5" fileRevision="4" timeStamp="2024-04-09 22:34:16">
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="1" editTime="0">
<name>New Project</name>
<author>Jane Doe</author>
@@ -16,16 +16,16 @@
</lastHandle>
<autoReplace />
<status>
<entry key="s000000" count="7" red="100" green="100" blue="100">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0">Finished</entry>
<entry key="s000000" count="7" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
</status>
<importance>
<entry key="i000004" count="5" red="100" green="100" blue="100">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0">Main</entry>
<entry key="i000004" count="5" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
</importance>
</settings>
<content items="12" novelWords="10" notesWords="6">
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:50:57">
<novelWriterXML appVersion="2.4rc1" hexVersion="0x020400c1" fileVersion="1.5" fileRevision="4" timeStamp="2024-04-09 22:34:16">
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="1" editTime="0">
<name>New Project</name>
<author>Jane Doe</author>
@@ -16,16 +16,16 @@
</lastHandle>
<autoReplace />
<status>
<entry key="s000000" count="6" red="100" green="100" blue="100">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0">Finished</entry>
<entry key="s000000" count="6" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
</status>
<importance>
<entry key="i000004" count="10" red="100" green="100" blue="100">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0">Main</entry>
<entry key="i000004" count="10" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
</importance>
</settings>
<content items="16" novelWords="9" notesWords="0">
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:53:40">
<novelWriterXML appVersion="2.4rc1" hexVersion="0x020400c1" fileVersion="1.5" fileRevision="4" timeStamp="2024-04-09 22:34:16">
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="1" editTime="0">
<name>New Project</name>
<author>Jane Doe</author>
@@ -16,16 +16,16 @@
</lastHandle>
<autoReplace />
<status>
<entry key="s000000" count="15" red="100" green="100" blue="100">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0">Finished</entry>
<entry key="s000000" count="15" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
</status>
<importance>
<entry key="i000004" count="3" red="100" green="100" blue="100">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0">Main</entry>
<entry key="i000004" count="3" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
</importance>
</settings>
<content items="18" novelWords="26" notesWords="0">
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.3b1" hexVersion="0x020300b1" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-20 12:52:16">
<novelWriterXML appVersion="2.4rc1" hexVersion="0x020400c1" fileVersion="1.5" fileRevision="4" timeStamp="2024-04-09 22:34:16">
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
<name>Test Project A</name>
<author>Jane Doe</author>
@@ -16,16 +16,16 @@
</lastHandle>
<autoReplace />
<status>
<entry key="s000000" count="15" red="100" green="100" blue="100">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0">Finished</entry>
<entry key="s000000" count="15" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
</status>
<importance>
<entry key="i000004" count="7" red="100" green="100" blue="100">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0">Main</entry>
<entry key="i000004" count="7" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
</importance>
</settings>
<content items="22" novelWords="0" notesWords="0">
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.3b1" hexVersion="0x020300b1" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-20 12:52:16">
<novelWriterXML appVersion="2.4rc1" hexVersion="0x020400c1" fileVersion="1.5" fileRevision="4" timeStamp="2024-04-09 22:34:16">
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
<name>Test Project B</name>
<author>Jane Doe</author>
@@ -16,16 +16,16 @@
</lastHandle>
<autoReplace />
<status>
<entry key="s000000" count="9" red="100" green="100" blue="100">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0">Finished</entry>
<entry key="s000000" count="9" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="s000001" count="0" red="200" green="50" blue="0" shape="SQUARE">Note</entry>
<entry key="s000002" count="0" red="200" green="150" blue="0" shape="SQUARE">Draft</entry>
<entry key="s000003" count="0" red="50" green="200" blue="0" shape="SQUARE">Finished</entry>
</status>
<importance>
<entry key="i000004" count="7" red="100" green="100" blue="100">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0">Main</entry>
<entry key="i000004" count="7" red="100" green="100" blue="100" shape="SQUARE">New</entry>
<entry key="i000005" count="0" red="200" green="50" blue="0" shape="SQUARE">Minor</entry>
<entry key="i000006" count="0" red="200" green="150" blue="0" shape="SQUARE">Major</entry>
<entry key="i000007" count="0" red="50" green="200" blue="0" shape="SQUARE">Main</entry>
</importance>
</settings>
<content items="16" novelWords="0" notesWords="0">

Some files were not shown because too many files have changed in this diff Show More