Compare commits

...

876 Commits
v1.0 ... v1.4

Author SHA1 Message Date
Veronica Berglyd Olsen
83e92994d1 Make a clarification in the changelog 2021-07-27 23:14:50 +02:00
Veronica Berglyd Olsen
33146f0a50 Bump version to 1.4 final, and update changelog and release notes 2021-07-27 23:10:48 +02:00
Veronica Berglyd Olsen
732450e163 Add CREDITS file and update README (#833)
* Add CREDITS file and update README
* Fix typo and add note in Libraries section of CREDITS
2021-07-25 16:50:12 +02:00
Veronica Berglyd Olsen
df8e3dd82b Update Contributing Guide (#832)
* Update Contributing Guide
* Minor improvements to README and CONTRIBUTING
2021-07-17 17:27:38 +02:00
Veronica Berglyd Olsen
75ddafd31d Update French translation (#829)
Co-authored-by: jyhelle <47108022+jyhelle@users.noreply.github.com>
2021-07-13 21:51:30 +02:00
Veronica Berglyd Olsen
4f38a8d16c Update the formatting section of the README (#828)
* Update the formatting section of the readme
* Use sup tags for footnotes in readme
2021-07-13 16:13:03 +02:00
Veronica Berglyd Olsen
35746103c7 i18n: Update en_US and nb_NO (#825)
* Update US English translation file
* Update Norwegian translation file
2021-07-13 15:37:24 +02:00
Veronica Berglyd Olsen
fb5347b8e4 Change the branching model (#827)
* Update workflows and add requirements-dev.txt
* Remove codecov from dev requirements
* Update readme and contributing guide
* Update PR template
2021-07-13 15:34:10 +02:00
Veronica Berglyd Olsen
6890b278ea Release 1.4 RC 1 (#824)
* Bump version to 1.4 RC 1
* Update changelog and release notes
2021-07-12 20:52:35 +02:00
Veronica Berglyd Olsen
9f667a0b35 Update code style to new standard 2021-07-05 16:28:44 +02:00
Veronica Berglyd Olsen
36be7b0b33 Test Coverage of the Editor (#787)
* Drop the _qDocument class variables
* Split up the current doceditor test file
* Add tests for editor init, load and save
* Add tests for editor meta functions and actions
* Add tests for editor insert functions
* Add tests for editor text manipulation and block formatting
* Fix code style
* Add text coverage for alignment and indent
2021-07-05 16:10:52 +02:00
Veronica Berglyd Olsen
1d16cc2a03 Move the coding of angle brackets in HTML to the innermost function in the chain (#821) 2021-07-04 18:05:26 +02:00
Veronica Berglyd Olsen
72fd2990e7 Merge branch 'main' into dev 2021-07-04 17:58:53 +02:00
Veronica Berglyd Olsen
6d7ca2bb86 Cleanup (#820)
* Update instructions and readmes
* Cleanup in base files
* Cleanup in core files
* Cleanup in gui files
* Cleanup in dialog files
* Cleanup in tools files
* Cleanup in test files
2021-07-04 17:57:54 +02:00
Veronica Berglyd Olsen
f10a8f9589 Update PR template 2021-07-04 17:56:40 +02:00
Veronica Berglyd Olsen
1881b3d32c Merge branch 'main' into dev 2021-07-02 10:25:56 +02:00
Veronica Berglyd Olsen
1b89d0a4f0 Logger messages (#818)
* Change the way logger messages are generated by using the printf-like method
* Use single quotes around log values that can be empty strings
* Fix bug in log message
2021-07-02 10:22:00 +02:00
용성지
671888b6ea add language support (Simplified Chinese - initial version) (#817)
* add translator's name in about dialog

* add new CN.ts

* Update nw_zh_CN.ts

* inital version (CN)

* add project_zh_CN.json

* Update project_zh_CN.json

* Revert changes to otherlanguage files

* Change case of first character in 'novelWriter' in Chinese translation

* Update about.py

Change the entry "Simplified Chinese" from English the local name of the language

Co-authored-by: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
2021-07-02 10:17:58 +02:00
Veronica Berglyd Olsen
50498a7462 Merge pull request #819 from vkbo/update_guides
Update guides
2021-07-01 20:28:41 +02:00
Veronica Berglyd Olsen
ecd190987e Add a pull request template 2021-07-01 20:23:21 +02:00
Veronica Berglyd Olsen
2c000f6808 Update contributing guide and i18n readme 2021-07-01 20:23:09 +02:00
Veronica Berglyd Olsen
c472e40b2b Fix workflow 2021-06-25 23:28:38 +02:00
Veronica Berglyd Olsen
0575f89ae9 Remove alignments in arguments for format statements 2021-06-25 23:20:15 +02:00
Veronica Berglyd Olsen
e1dcfaa1e3 Drop dictionary alignment by colon 2021-06-25 23:14:13 +02:00
Veronica Berglyd Olsen
486af84107 Merge pull request #816 from vkbo/style
Style
2021-06-25 21:56:03 +02:00
Veronica Berglyd Olsen
8acbd8b978 Update contributing guide with new restrictions 2021-06-25 21:48:50 +02:00
Veronica Berglyd Olsen
7f9180e356 Update workflow 2021-06-25 21:39:24 +02:00
Veronica Berglyd Olsen
26912f226f Add double space before in-line comments 2021-06-25 21:36:52 +02:00
Veronica Berglyd Olsen
0c286231cc Remove multiple hashes before comments 2021-06-25 21:11:25 +02:00
Veronica Berglyd Olsen
991a61f2f6 Remove encoding line and add spaces between classes and functions, tests 2021-06-25 21:04:48 +02:00
Veronica Berglyd Olsen
edfd7c9770 Remove encoding line and add spaces between classes and functions 2021-06-25 20:53:33 +02:00
Veronica Berglyd Olsen
ad62faaeea Fix broken links in docs 2021-06-13 20:03:53 +02:00
Veronica Berglyd Olsen
468903bbeb Merge pull request #812 from vkbo/release_1.4beta1
Release 1.4 Beta 1
2021-06-13 20:01:03 +02:00
Veronica Berglyd Olsen
0723f44dc3 Update changelog and release notes 2021-06-13 19:56:16 +02:00
Veronica Berglyd Olsen
831bdabfc6 Bumped version to 1.4-beta1 2021-06-13 19:12:10 +02:00
Veronica Berglyd Olsen
93a3eed530 Merge pull request #804 from vkbo/text_align
Text alignment and indent
2021-06-13 19:10:15 +02:00
Veronica Berglyd Olsen
307a52e7f4 Update documentation 2021-06-13 19:07:36 +02:00
Veronica Berglyd Olsen
3246f4bfcc Add tests for the menu functions 2021-06-13 18:46:35 +02:00
Veronica Berglyd Olsen
fa4f4a8db4 Make the comment format action a toggle feature 2021-06-13 18:32:11 +02:00
Veronica Berglyd Olsen
cb797fe903 Add menu entries for align and indent 2021-06-13 18:28:23 +02:00
Veronica Berglyd Olsen
618461b1ff Merge branch 'dev' into text_align 2021-06-13 17:59:47 +02:00
Veronica Berglyd Olsen
e2f08d3c76 Merge branch 'main' into dev 2021-06-13 17:58:49 +02:00
Veronica Berglyd Olsen
f39cda729d Merge pull request #811 from vkbo/release_1.3.3
Release 1.3.3
2021-06-13 17:13:54 +02:00
Veronica Berglyd Olsen
b28d826d76 Updated changelog and release notes 2021-06-13 17:11:19 +02:00
Veronica Berglyd Olsen
57ae559723 Merge pull request #810 from vkbo/wcount_when_delete
Update project word count when a file is permanently deleted
2021-06-13 16:57:31 +02:00
Veronica Berglyd Olsen
1d1be18689 Bumped version to 1.3.3 2021-06-13 16:56:29 +02:00
Veronica Berglyd Olsen
141b5eb776 Update project word count when a file is permanently deleted 2021-06-13 16:53:40 +02:00
Veronica Berglyd Olsen
3f941bf9fd Merge branch 'dev' into text_align 2021-06-11 00:11:40 +02:00
Veronica Berglyd Olsen
a48f302531 Merge branch 'main' into dev 2021-06-11 00:11:19 +02:00
Veronica Berglyd Olsen
12d8872973 Merge pull request #809 from vkbo/item_tags
Make XML parser for items less picky
2021-06-11 00:10:46 +02:00
Veronica Berglyd Olsen
40ff865989 Make XML parser for items less picky 2021-06-11 00:01:58 +02:00
Veronica Berglyd Olsen
32e9c10702 Fix word counter for align and indent tags 2021-06-10 23:38:11 +02:00
Veronica Berglyd Olsen
804dd3bb7c Merge branch 'dev' into text_align 2021-06-10 22:52:47 +02:00
Veronica Berglyd Olsen
9f2e3a66cd Merge branch 'main' into dev 2021-06-10 22:51:45 +02:00
Veronica Berglyd Olsen
960d1967a3 Merge pull request #808 from vkbo/focus_keys
Focus keys
2021-06-10 22:45:18 +02:00
Veronica Berglyd Olsen
ad025c3fe4 Merge branch 'main' into focus_keys 2021-06-10 22:42:40 +02:00
Veronica Berglyd Olsen
81212a108e Merge pull request #807 from vkbo/setup_win_encoding
Make the extractVersion function in setup a bit more robust
2021-06-10 22:42:30 +02:00
Veronica Berglyd Olsen
8637a4eb12 Merge branch 'main' into focus_keys 2021-06-10 22:35:55 +02:00
Veronica Berglyd Olsen
0e4489d627 Merge branch 'main' into setup_win_encoding 2021-06-10 22:33:04 +02:00
Veronica Berglyd Olsen
0bfb9d0700 Update docs 2021-06-10 22:18:51 +02:00
Veronica Berglyd Olsen
efe759b94e Change focus shortcuts on Window as they conflict with alt codes 2021-06-10 22:16:06 +02:00
Veronica Berglyd Olsen
9f89c1f7a4 Merge pull request #806 from vkbo/cleanup_alerts
Fix translations and refactor makeAlert calls
2021-06-10 22:10:32 +02:00
Veronica Berglyd Olsen
530d92cc3f Make the extractVersion function in setup a bit more robust 2021-06-10 22:08:26 +02:00
Veronica Berglyd Olsen
b0225515d2 Remove isinstance check in error reporting 2021-06-10 21:55:40 +02:00
Veronica Berglyd Olsen
d511c69ee7 Rewrap some alert messages 2021-06-10 21:51:52 +02:00
Veronica Berglyd Olsen
6e1e40f13e Fix translations and refactor makeAlert calls 2021-06-10 21:42:40 +02:00
Veronica Berglyd Olsen
70d3ee07bf Update sample project 2021-06-10 21:39:58 +02:00
Veronica Berglyd Olsen
e5477f314e Add support for indented paragraphs in exports 2021-06-10 21:38:58 +02:00
Veronica Berglyd Olsen
80c4826253 Added left/right indentation to Tokenizer class 2021-06-10 00:04:54 +02:00
Veronica Berglyd Olsen
e0de3ff191 Improve test coverage 2021-06-09 23:40:37 +02:00
Veronica Berglyd Olsen
239cff3dee Fix tests 2021-06-09 23:32:22 +02:00
Veronica Berglyd Olsen
6f9e3168b0 Fix default alignment 2021-06-09 23:05:16 +02:00
Veronica Berglyd Olsen
7d067f807d Add text alignment tags 2021-06-09 22:08:31 +02:00
Veronica Berglyd Olsen
a7b43699ed Merge pull request #802 from teymour-aldridge/patch-1
Remove redundant assignment.
2021-06-09 19:46:48 +02:00
Teymour Aldridge
7d11917d1c Remove redundant assignment. 2021-06-09 18:42:16 +01:00
Veronica Berglyd Olsen
904ba9b1ca Merge branch 'main' into dev 2021-05-30 12:27:30 +02:00
Veronica Berglyd Olsen
616fe35ed5 Merge pull request #797 from vkbo/release_1.3.2
Release 1.3.2
2021-05-30 12:17:58 +02:00
Veronica Berglyd Olsen
577a3c6c6a Bump version to 1.3.2 and update changelog 2021-05-30 12:14:41 +02:00
Veronica Berglyd Olsen
e937267eb0 Merge pull request #796 from vkbo/split_tool
Fix split tool dropping last line (#795)
2021-05-30 11:58:28 +02:00
Veronica Berglyd Olsen
2c1e1b94e7 Fix split tool dropping last line (#795) 2021-05-30 11:55:56 +02:00
Veronica Berglyd Olsen
60736ce04c Update readme 2021-05-25 19:23:34 +02:00
Veronica Berglyd Olsen
03daa350f8 Merge branch 'main' into dev 2021-05-23 16:37:24 +02:00
Veronica Berglyd Olsen
095cc38122 Merge pull request #786 from vkbo/allow_line_breaks
Allow line breaks
2021-05-23 16:35:09 +02:00
Veronica Berglyd Olsen
142d659b70 Fix an issue with markdown export 2021-05-23 16:31:06 +02:00
Veronica Berglyd Olsen
0826a2f8a3 Remove trailing space highlight and add highlight of redundant spaces 2021-05-23 16:17:05 +02:00
Veronica Berglyd Olsen
a3819a7785 Update docs 2021-05-23 15:20:26 +02:00
Veronica Berglyd Olsen
2314777b4b Add test coverage 2021-05-23 15:04:26 +02:00
Veronica Berglyd Olsen
729e97a95d Add function to clean up line breaks 2021-05-23 14:39:02 +02:00
Veronica Berglyd Olsen
5ab60ca4a3 Fix test 2021-05-23 13:15:09 +02:00
Veronica Berglyd Olsen
f1adff82a8 Remove hard line break menu entry 2021-05-23 13:13:03 +02:00
Veronica Berglyd Olsen
96b2d139c9 Allow line breaks in paragraphs 2021-05-23 13:08:10 +02:00
Veronica Berglyd Olsen
e1bc1222c4 Merge pull request #784 from vkbo/xdg_setup
Add entry in xdg-install to remove old desktop icon
2021-05-22 10:55:53 +02:00
Veronica Berglyd Olsen
0bff4a3d21 Add entry in xdg-install to remove old desktop icon 2021-05-22 10:50:21 +02:00
Veronica K. B. Olsen
dfc775c925 Fix merge from main 2021-05-17 20:28:36 +02:00
Veronica K. B. Olsen
dea304d1eb Merge branch 'main' into dev 2021-05-17 20:27:08 +02:00
Veronica Berglyd Olsen
cfd80645e2 Merge pull request #782 from vkbo/meta_stats
Clear handle when tree details panel is cleared
2021-05-17 20:25:36 +02:00
Veronica K. B. Olsen
4b7f7887c8 Clear handle when tree details panel is cleared 2021-05-17 20:07:56 +02:00
Veronica Berglyd Olsen
9fc640aa59 Merge pull request #780 from vkbo/class_cleanup
GUI Class Cleanup
2021-05-17 17:02:39 +02:00
Veronica K. B. Olsen
d812aab173 Update gitignore with versions files 2021-05-17 16:58:52 +02:00
Veronica K. B. Olsen
39b58711c7 Make some GuiItemDetails variables private 2021-05-17 16:58:07 +02:00
Veronica K. B. Olsen
c6120fcf7c Make some GuiDocViewer variables private 2021-05-17 16:57:49 +02:00
Veronica Berglyd Olsen
45b9215c87 Merge pull request #779 from vkbo/editor_cleanup
Editor Code Improvements
2021-05-16 19:02:57 +02:00
Veronica K. B. Olsen
394f6adf82 Remove no longer needed forward function 2021-05-16 17:35:33 +02:00
Veronica K. B. Olsen
1a5076438d Add a signal for updated word counts 2021-05-16 17:31:12 +02:00
Veronica K. B. Olsen
872b8e7902 Fix broken tests 2021-05-16 16:57:00 +02:00
Veronica K. B. Olsen
0cad96fdca Use an enum to pass values to the status bar LEDs 2021-05-16 16:43:44 +02:00
Veronica K. B. Olsen
e9ef4fd091 Make sure slots and signals are correct type 2021-05-16 16:26:03 +02:00
Veronica K. B. Olsen
4ce8b38acd Add editorDocumentChanged signal in GuiDocEditor 2021-05-16 00:41:44 +02:00
Veronica K. B. Olsen
24ab6f2d3b Make the editor dictionary internal 2021-05-16 00:19:40 +02:00
Veronica K. B. Olsen
ba5e5f4bb5 Make GuiDocEditor variables private 2021-05-15 23:57:31 +02:00
Veronica K. B. Olsen
6ef8611a0a Merge branch 'main' into dev 2021-05-08 21:41:36 +02:00
Veronica Berglyd Olsen
486676baa5 Merge pull request #777 from vkbo/release_1.3.1
Release 1.3.1
2021-05-06 22:26:25 +02:00
Veronica K. B. Olsen
542cbf13ff Update changelog and release notes 2021-05-06 22:23:22 +02:00
Veronica K. B. Olsen
62630eb519 Merge branch 'main' into release_1.3.1 2021-05-06 22:08:11 +02:00
Veronica Berglyd Olsen
b1d597e63f Merge pull request #776 from vkbo/issue769_handles_on_windows
Issue #769: Generating handles on Windows
2021-05-06 22:07:36 +02:00
Veronica Berglyd Olsen
887eee01fc Merge branch 'main' into issue769_handles_on_windows 2021-05-06 22:05:34 +02:00
Veronica K. B. Olsen
f605f1fc75 Solve an unwante error message when creating a new project 2021-05-06 22:02:59 +02:00
Veronica K. B. Olsen
cc8fc38734 Update the handle generator test 2021-05-06 21:58:35 +02:00
Veronica K. B. Olsen
5797b8655d {#769) Fix problem with handle collisions when generated rapidly in Windows 2021-05-06 21:58:08 +02:00
Veronica K. B. Olsen
fd4d663a1c Bump version to 1.3.1 2021-05-06 21:43:43 +02:00
Veronica Berglyd Olsen
88263d55f2 Merge pull request #774 from vkbo/issue773_qtranslate_filepath
Issue #773: Fix QTranslate() filePath issue
2021-05-06 12:52:58 +02:00
Veronica Berglyd Olsen
5c4398f948 Some more tweaks to Linux workflow 2021-05-06 12:50:00 +02:00
Veronica Berglyd Olsen
9ff397dfbc Build translation on Linux workflow 2021-05-06 12:44:58 +02:00
Veronica Berglyd Olsen
1c9ebfd11c Improve feedback and documentation for i18n 2021-05-06 12:33:15 +02:00
Veronica Berglyd Olsen
22e8d7ee71 (#773) Fix Qt 5.15 only call in Config 2021-05-06 10:35:16 +02:00
Veronica K. B. Olsen
35458a7e37 Fix wrong location of parameter in setup.cfg 2021-05-05 19:50:17 +02:00
Veronica Berglyd Olsen
c1544ab374 Merge pull request #760 from vkbo/doc_class
Non-Reusable Document Class
2021-05-02 19:53:20 +02:00
Veronica K. B. Olsen
d795eb6f5f Delete no longer needed test reference files 2021-05-02 19:47:39 +02:00
Veronica K. B. Olsen
ce8264b8f2 New split tool test 2021-05-02 19:47:04 +02:00
Veronica K. B. Olsen
c6cbc8a8b1 New merge tool test 2021-05-02 18:52:36 +02:00
Veronica K. B. Olsen
6c79a1daba Test terminology update 2021-05-02 17:48:28 +02:00
Veronica K. B. Olsen
7867965989 Alter the init logic of handles in NWDoc 2021-05-02 17:19:50 +02:00
Veronica K. B. Olsen
348513a248 Merge branch 'dev' into doc_class 2021-05-02 17:14:15 +02:00
Veronica K. B. Olsen
eb62253137 Merge branch 'main' into dev 2021-05-02 17:12:41 +02:00
Veronica Berglyd Olsen
c4e87435dd Merge pull request #766 from vkbo/release_1.3
Release 1.3
2021-05-02 16:58:48 +02:00
Veronica K. B. Olsen
9980d225f5 Fix test that failed due to change in version number 2021-05-02 16:54:25 +02:00
Veronica K. B. Olsen
9c0f596c0d Release 1.3 2021-05-02 16:49:08 +02:00
Veronica Berglyd Olsen
ff8cca6d8b Merge pull request #765 from vkbo/minimal_setup
Minimal Setup and i18n
2021-05-02 16:08:09 +02:00
Veronica K. B. Olsen
0e5e263dea Merge branch 'main' into minimal_setup 2021-05-02 15:57:48 +02:00
Veronica K. B. Olsen
166732946e Add a custom long description for PyPi 2021-05-02 15:57:38 +02:00
Veronica K. B. Olsen
cccdab45dc Add novelwriter banner png 2021-05-02 15:50:26 +02:00
Veronica K. B. Olsen
190ca7cf2d Merge branch 'main' into minimal_setup 2021-05-02 15:41:08 +02:00
Veronica K. B. Olsen
009160b6bf Add a paragraph break 2021-05-02 15:40:45 +02:00
Veronica K. B. Olsen
851f67d86f Update badges 2021-05-02 15:39:34 +02:00
Veronica K. B. Olsen
b8be2277c4 Merge linux workflows 2021-05-02 15:34:09 +02:00
Veronica K. B. Olsen
14e266b938 Update i18n README 2021-05-02 15:28:38 +02:00
Veronica K. B. Olsen
94f070f096 Fix setup entries for i18n files for minimal packages 2021-05-02 15:20:32 +02:00
Veronica Berglyd Olsen
0c28664ced Merge pull request #764 from vkbo/i18n_pip
I18n and PyPi
2021-05-02 15:05:21 +02:00
Veronica K. B. Olsen
754863e42c Fix setup message 2021-05-01 17:18:15 +02:00
Veronica K. B. Olsen
fb5e4a5f17 Update translations 2021-05-01 17:14:13 +02:00
Veronica K. B. Olsen
03e9fb93c7 Update readmes 2021-05-01 17:14:04 +02:00
Veronica K. B. Olsen
3e77e24b1f The i18n files are no read from assets, while the ts files remain in the root folder 2021-05-01 17:12:59 +02:00
Veronica Berglyd Olsen
d97809e4b0 Merge pull request #762 from vkbo/issue761_lastpath
Issue #761: lastpath in build + test coverage
2021-04-26 23:57:34 +02:00
Veronica K. B. Olsen
551fd0aaf9 This line should not have been changed 2021-04-26 23:54:32 +02:00
Veronica K. B. Olsen
2fc36f8355 Fix timestamp format in odt generator 2021-04-26 23:47:47 +02:00
Veronica K. B. Olsen
13cc2feb3f Improve build class test 2021-04-26 23:41:40 +02:00
Veronica K. B. Olsen
e2b62fc9f6 Fix alternative save path in build, and also add in project wizard 2021-04-26 18:22:16 +02:00
Veronica K. B. Olsen
6b119cf4b8 Remove the return false on error in doc viewer 2021-04-25 23:58:11 +02:00
Veronica K. B. Olsen
88d198403e Update translations 2021-04-25 23:47:42 +02:00
Veronica K. B. Olsen
5ee39d7ecc Tighten up the use of item and nwdoc objects in editor class 2021-04-25 23:46:09 +02:00
Veronica K. B. Olsen
e7102725bd Update translations 2021-04-25 23:24:21 +02:00
Veronica K. B. Olsen
bd28867804 Update tests 2021-04-25 23:22:05 +02:00
Veronica K. B. Olsen
0eb09a2136 Move error reporting out of the NWDoc class 2021-04-25 23:21:51 +02:00
Veronica K. B. Olsen
470daf0036 Make NWDoc class non-reusable 2021-04-25 23:01:20 +02:00
Veronica K. B. Olsen
fd28cbca4e Merge branch 'main' into dev 2021-04-25 18:25:12 +02:00
Veronica Berglyd Olsen
6ecf0ecd88 Merge pull request #759 from vkbo/index_alert
Remove duplicate error message in index class
2021-04-25 18:24:09 +02:00
Veronica K. B. Olsen
c940d9d8a4 Remove duplicate error message in index class 2021-04-25 18:20:31 +02:00
Veronica K. B. Olsen
efef172658 Another round of edits to the main README 2021-04-25 18:18:36 +02:00
Veronica Berglyd Olsen
e865b2c054 Merge pull request #758 from vkbo/class_cleanup
Class Cleanup
2021-04-25 18:02:25 +02:00
Veronica K. B. Olsen
f8243f6934 Update translation files 2021-04-25 17:52:07 +02:00
Veronica K. B. Olsen
746268c3ef GUI classes should only init with main GUI as parent 2021-04-25 17:50:11 +02:00
Veronica K. B. Olsen
48695651e1 Core classes should only init with project class and if needed access main gui via project 2021-04-25 17:39:52 +02:00
Veronica K. B. Olsen
45f726669e Remove the showStatus flag from document handling 2021-04-25 17:16:57 +02:00
Veronica K. B. Olsen
d473615ccf Rename open and save document to read and write in NWDoc 2021-04-25 17:10:12 +02:00
Veronica K. B. Olsen
70425c77ea Clarigy the second paragraph of the README 2021-04-25 13:21:28 +02:00
Veronica K. B. Olsen
8520409459 Shorten the first paragraph of the README 2021-04-25 13:18:39 +02:00
Veronica K. B. Olsen
1e48c6dcfe Merge branch 'main' into dev 2021-04-25 11:27:13 +02:00
Veronica K. B. Olsen
67a81400ff Clarify a few things about markup in the main readme 2021-04-25 11:25:30 +02:00
Veronica K. B. Olsen
51431169dd Merge branch 'main' into dev 2021-04-23 22:02:59 +02:00
Veronica Berglyd Olsen
2a0183c838 Merge pull request #754 from vkbo/restructure_code
Restructure Code
2021-04-23 22:01:36 +02:00
Veronica K. B. Olsen
e222915a37 Update tests readme 2021-04-23 21:54:03 +02:00
Veronica K. B. Olsen
b698ccbc1d Move qutae symbol dialog source file to the dialogs folder 2021-04-23 21:49:20 +02:00
Veronica K. B. Olsen
03a80beebe Move tools source files to their own folder 2021-04-23 21:34:45 +02:00
Veronica K. B. Olsen
1c072e9f32 Move dialog source files to their own folder 2021-04-23 21:24:09 +02:00
Veronica Berglyd Olsen
01576f941f Merge pull request #753 from vkbo/update_readmes
Cleanup of setup instructions and scripts
2021-04-19 20:20:37 +02:00
Veronica K. B. Olsen
4af80286d5 Minor corrections to the main README 2021-04-19 20:15:36 +02:00
Veronica K. B. Olsen
c9785bc57b Cleanup the setup instructions and rename the windows setup scripts 2021-04-19 20:02:58 +02:00
Veronica K. B. Olsen
81e72826ce Merge branch 'main' into dev 2021-04-18 18:18:05 +02:00
Veronica Berglyd Olsen
71f9f3d230 Merge pull request #751 from vkbo/release_1.3rc1
Release 1.3 RC 1
2021-04-18 17:58:36 +02:00
Veronica K. B. Olsen
500a01b46d Bump version to 1.3-rc1 and update changelog and release notes 2021-04-18 17:55:06 +02:00
Veronica K. B. Olsen
8190c189e5 Merge branch 'testing' into dev 2021-04-18 17:33:54 +02:00
Veronica K. B. Olsen
dea2ac22e1 Merge branch 'main' into testing 2021-04-18 17:33:29 +02:00
Veronica Berglyd Olsen
1cae46a936 Merge pull request #750 from vkbo/release_1.2.3
Release 1.2.3
2021-04-18 16:05:18 +02:00
Veronica K. B. Olsen
ac22838ded Bump version to 1.2.3 and update changelog and release notes 2021-04-17 23:44:49 +02:00
Veronica Berglyd Olsen
93875d667c Merge pull request #749 from vkbo/win_uninstall
Windows Uninstall
2021-04-17 18:02:21 +02:00
Veronica K. B. Olsen
41043e4dc1 Fix wrong progress message in setup script 2021-04-17 17:59:35 +02:00
Veronica K. B. Olsen
2e8425d4b1 Improve the setup/uninstall text a bit for windows 2021-04-17 17:57:13 +02:00
Veronica K. B. Olsen
fcac28c69f Improve the windows uninstall script a little 2021-04-17 17:45:28 +02:00
Veronica K. B. Olsen
a14b319ada Update the docs 2021-04-17 17:37:22 +02:00
Veronica K. B. Olsen
6763ebdd66 Don't use import to read version number during setup 2021-04-17 17:18:47 +02:00
Veronica K. B. Olsen
421f2dd688 Add uninstall script for windows 2021-04-17 16:35:13 +02:00
Veronica K. B. Olsen
19b21a3e8a Add win-uninstall command to the setup script 2021-04-17 16:13:13 +02:00
Veronica K. B. Olsen
06dcaff806 Merge branch 'testing' into dev 2021-04-06 17:49:28 +02:00
Veronica K. B. Olsen
f02bba5630 Merge branch 'main' into testing 2021-04-06 17:49:11 +02:00
Veronica Berglyd Olsen
12fa295506 Merge pull request #742 from vkbo/update_i18n
Update i18n
2021-04-06 17:46:39 +02:00
Veronica K. B. Olsen
1054bbdf8b Refresh translation files 2021-04-06 17:42:26 +02:00
Bruno Meneguello
b47436ec59 Update Portuguese translation 2021-04-06 17:42:05 +02:00
Veronica K. B. Olsen
856534cb81 Fix reference to moved file in translation files 2021-04-06 17:39:54 +02:00
Veronica Berglyd Olsen
3ee07c7da7 Merge pull request #736 from vkbo/xdg_setup
XDG Setup and Uninstall
2021-04-02 16:17:57 +02:00
Veronica K. B. Olsen
96fb892465 Update docs 2021-04-02 16:13:18 +02:00
Veronica K. B. Olsen
3a48a124e2 Linux tests 3.6 and 3.7 should also push to codecov 2021-04-02 16:02:40 +02:00
Veronica K. B. Olsen
b391d47a40 Add xdg-uninstall option to setup 2021-04-02 15:50:20 +02:00
Veronica K. B. Olsen
a3c4d7c7b6 Remove desktop icon for xdg install 2021-04-02 15:37:55 +02:00
Veronica K. B. Olsen
4ee5890d90 Merge branch 'testing' into dev 2021-03-31 19:03:42 +02:00
Veronica K. B. Olsen
2ce1134b8b Merge branch 'main' into testing 2021-03-31 19:03:28 +02:00
Veronica Berglyd Olsen
641ff441b5 Merge pull request #734 from vkbo/issue733_project_wordlist
Fix failed initial project dictionary
2021-03-31 19:02:21 +02:00
Veronica K. B. Olsen
7687259381 Non-existing project dictionary file shouldn't prevent the vraiable from being set 2021-03-31 18:53:54 +02:00
Veronica K. B. Olsen
bd888451ec Merge branch 'testing' into dev 2021-03-29 18:52:36 +02:00
Veronica K. B. Olsen
7484542af2 Merge branch 'main' into testing 2021-03-29 18:52:23 +02:00
Veronica K. B. Olsen
1e64a3f94c Further clarifications on installation 2021-03-29 18:51:43 +02:00
Veronica K. B. Olsen
fd7319b295 Merge branch 'testing' into dev 2021-03-29 18:39:36 +02:00
Veronica K. B. Olsen
923e00ad19 Merge branch 'main' into testing 2021-03-29 18:39:17 +02:00
Veronica K. B. Olsen
518be4e630 Merge REaDME from testing branch and rename some tests in workflows 2021-03-29 18:36:15 +02:00
Veronica K. B. Olsen
06a13557e3 Merge branch 'testing' into dev 2021-03-28 18:15:40 +02:00
Veronica Berglyd Olsen
72aa82c8ed Merge pull request #731 from vkbo/release_1.3b1
Release 1.3 Beta 1
2021-03-28 17:59:34 +02:00
Veronica K. B. Olsen
b8a136e0ad Typo in changelog 2021-03-28 17:58:00 +02:00
Veronica K. B. Olsen
38ba214327 Updated changelog and release notes 2021-03-28 17:54:22 +02:00
Veronica K. B. Olsen
c23ec06ce6 Bumped version to 1.3b1 2021-03-28 17:54:06 +02:00
Veronica Berglyd Olsen
c495098582 Merge pull request #730 from vkbo/cleanup
Source Cleanup
2021-03-28 17:25:30 +02:00
Veronica Berglyd Olsen
499d095f81 Merge branch 'testing' into cleanup 2021-03-28 17:18:30 +02:00
Veronica Berglyd Olsen
2ed9367dc8 Merge pull request #729 from vkbo/i18n_setup
I18n Setup
2021-03-28 17:18:22 +02:00
Veronica K. B. Olsen
820e6fcfa3 Update tests 2021-03-28 17:15:35 +02:00
Veronica K. B. Olsen
f92ef05ee2 Move enum and constants to the root source folder 2021-03-28 17:15:17 +02:00
Veronica K. B. Olsen
4b3795671d Update lanaguage files 2021-03-28 16:37:23 +02:00
Veronica K. B. Olsen
bff5ff79bd Added i18n instructions to the docs 2021-03-28 16:30:08 +02:00
Veronica K. B. Olsen
21056c5cb8 Clean up and update the main README 2021-03-28 16:22:03 +02:00
Veronica K. B. Olsen
a4567939d6 Include i18n files in the minimal zip files 2021-03-28 15:42:58 +02:00
Veronica K. B. Olsen
e92ac2b30d Merge branch 'testing' into dev 2021-03-28 15:23:16 +02:00
Veronica K. B. Olsen
90871d5859 Merge branch 'main' into testing 2021-03-28 15:23:02 +02:00
Veronica Berglyd Olsen
cb299d145b Merge pull request #725 from vkbo/release_1.2.2
Release 1.2.2
2021-03-28 15:08:17 +02:00
Veronica K. B. Olsen
6afc34e47e Update changelog and release notes 2021-03-27 22:31:15 +01:00
Veronica K. B. Olsen
f6bcbbd962 Merge branch 'main' into release_1.2.2 2021-03-27 22:22:02 +01:00
Veronica Berglyd Olsen
55f1129a24 Merge pull request #728 from vkbo/issue727_pyw_file
Fix Win-Install from Source
2021-03-27 22:16:22 +01:00
Veronica K. B. Olsen
a2c48492ee Make sure the novelWriter.pyw file exists on win-install 2021-03-27 22:12:33 +01:00
Veronica K. B. Olsen
cb0591fe5f Bump version to 1.2.2 and update changelog 2021-03-27 15:38:48 +01:00
Veronica Berglyd Olsen
2f269c3e17 Merge pull request #724 from vkbo/setup_shasum
SHA 256 Sum for setup files
2021-03-27 15:37:50 +01:00
Veronica K. B. Olsen
d1a15f07d5 Add sha256sum to setup script 2021-03-23 21:21:29 +01:00
Veronica Berglyd Olsen
3cb0c95278 Merge pull request #717 from vkbo/issue716_focus_shortcuts
Issue #716: Focus Mode Improvement and Bugfix
2021-03-22 19:01:42 +01:00
Veronica K. B. Olsen
74910a6b56 Use an enum for switching focus instead of hard coded numbers 2021-03-22 18:57:57 +01:00
Veronica K. B. Olsen
5ab32326c1 Update tests 2021-03-22 18:39:25 +01:00
Veronica K. B. Olsen
7dc184f05f Rename the main GUi setFocus function so that it doesn't override the internal one 2021-03-22 18:35:02 +01:00
Veronica K. B. Olsen
dbdb3931f4 Fix search shortcuts in Focus Mode and stop hiding buttons 2021-03-22 18:34:18 +01:00
Veronica K. B. Olsen
56a5559024 Merge branch 'testing' into dev 2021-03-21 17:18:43 +01:00
Veronica K. B. Olsen
8798afc41c Merge branch 'main' into testing 2021-03-21 17:18:29 +01:00
Veronica Berglyd Olsen
e67c911c97 Merge pull request #710 from vkbo/release_1.2.1
Release 1.2.1
2021-03-21 17:10:31 +01:00
Veronica K. B. Olsen
88d69f6fd4 Update changelog and release notes 2021-03-21 17:08:51 +01:00
Veronica Berglyd Olsen
99555f7dd0 Merge branch 'main' into release_1.2.1 2021-03-21 17:01:14 +01:00
Veronica Berglyd Olsen
b3ec77c631 Merge pull request #715 from vkbo/issue714_install_docs
Issue #714: Linux Setup
2021-03-21 17:01:02 +01:00
Veronica K. B. Olsen
d4c61e7ec9 Update Linux setup for consistency and add more details for macOS 2021-03-21 16:54:53 +01:00
Veronica K. B. Olsen
48bbe288b7 Clarify the install instructions for Linux 2021-03-21 16:50:10 +01:00
Veronica K. B. Olsen
3664266eed Merge branch 'testing' into dev 2021-03-17 22:58:28 +01:00
Veronica Berglyd Olsen
a1f7ab1562 Merge pull request #713 from vkbo/update_french_again
Update french again
2021-03-17 22:57:48 +01:00
Veronica K. B. Olsen
5f95c745e2 Update positions in translation files 2021-03-17 22:40:07 +01:00
jyhelle
1f735d8739 Remove French translations for Qt base, submitted by email 2021-03-17 22:39:46 +01:00
Veronica K. B. Olsen
551fa28b27 Fix typo in i18n readme 2021-03-17 21:19:48 +01:00
Veronica K. B. Olsen
909114e318 Merge branch 'testing' into dev 2021-03-17 21:13:51 +01:00
Veronica Berglyd Olsen
a4e55a0664 Merge pull request #711 from vkbo/update_french
Update French + Bugfix
2021-03-17 21:12:57 +01:00
Veronica K. B. Olsen
86e196808e Fix bug saving quote settings in Preferences 2021-03-17 21:06:58 +01:00
jyhelle
0a4e15de31 Update French translation submitted by email 2021-03-17 21:06:32 +01:00
Veronica K. B. Olsen
cd1f52c6b5 Update translation files 2021-03-17 21:05:57 +01:00
Veronica K. B. Olsen
b63449bffd Merge branch 'main' into testing 2021-03-17 17:25:00 +01:00
Veronica K. B. Olsen
93965138da Bump version and update changelog for patch 1.2.1 2021-03-17 17:23:20 +01:00
Veronica Berglyd Olsen
fae1bd791f Merge pull request #709 from vkbo/issue708_focus
Issue #708: Search bar focus
2021-03-17 17:12:53 +01:00
Veronica K. B. Olsen
35855d2d71 Add a section about search in the docs 2021-03-17 17:09:24 +01:00
Veronica K. B. Olsen
c374534d9e Fix test 2021-03-17 16:43:51 +01:00
Veronica K. B. Olsen
f6c92dab24 Make the editor search/replace bypass the docAction pipeline and be called directly 2021-03-17 16:43:45 +01:00
Veronica K. B. Olsen
03beae30ca Move dev branch to version 1.4-alpha0 2021-03-17 11:33:37 +01:00
Veronica K. B. Olsen
4ee81501a9 Merge branch 'testing' into dev 2021-03-14 18:28:50 +01:00
Veronica K. B. Olsen
3b92c3d75c Wrong docs link on PyPi 2021-03-14 18:22:22 +01:00
Veronica Berglyd Olsen
814876f8df Merge pull request #699 from vkbo/release_1.2
Release 1.2
2021-03-14 18:11:44 +01:00
Veronica K. B. Olsen
567d1ae104 Improve the text for new Preferences options 2021-03-14 15:00:31 +01:00
Veronica Berglyd Olsen
7b7f028d74 Merge pull request #704 from vkbo/french_space
French space padding
2021-03-14 14:52:32 +01:00
Veronica K. B. Olsen
0e53524f2e Update translation files 2021-03-14 14:49:56 +01:00
Veronica K. B. Olsen
0f0e0951ec Add padding options to Preferences 2021-03-14 14:43:12 +01:00
Veronica K. B. Olsen
a172c4b725 Move quote symbols to new Preferences tab 2021-03-14 14:32:05 +01:00
Veronica K. B. Olsen
9f979c02f8 Use free string entries for padding instead of many switches 2021-03-14 14:23:44 +01:00
Veronica K. B. Olsen
1d59a67d6e Fix tests 2021-03-13 23:41:39 +01:00
Veronica K. B. Olsen
5837a4602a Add optional padding for large punctuation symbols 2021-03-13 23:38:12 +01:00
Veronica K. B. Olsen
e07a7ac496 Add optional padding to single and double quotes 2021-03-13 23:25:20 +01:00
Veronica K. B. Olsen
de57d0b027 Merge branch 'main' into dev 2021-03-13 17:00:07 +01:00
Veronica K. B. Olsen
32bcb52f14 Properly update release notes 2021-03-13 16:54:02 +01:00
Veronica K. B. Olsen
612ec06262 Updated changelog and release notes 2021-03-13 16:44:59 +01:00
Veronica K. B. Olsen
93dea90970 Merge branch 'main' into release_1.2 2021-03-13 16:35:27 +01:00
Veronica Berglyd Olsen
47ece1f285 Merge pull request #700 from vkbo/manual_updates
Updates for the documentation
2021-03-13 16:33:17 +01:00
Veronica Berglyd Olsen
64378419d0 Merge branch 'main' into manual_updates 2021-03-13 16:27:15 +01:00
Veronica K. B. Olsen
00a201181d Updated documentation for release 1.2 2021-03-13 16:25:59 +01:00
Veronica Berglyd Olsen
b3f9a14c85 Merge pull request #702 from vkbo/empty_trash
Empty Trash Fix
2021-03-09 12:06:51 +01:00
Veronica K. B. Olsen
065e3828b1 Update test and always ask before moving to trash 2021-03-09 11:02:44 +01:00
Veronica K. B. Olsen
63e91f0ee5 Fix broken emptu trash feature (#701) 2021-03-09 10:52:27 +01:00
jyhelle
182ef5c8f7 Corrections received by email 2021-03-05 19:10:59 +01:00
Veronica Berglyd Olsen
2f790140e0 Merge pull request #698 from vkbo/about_dialog
About dialog updates
2021-03-03 23:04:45 +01:00
Veronica K. B. Olsen
a8bf247d01 Consistency 2021-03-03 22:56:03 +01:00
Veronica K. B. Olsen
e2b3e06077 Merge branch 'dev' into about_dialog 2021-03-03 22:53:45 +01:00
Veronica Berglyd Olsen
43332d8752 Merge pull request #697 from bkmeneguello/pt
Update portuguese translation
2021-03-03 22:52:12 +01:00
Veronica K. B. Olsen
b410ef5d08 Update translations 2021-03-03 22:51:13 +01:00
Veronica K. B. Olsen
1e97a9a872 Use tables instead of lists in About dialog 2021-03-03 22:50:55 +01:00
Veronica K. B. Olsen
26c49e7c22 Add a translations credit section to the About dialog 2021-03-03 21:52:30 +01:00
Veronica B. Olsen
b0f000acfd Bumped version for 1.2 2021-03-03 09:21:52 +01:00
Bruno Kühnen Meneguello
89269b848d Update portuguese translation 2021-03-02 09:04:21 -03:00
Veronica K. B. Olsen
7a55af405b Update outdated info in README 2021-03-02 12:31:22 +01:00
Veronica K. B. Olsen
a3343bc738 Backport .gitignore from dev branch 2021-03-02 11:42:07 +01:00
Veronica K. B. Olsen
dd10486f27 Merge branch 'main' into dev 2021-03-02 11:38:36 +01:00
Veronica Berglyd Olsen
a324ad2dd8 Merge pull request #696 from vkbo/testing
Testing to Main
2021-03-02 11:36:30 +01:00
Veronica Berglyd Olsen
38b4653cb3 Merge pull request #671 from vkbo/release_1.2rc1
Release 1.2 RC 1
2021-03-02 10:29:51 +01:00
Veronica K. B. Olsen
fdd9186ae9 Update release notes and bumped release date 2021-03-02 10:26:55 +01:00
Veronica Berglyd Olsen
81302e3ca5 Merge pull request #695 from vkbo/projsettings_update
Project Settings update
2021-02-27 17:37:01 +01:00
Veronica K. B. Olsen
cf99b4f8b9 Fix flake8 error 2021-02-27 17:19:39 +01:00
Veronica K. B. Olsen
12d39550a8 Use constants for column indices 2021-02-27 17:18:30 +01:00
Veronica K. B. Olsen
9c3e063635 Update en_US and nb_NO translations 2021-02-27 17:08:28 +01:00
Veronica K. B. Olsen
bc0f3e343b Merge branch 'dev' into projsettings_update 2021-02-27 17:02:23 +01:00
Veronica K. B. Olsen
d3eabd8d8f Fix test and revealed bug in main code 2021-02-27 17:00:17 +01:00
Veronica K. B. Olsen
bfa8f97e7e Make the Importance and Status tabs look consistent with Auto-Replace 2021-02-27 16:49:54 +01:00
Veronica K. B. Olsen
4136328a36 Improve the layout of Project Settings > Auto-Replace 2021-02-27 16:21:03 +01:00
Veronica K. B. Olsen
2fd2c18dfc Remove the colour range function as it will not be used 2021-02-27 16:06:24 +01:00
Veronica K. B. Olsen
0a32f9405a Merge branch 'testing' into dev 2021-02-24 22:45:41 +01:00
Veronica K. B. Olsen
7125e9ecd5 Updated changelog 2021-02-24 22:44:01 +01:00
Veronica K. B. Olsen
869e4a0b9d Merge branch 'testing' into release_1.2rc1 2021-02-24 22:38:05 +01:00
Veronica K. B. Olsen
dc0e5c218f Merge branch 'main' into testing 2021-02-24 22:37:44 +01:00
Veronica Berglyd Olsen
7fe3238339 Merge pull request #693 from vkbo/translations
Translations Rondup
2021-02-24 22:34:04 +01:00
Veronica K. B. Olsen
f491f5bf49 Fix broken test 2021-02-24 22:29:49 +01:00
Veronica K. B. Olsen
17070b88d3 Add American English translation 2021-02-24 22:23:35 +01:00
Veronica K. B. Olsen
36fd23b264 Fix some typos and inconsistencies in GUI texts 2021-02-24 22:19:17 +01:00
Veronica K. B. Olsen
fcd1d400f8 Fix spelling of the word "licence" 2021-02-24 21:39:21 +01:00
Veronica K. B. Olsen
dbbec86a13 Merge branch 'dev' into projsettings_update 2021-02-24 20:57:11 +01:00
Veronica K. B. Olsen
67bd23a027 Workflow updates and file cleanup 2021-02-24 20:47:00 +01:00
Veronica Berglyd Olsen
f22a350938 Create FUNDING.yml 2021-02-24 20:38:51 +01:00
Veronica Berglyd Olsen
2f0388d692 Merge pull request #692 from vkbo/french_translation
Add French translation
2021-02-24 20:06:36 +01:00
Jan Lüdke
d7922c6330 Add French translation 2021-02-24 20:00:53 +01:00
Veronica K. B. Olsen
b383142c14 Set maximum height for author box on project settings 2021-02-24 19:47:49 +01:00
Veronica K. B. Olsen
c42b0caf0f Clean up the Project Settings classes 2021-02-23 23:29:18 +01:00
Veronica Berglyd Olsen
6ba286087d Merge pull request #690 from vkbo/issue688_testing
Issue #688: Keyword indexing
2021-02-23 22:35:07 +01:00
Veronica K. B. Olsen
c2e3fef7fc Improve keyword indexer and extend test 2021-02-23 22:28:02 +01:00
Veronica K. B. Olsen
b9d344c7d9 Make sure the test cheks for issue 688 2021-02-23 22:07:14 +01:00
Veronica K. B. Olsen
320643d2da Merge branch 'testing' into dev 2021-02-23 21:14:48 +01:00
Veronica K. B. Olsen
fe04c1af25 Merge branch 'main' into testing 2021-02-23 21:14:30 +01:00
Veronica Berglyd Olsen
21d3ed61ef Merge pull request #689 from vkbo/issue688_wrong_tag
Issue #688: Indexing of invalid keywords
2021-02-23 21:14:03 +01:00
Veronica K. B. Olsen
b7f27a2af0 Don't save invalid keyword references to the index 2021-02-23 20:51:43 +01:00
Veronica Berglyd Olsen
2560b4d336 Merge pull request #687 from vkbo/gui_tweaks
Make settings layouts more responsive
2021-02-23 17:38:44 +01:00
Veronica K. B. Olsen
66282d4ed0 Add Preferences window size to Config and update tests 2021-02-22 20:23:14 +01:00
Veronica K. B. Olsen
2152f54066 Make use of the improved layout class in Project Settings and Preferences 2021-02-22 20:22:49 +01:00
Veronica K. B. Olsen
c89cb32871 Make the QConfigLayout custom class more responsive to the length of labels due to translations 2021-02-22 20:21:22 +01:00
Veronica K. B. Olsen
59eaf9177e Remove some debug print statements 2021-02-22 19:29:01 +01:00
Veronica B. Olsen
36aa58b38e Update changelog 2021-02-22 09:36:09 +01:00
Veronica B. Olsen
2f4fccfb2c Merge branch 'testing' into release_1.2rc1 2021-02-22 09:14:46 +01:00
Veronica B. Olsen
d251ebb995 Fix typo in changelog 2021-02-22 09:13:52 +01:00
Veronica K. B. Olsen
0cc1573503 Merge remote-tracking branch 'origin/dev' into dev 2021-02-21 20:37:04 +01:00
Veronica Berglyd Olsen
2ad3f2c1ab Merge pull request #686 from bkmeneguello/pt
Update portuguese translation
2021-02-21 17:49:28 +01:00
Bruno Kühnen Meneguello
6cca26b914 Updates portuguese translation 2021-02-21 13:34:00 -03:00
Veronica K. B. Olsen
0c946516e8 Merge branch 'testing' into release_1.2rc1 2021-02-21 16:27:04 +01:00
Veronica K. B. Olsen
7b417929e6 Merge branch 'testing' into dev 2021-02-21 16:24:33 +01:00
Veronica K. B. Olsen
c77ef4e4ce Merge branch 'main' into testing 2021-02-21 16:23:50 +01:00
Veronica Berglyd Olsen
a9d90da5c8 Merge pull request #672 from vkbo/release_1.1.1
Release 1.1.1
2021-02-21 16:09:27 +01:00
Veronica K. B. Olsen
4071c2ca43 Last changes to release notes 2021-02-21 16:01:15 +01:00
Veronica K. B. Olsen
58eaddf753 Merge branch 'main' into dev 2021-02-20 17:40:44 +01:00
Veronica K. B. Olsen
0a571502ce Merge branch 'main' into testing 2021-02-20 17:40:30 +01:00
Veronica K. B. Olsen
a850e5b74e Merge latest changes in main and update changelog and release notes 2021-02-20 17:40:17 +01:00
Veronica K. B. Olsen
71aa1fa113 Merge branch 'main' into release_1.1.1 2021-02-20 17:37:01 +01:00
Veronica Berglyd Olsen
24eef2dc0b Merge pull request #685 from vkbo/session_log_short
Drop short sessions from the log file
2021-02-20 17:35:53 +01:00
Veronica K. B. Olsen
5977c8c8e2 Fix test 2021-02-20 17:31:31 +01:00
Veronica K. B. Olsen
dcd4c19b21 Drop logging quick open and close sessions to the session log 2021-02-20 17:28:05 +01:00
Veronica K. B. Olsen
464c7dae0a Fix an issue in index with open a version 1.2 project 2021-02-20 17:27:32 +01:00
Veronica K. B. Olsen
ad92e2e5eb Update changelog 2021-02-20 17:09:47 +01:00
Veronica K. B. Olsen
254845d71f Update changelog and release notes 2021-02-20 16:41:33 +01:00
Veronica Berglyd Olsen
89ab97076c Merge pull request #684 from vkbo/qt_translations
Qt Widget Translations
2021-02-20 13:48:57 +01:00
Veronica K. B. Olsen
dd444ccc8a Update TS files 2021-02-20 13:44:37 +01:00
Veronica K. B. Olsen
c9cab47ce0 Minor code changes for consistency 2021-02-20 13:40:26 +01:00
Veronica K. B. Olsen
b868477406 Change minimum Qt version to 5.3 2021-02-20 13:39:48 +01:00
Veronica K. B. Olsen
71ad3fc51d Fix flake8 error 2021-02-19 17:21:49 +01:00
Veronica K. B. Olsen
837ad7e39c Fix tests 2021-02-19 17:19:10 +01:00
Veronica Berglyd Olsen
898c589e2b Merge branch 'dev' into qt_translations 2021-02-19 16:46:48 +01:00
Veronica K. B. Olsen
49c90a4455 Add a dummy file for translating Qt widgets used in nW for languages with no qtbase localised file 2021-02-19 16:40:52 +01:00
Veronica K. B. Olsen
d315f37c88 Remove translations of standard buttons and switch to native file dialogs 2021-02-19 16:38:56 +01:00
Veronica Berglyd Olsen
799c1dc804 Merge pull request #683 from Number042/dev
Add German translation.
2021-02-19 16:30:00 +01:00
Marian Lückhof
3d457e757d Add German translation. 2021-02-19 16:06:19 +01:00
Veronica K. B. Olsen
f74d575d6a Update the i18n readme 2021-02-18 21:42:46 +01:00
Veronica Berglyd Olsen
d4e0bacde9 Merge pull request #682 from vkbo/project_language
Project Language
2021-02-18 21:26:43 +01:00
Veronica K. B. Olsen
844c3ab26f Allow Build language to not be set at all 2021-02-18 21:18:14 +01:00
Veronica K. B. Olsen
97c884de42 Fix a potential bug 2021-02-18 20:53:31 +01:00
Veronica K. B. Olsen
6cc974a8e9 Fix tests 2021-02-18 20:47:22 +01:00
Veronica K. B. Olsen
5f3822ac1a The word "Synopsis" should be translated to GUI language when it appears in document viewer 2021-02-18 20:46:27 +01:00
Veronica K. B. Olsen
e9763f4ec6 Add language option to the Build tool 2021-02-18 20:45:18 +01:00
Veronica K. B. Olsen
e4d03f9581 Fix tests for variable change, and change monkeypatches to use the context manager 2021-02-18 19:21:46 +01:00
Veronica K. B. Olsen
8b0ac6e81e Rename projLang to spellLang 2021-02-18 19:19:50 +01:00
Veronica Berglyd Olsen
a73eba8916 Merge pull request #681 from bkmeneguello/pt
Updates portuguese translations
2021-02-18 09:10:32 +01:00
Bruno Kühnen Meneguello
c74d761a4b Updates portuguese translations 2021-02-17 21:41:45 -03:00
Veronica Berglyd Olsen
e60cc7b544 Merge pull request #679 from vkbo/norwegian_locale
Norwegian Localisation
2021-02-17 23:25:19 +01:00
Veronica K. B. Olsen
515e53b220 Fix indentation 2021-02-17 23:20:20 +01:00
Veronica K. B. Olsen
8948c3f435 Final translation pass for Norwegian 2021-02-17 23:16:23 +01:00
Veronica K. B. Olsen
3a1367a1d8 Finish the first iteration of the Norwegian translation 2021-02-17 21:55:23 +01:00
Veronica K. B. Olsen
e114873e4c Remove deprecated meta entry support in project files 2021-02-17 21:54:56 +01:00
Veronica K. B. Olsen
be8f98f6c7 Add more translations 2021-02-17 19:10:50 +01:00
Veronica K. B. Olsen
5a685474ff Move the remanining two functions in the tools.py file to other source files 2021-02-17 16:31:37 +01:00
Veronica K. B. Olsen
185974a3ea Add a basic project_pt.json file 2021-02-17 16:30:29 +01:00
Veronica K. B. Olsen
6c87711595 Add internationalisation README 2021-02-17 12:32:00 +01:00
Veronica K. B. Olsen
35b8e389a3 The project language files should obviously also be in the i18n folder 2021-02-17 12:14:57 +01:00
Veronica K. B. Olsen
51564d1adc Rename nb-NO to nb_NO 2021-02-17 10:08:48 +01:00
Veronica K. B. Olsen
88df06ee47 Merge branch 'dev' into norwegian_locale 2021-02-17 10:06:12 +01:00
Veronica Berglyd Olsen
770c746444 Merge pull request #680 from bkmeneguello/Languages-GUI
Adds language selector to preferences
2021-02-17 10:04:41 +01:00
Veronica K. B. Olsen
47215ddb13 Fix instantiation of DummyApp 2021-02-17 09:59:53 +01:00
Veronica K. B. Olsen
fb09066679 Remove debug print and add test coverage 2021-02-17 09:53:27 +01:00
Veronica K. B. Olsen
7591095f2a Rewrite listLanguages function to add more checks and fix misidentification of default language 2021-02-17 09:28:25 +01:00
Bruno Kühnen Meneguello
48575c09ca Adds languages combo to preferences 2021-02-16 23:07:13 -03:00
Veronica K. B. Olsen
5fc01fe685 Add the updated translation files 2021-02-17 01:43:12 +01:00
Veronica Berglyd Olsen
df94dd2cf5 Merge branch 'dev' into norwegian_locale 2021-02-17 01:39:07 +01:00
Veronica Berglyd Olsen
ae53ce5544 Merge pull request #676 from vkbo/tokenizer_localisation
Tokenizer Localisation
2021-02-17 01:37:58 +01:00
Veronica K. B. Olsen
1f0e6c0426 Fix a bunch of missing translation tags and fix a few default strings 2021-02-17 01:37:28 +01:00
Veronica K. B. Olsen
7f84c3c71c Ignore compiled linguistics files 2021-02-17 01:36:06 +01:00
Veronica K. B. Olsen
8a050810c1 Update translation file after removing no longer needed Tokenizer translations 2021-02-17 00:01:07 +01:00
Veronica K. B. Olsen
4033f7a47d Fix tests 2021-02-16 23:58:25 +01:00
Veronica K. B. Olsen
62cc64d912 Remove the old numberToWord functions and clean up the translation files 2021-02-16 23:47:49 +01:00
Veronica K. B. Olsen
290ca2178d Merge branch 'dev' into tokenizer_localisation 2021-02-16 23:13:36 +01:00
Veronica Berglyd Olsen
b935f8a3f3 Merge pull request #673 from bkmeneguello/i18n
Project basic internationalization support
2021-02-16 23:08:34 +01:00
Bruno Kühnen Meneguello
65e31115a1 Final translations 2021-02-16 18:48:15 -03:00
Veronica K. B. Olsen
19d536ea8b Add norwegian project translation files 2021-02-16 22:45:17 +01:00
Veronica K. B. Olsen
8aa2401134 Make sure the project translation map is loaded correctly 2021-02-16 22:42:18 +01:00
Veronica K. B. Olsen
4699d9404b Add the project localisation to the converter classes 2021-02-16 22:18:14 +01:00
Veronica K. B. Olsen
b50132e255 Add support for project language file 2021-02-16 22:02:59 +01:00
Veronica K. B. Olsen
8f1c4af9fa Fix a bug in Build and Constants, and clean up some more nested translates 2021-02-16 19:42:50 +01:00
Veronica K. B. Olsen
d5bd816676 Last round of changes to localisation 2021-02-16 18:14:04 +01:00
Bruno Kühnen Meneguello
8093528694 Update portuguese translation 2021-02-15 22:22:05 -03:00
Veronica K. B. Olsen
7b7bf5d390 Fix a bug in parsing orphaned file names 2021-02-16 00:38:15 +01:00
Veronica K. B. Olsen
8db140fe89 Make the number to word function ready for multiple langauges, and make some minor changes to tooltips in build and status bar 2021-02-15 23:43:56 +01:00
Veronica K. B. Olsen
2e4148a9eb Restore some of the old spell check information in the status bar 2021-02-15 22:29:05 +01:00
Bruno Kühnen Meneguello
ed356ba85d Merge branch 'i18n' of https://github.com/bkmeneguello/novelWriter into i18n 2021-02-15 15:48:52 -03:00
Bruno Kühnen Meneguello
cf79fef0bc Update portuguese translation 2021-02-15 15:47:14 -03:00
Bruno Kühnen Meneguello
d4b4451a48 Improved list and quote handling, also fix a typo 2021-02-15 15:46:48 -03:00
Veronica K. B. Olsen
2f57a4f86f Resolve comment about numbered format string in dialog 2021-02-15 18:03:36 +01:00
Veronica K. B. Olsen
31b665d344 Last pass of fixes and tweaks 2021-02-15 17:52:04 +01:00
Veronica K. B. Olsen
6d56bc7c0c Fix flake8 complaints 2021-02-15 17:01:38 +01:00
Veronica K. B. Olsen
89cf28fade Make tests work on github actions default language code 2021-02-15 16:57:56 +01:00
Veronica K. B. Olsen
8087e8ad75 Fix tests and a bug in GuiMain 2021-02-15 16:48:12 +01:00
Veronica K. B. Olsen
df19ced50c Rewrap self.tr and fix a few bugs 2021-02-15 16:47:57 +01:00
Veronica K. B. Olsen
dba8865d75 Revert some changes to how languages are loaded and remove iso.py 2021-02-15 16:32:20 +01:00
Bruno Meneguello
d506cf2d2a Fix typo and left back "print" 2021-02-15 09:37:45 -03:00
Veronica K. B. Olsen
5e30e1a2ee Just use Qt's own facility for loading localisation files 2021-02-15 11:35:19 +01:00
Veronica K. B. Olsen
af6d96843d Add docstrings and help info for the i18n tools in setup.py 2021-02-15 00:03:14 +01:00
Veronica K. B. Olsen
c0acc1d087 Move the i18n initialisation to the Config class 2021-02-15 00:02:45 +01:00
Bruno Kühnen Meneguello
98e3343808 novelWriter i18n and portuguese translation 2021-02-14 17:16:43 -03:00
Veronica K. B. Olsen
3c72f195ba Bumped version for release 1.1.1 2021-02-13 12:54:16 +01:00
Veronica K. B. Olsen
f3f46858c9 Bumped version for release 1.2 RC 1 2021-02-13 12:48:41 +01:00
Veronica K. B. Olsen
861a847692 Merge branch 'testing' into dev 2021-02-12 22:07:46 +01:00
Veronica K. B. Olsen
d4631229af Merge branch 'main' into testing 2021-02-12 22:07:32 +01:00
Veronica Berglyd Olsen
a78f7d5789 Merge pull request #669 from vkbo/user_dict
Tool to Edit User Dictionary
2021-02-12 22:05:06 +01:00
Veronica K. B. Olsen
fca5c77089 Add GuiWordList test 2021-02-12 22:00:22 +01:00
Veronica Berglyd Olsen
fe828a1c49 Merge pull request #670 from Symbian9/patch-1
Fix installation guide links order
2021-02-12 21:04:42 +01:00
app4soft
11e3573ebd Fix installation guide links order 2021-02-12 22:00:09 +02:00
Veronica K. B. Olsen
ff1d625dc8 Fix logging of exception 2021-02-12 20:26:37 +01:00
Veronica K. B. Olsen
bd9691532f Merge branch 'testing' into user_dict 2021-02-12 20:25:05 +01:00
Veronica K. B. Olsen
133b597093 Merge branch 'main' into testing 2021-02-12 20:23:50 +01:00
Veronica Berglyd Olsen
d4d540bc33 Merge pull request #668 from vkbo/spelling_speedup
Simple Spell Check Speedup
2021-02-12 20:22:11 +01:00
Veronica K. B. Olsen
d08322c1a3 No point making a list to convert to a set 2021-02-12 20:18:32 +01:00
Veronica K. B. Olsen
ec1c664ed6 Fix test 2021-02-12 20:15:38 +01:00
Veronica K. B. Olsen
a3b46581b0 Make the simple spell checker use a set instead of a list 2021-02-12 20:15:28 +01:00
Veronica K. B. Olsen
b115d4f02d Finish the word list dialog and make it possible to reload the user dictionary with pyenchant 2021-02-12 19:40:10 +01:00
Veronica K. B. Olsen
6e64ede90b Add a starting widget for the word liste ditor and connect it to the GUI 2021-02-12 17:01:46 +01:00
Veronica K. B. Olsen
1917c2ce38 Merge branch 'testing' into dev 2021-02-11 23:14:50 +01:00
Veronica K. B. Olsen
c06c2422a9 Merge branch 'main' into testing 2021-02-11 23:13:32 +01:00
Veronica K. Berglyd Olsen
14d205f845 Merge pull request #666 from vkbo/ctrl_del
Change Delete Item Shortcut
2021-02-11 22:06:39 +00:00
Veronica K. B. Olsen
a57ce557e8 Clean up lisence header of main init file 2021-02-11 22:59:19 +01:00
Veronica K. B. Olsen
23c200f333 Update docs 2021-02-11 22:53:58 +01:00
Veronica K. B. Olsen
bf6a3adc06 Change the delete item shortcut 2021-02-11 22:53:14 +01:00
Veronica K. Berglyd Olsen
60a8c8212c Merge pull request #664 from vkbo/minor_fixes
Minor Fixes for 1.2 Beta 1
2021-02-11 21:51:15 +00:00
Veronica K. B. Olsen
525c9c8fd8 Revert last commit and instead change delete item shortcut 2021-02-11 19:27:35 +01:00
Veronica K. B. Olsen
08651685d4 Allow Ctrl+Del to be propagated to the document editor 2021-02-11 19:11:41 +01:00
Veronica K. B. Olsen
3a60abaeee F2 should only edit item if project tree has focus, and edit current document meta if editor has focus 2021-02-11 18:57:44 +01:00
Veronica K. B. Olsen
1e5d980b85 Fix the label of the idle time switch on Writing Statistics 2021-02-11 18:42:28 +01:00
Veronica K. B. Olsen
f9e97735e6 Merge branch 'testing' into dev 2021-02-11 17:19:53 +01:00
Veronica K. Berglyd Olsen
df36aceddb Merge pull request #663 from vkbo/release_1.2beta1
Release 1.2 Beta 1
2021-02-11 16:08:31 +00:00
Veronica K. B. Olsen
600e1cdbfb Added release notes 2021-02-11 17:04:48 +01:00
Veronica K. B. Olsen
d0f11db700 Fix main init source file header 2021-02-10 23:08:47 +01:00
Veronica K. B. Olsen
27de8138f5 Bumped version to 1.3 alpha0 for next dev cycle 2021-02-10 23:00:40 +01:00
Veronica K. B. Olsen
bc0cd2332c Changelog clarifications and corrected typos 2021-02-10 22:59:13 +01:00
Veronica K. B. Olsen
c1b5287ba0 Bumped version to 1.2beta1 and updated changelog 2021-02-10 22:49:32 +01:00
Veronica K. Berglyd Olsen
a2a43b3996 Merge pull request #662 from vkbo/issue605_focus_char
Issue #605: Focus Character
2021-02-10 21:07:25 +00:00
Veronica K. B. Olsen
6c07ecb700 Fix a typo 2021-02-10 22:03:25 +01:00
Veronica K. B. Olsen
2d3f848ab3 Update documentation with references to the @focus keyword 2021-02-10 21:58:25 +01:00
Veronica K. B. Olsen
fdd188516b Update sample project and test 2021-02-10 21:47:42 +01:00
Veronica K. B. Olsen
4c95b1d7ad Add Focus reference to the GUI elements 2021-02-10 21:47:23 +01:00
Veronica K. B. Olsen
19b7b51eea Add the @focus keyword to the base constant classes 2021-02-10 21:46:55 +01:00
Veronica K. Berglyd Olsen
3c355e2d75 Merge pull request #660 from vkbo/build_tool
Build Tool Updates
2021-02-10 19:30:40 +00:00
Veronica K. Berglyd Olsen
290c2f7b62 Merge branch 'dev' into build_tool 2021-02-10 18:34:51 +00:00
Veronica K. Berglyd Olsen
be7bcd03e1 Merge pull request #661 from vkbo/fix_idle_stats
Fix idle Time in Writing Stats
2021-02-10 18:34:04 +00:00
Veronica K. B. Olsen
0965f4213e Fix an issue with summing up idle time when grouping writing stats by day 2021-02-10 19:27:32 +01:00
Veronica K. B. Olsen
bb9ca6e40f Reorder HTML cache file 2021-02-10 18:48:13 +01:00
Veronica K. B. Olsen
672ea6d6f2 Fix and update tests 2021-02-10 16:57:32 +01:00
Veronica K. B. Olsen
ec189a4867 Clean up the Build dialog and connect new options 2021-02-10 16:57:15 +01:00
Veronica K. B. Olsen
f67a50c064 Change the way Unicode is handled in HTML, and clean up the class a bit 2021-02-10 16:56:52 +01:00
Veronica K. B. Olsen
a0fba34ff6 Apply line height and margins to HTML output 2021-02-10 16:55:46 +01:00
Veronica K. B. Olsen
7ea45ac3d2 Cleanup Build dialog and add line height to HTML 2021-02-10 10:39:25 +01:00
Veronica K. B. Olsen
78a58617c1 Connect line height to Build dialog 2021-02-10 10:38:22 +01:00
Veronica K. Berglyd Olsen
f098aeb622 Merge pull request #656 from vkbo/session_idle
Session Idle Time
2021-02-09 20:36:10 +00:00
Veronica K. B. Olsen
6904afc5e7 Updated tests 2021-02-09 21:09:03 +01:00
Veronica K. B. Olsen
b079b30694 Merge branch 'dev' into session_idle 2021-02-09 20:55:26 +01:00
Veronica K. B. Olsen
3e8a425684 Merge branch 'main' into dev 2021-02-09 20:54:31 +01:00
Veronica K. Berglyd Olsen
b47c4c8f71 Merge pull request #659 from vkbo/writing_stats_calc
Make writing stats word calculation more intuitive
2021-02-09 19:54:03 +00:00
Veronica K. B. Olsen
6d3097ae76 Update test 2021-02-09 20:48:48 +01:00
Veronica K. B. Olsen
09e521c2c2 Make writing stats word calculation more intuitive 2021-02-09 19:57:14 +01:00
Veronica K. B. Olsen
2439cf4633 Writing Stats tool should show idle time as either percantage or actual time 2021-02-09 19:46:00 +01:00
Veronica K. B. Olsen
f1b31f26d0 Add preferences for controlling session timer behaviour 2021-02-09 18:54:44 +01:00
Veronica K. B. Olsen
b1eca89a05 Switch icon when session timer is paused 2021-02-09 18:28:22 +01:00
Veronica K. B. Olsen
09bf2a0fe0 Forgot to consider GUI scale 2021-02-08 23:51:03 +01:00
Veronica K. B. Olsen
2d754641b5 Add a switch to hide the idle time column 2021-02-08 23:40:21 +01:00
Veronica K. B. Olsen
871a0dfc6c Fix tests 2021-02-08 23:26:40 +01:00
Veronica K. B. Olsen
3521d4a4f7 Add idle time to session log and writing stats dialog 2021-02-08 23:17:33 +01:00
Veronica K. B. Olsen
407f12760c Record idle time 2021-02-08 21:58:38 +01:00
Veronica K. B. Olsen
479975fdff Move clock tick timer to main GUI 2021-02-08 21:33:06 +01:00
Veronica K. B. Olsen
98fae8a6de Merge branch 'main' into dev 2021-02-08 17:35:41 +01:00
Veronica K. Berglyd Olsen
2e94104ff8 Merge pull request #655 from vkbo/improvements
Various Improvements
2021-02-08 16:34:48 +00:00
Veronica K. B. Olsen
039c13fc0a Add some clarifications to the changelog 2021-02-08 17:29:58 +01:00
Veronica K. B. Olsen
de266e8c88 Add branching policy to the contributing guide 2021-02-08 17:08:48 +01:00
Veronica K. B. Olsen
ada99077a4 Fix some issues with resolving paths for a packaged single executable 2021-02-08 09:44:10 +01:00
Veronica K. B. Olsen
f5588f94db Tweak the project config files 2021-02-08 09:19:53 +01:00
Veronica K. B. Olsen
2a325ae4cc GUI font on Windows should default to Arial first, and fall back to Cantarell 2021-02-07 21:43:32 +01:00
Veronica K. B. Olsen
ac9345419e Merge branch 'main' into dev 2021-02-07 21:14:34 +01:00
Veronica K. B. Olsen
b3fb020dfa Drop using the __status__ variable 2021-02-07 21:12:31 +01:00
Veronica K. Berglyd Olsen
4b885a6e30 Merge pull request #648 from vkbo/release_1.1
Release 1.1
2021-02-07 19:09:48 +00:00
Veronica K. B. Olsen
fa814d64de Updated release notes 2021-02-07 19:45:46 +01:00
Veronica K. B. Olsen
8aa376de25 Merge branch 'main' into release_1.1 2021-02-07 19:43:39 +01:00
Veronica K. Berglyd Olsen
14e7f2d986 Merge pull request #652 from vkbo/odt_header
Add Header to Open Document export
2021-02-07 14:14:44 +00:00
Veronica K. B. Olsen
f816f3d29b Turn document margins into settings 2021-02-06 23:28:41 +01:00
Veronica K. B. Olsen
3db9987966 Add a default header to Open Document files 2021-02-06 23:22:23 +01:00
Veronica K. B. Olsen
5e40bd5deb Change text on build tool print button 2021-02-06 18:31:37 +01:00
Veronica K. B. Olsen
74a9ddbe47 Fix wrong version in ToOdt class header 2021-02-06 18:29:59 +01:00
Veronica K. Berglyd Olsen
188c2ae7ea Merge pull request #650 from vkbo/markdown_export
Markdown Export
2021-02-06 17:05:11 +00:00
Veronica K. B. Olsen
e645c19761 Fix flake8 error 2021-02-06 18:01:03 +01:00
Veronica K. B. Olsen
baf9cab66c Fix a few other docs sections about export 2021-02-06 17:55:29 +01:00
Veronica K. B. Olsen
2fd940bcde Update documentation 2021-02-06 17:48:59 +01:00
Veronica K. B. Olsen
f4988c5d86 Clean up build tool and extend export tests 2021-02-06 17:40:39 +01:00
Veronica K. B. Olsen
b59b3a3a74 Use the old converter for nwd file, not the markdown class 2021-02-06 17:19:30 +01:00
Veronica K. B. Olsen
c677db70b4 Fix a few issues with markdown export 2021-02-06 16:38:06 +01:00
Veronica K. B. Olsen
9861f294b7 Connect markdown exporter to build tool 2021-02-06 15:20:03 +01:00
Veronica K. B. Olsen
c7a42a1641 Basic to markdown class added 2021-02-06 15:07:08 +01:00
Veronica K. B. Olsen
e2a721b209 Merge branch 'main' into dev 2021-02-06 14:35:09 +01:00
Veronica K. Berglyd Olsen
66090e3926 Merge pull request #649 from vkbo/branch_and_ci
Branch and Actions
2021-02-06 13:18:31 +00:00
Veronica K. B. Olsen
60395fb16d Change badges in readme 2021-02-06 14:14:47 +01:00
Veronica K. B. Olsen
54881facf8 Change release branch to testing, and bump mac and windows action to Python 3.9 2021-02-06 14:07:08 +01:00
Veronica K. B. Olsen
9f2f131df9 Merge branch 'main' into dev 2021-02-06 14:03:22 +01:00
Veronica K. B. Olsen
70ab4122a3 Updated version to 1.1 and updated changelog 2021-02-06 13:59:54 +01:00
Veronica K. Berglyd Olsen
7302fb951e Merge pull request #639 from vkbo/minor_tweaks
Minor Tweaks
2021-02-06 12:38:48 +00:00
Veronica K. B. Olsen
dee8ccd8b3 Search box should select the text on open #645 2021-02-06 13:35:53 +01:00
Veronica K. B. Olsen
40b2efb339 Remove some redundant line breaks 2021-02-06 13:35:20 +01:00
Veronica K. B. Olsen
190e74b4d2 Clarify and cross-reference the two sections of the docs describing references and tags 2021-02-06 01:41:56 +01:00
Veronica K. B. Olsen
8bec08799e Merge branch 'release' into dev 2021-02-05 23:08:48 +01:00
Veronica K. B. Olsen
003b056301 Merge branch 'release' into minor_tweaks 2021-02-05 23:08:35 +01:00
Veronica K. B. Olsen
97fd58f793 Merge branch 'main' into release 2021-02-05 23:08:05 +01:00
Veronica K. Berglyd Olsen
aa70d410f8 Merge pull request #644 from vkbo/packaging_cleanup
Packaging Cleanup
2021-02-05 22:07:12 +00:00
Veronica K. B. Olsen
ab21a9238d Update Windows Setup documentation 2021-02-05 17:28:16 +01:00
Veronica K. B. Olsen
be080b1463 Remove the pyinstaller setup functions 2021-02-05 17:27:56 +01:00
Veronica K. B. Olsen
f8ef3e6754 Add flag to tailor minimal zip package to different OSes 2021-02-05 16:52:23 +01:00
Veronica K. Berglyd Olsen
e4e8b939e2 Merge pull request #643 from vkbo/minimal_zip
Minimal Zip Package
2021-02-04 22:20:59 +00:00
Veronica K. B. Olsen
020f122647 Add size 192 scaled icons 2021-02-04 23:16:31 +01:00
Veronica K. B. Olsen
ab0626720a Add setup files to the minimal zip packager in setup.py 2021-02-04 23:16:14 +01:00
Veronica K. B. Olsen
637c05466a Compress minimal zip file 2021-02-03 21:45:22 +01:00
Veronica K. B. Olsen
08b98739f7 Fix typo 2021-02-03 21:37:35 +01:00
Veronica K. B. Olsen
920a835344 Merge branch 'release' into dev 2021-02-03 21:33:42 +01:00
Veronica K. B. Olsen
88e27e315f Merge branch 'release' into minor_tweaks 2021-02-03 21:33:25 +01:00
Veronica K. B. Olsen
7d3427474d Merge branch 'main' into release 2021-02-03 21:32:29 +01:00
Veronica K. Berglyd Olsen
d77183fd48 Merge pull request #635 from vkbo/release_1.0.4
Release 1.0.4
2021-02-03 19:55:38 +00:00
Veronica K. B. Olsen
caa601c9aa Update of release notes and changelog before release 1.0.4 2021-02-03 20:52:36 +01:00
Veronica K. B. Olsen
b9a0152000 Merge branch 'main' into release_1.0.4 2021-02-03 20:41:32 +01:00
Veronica K. Berglyd Olsen
5c5e4e3464 Merge pull request #642 from vkbo/minimal_zip
Minimal Zip Package
2021-02-03 19:40:42 +00:00
Veronica K. B. Olsen
044f987ecd Include the CHANGELOG in the minimal zip 2021-02-03 20:37:04 +01:00
Veronica K. B. Olsen
295351d3e9 Fix a few issues with the minimal zip file and update README 2021-02-03 20:33:32 +01:00
Veronica K. B. Olsen
ab7ca411a4 Add setup command to build a minimal zip file 2021-02-03 20:13:15 +01:00
Veronica K. B. Olsen
c0dee497cd Updated readme and changelog 2021-02-03 19:38:34 +01:00
Veronica K. B. Olsen
247e51478b Merge branch 'main' into release_1.0.4 2021-02-03 17:49:35 +01:00
Veronica K. Berglyd Olsen
a0540e0452 Merge pull request #641 from vkbo/win_install_cont
Windows Install Continued
2021-02-03 16:48:41 +00:00
Veronica K. B. Olsen
515d421dc0 Fix a couple of setup issues and add a note to the docs about updating python 2021-02-03 17:36:25 +01:00
Veronica K. B. Olsen
6032f52798 Update documentation 2021-02-03 16:59:07 +01:00
Veronica K. B. Olsen
05989fdc58 Improve setup for Windows 2021-02-03 16:58:42 +01:00
Veronica K. B. Olsen
b62fafe520 Add source headers to setup and start files, and keep windows start file 2021-02-03 15:21:01 +01:00
Veronica K. B. Olsen
4562a0130a Add a button to the Project Open to remove listed projects, and clarify the dialog message 2021-02-02 22:06:02 +01:00
Veronica K. B. Olsen
6949481198 Stop lookup error on none in project tree meta panel 2021-02-02 16:36:45 +01:00
Veronica K. B. Olsen
5654170278 Let the main gui handle the novel tree refresh decision 2021-02-02 16:36:19 +01:00
Veronica K. Berglyd Olsen
735a324f5a Merge pull request #638 from vkbo/fix_duplicate_from_issue636
Fix Duplicate Code from PR #637
2021-02-01 22:25:47 +00:00
Veronica K. B. Olsen
2cb51f5b58 Backport a small fix from the dev branch 2021-02-01 23:24:02 +01:00
Veronica K. B. Olsen
3baeef4f44 Drop the whole firstTitle index again 2021-02-01 23:20:07 +01:00
Veronica K. B. Olsen
cada78ca4d use what was added in #637 to replace first title lookup in editor saveText 2021-02-01 23:19:24 +01:00
Veronica K. B. Olsen
a2929ef441 Merge branch 'release' into dev 2021-02-01 23:02:40 +01:00
Veronica K. Berglyd Olsen
6c7c8b43b9 Merge pull request #637 from vkbo/issue636_noveltab_wcount
Issue #636: Novel Tab Word Count
2021-02-01 21:59:06 +00:00
Veronica K. B. Olsen
d0940708b0 Add a header structure record to the editor, and force an update of te novel tree if header levels change 2021-02-01 22:49:11 +01:00
Veronica K. B. Olsen
af21f3c5d8 Add index functions to extract headers and word counts for a given handle 2021-02-01 22:48:07 +01:00
Veronica K. B. Olsen
dd18040232 Fix some source file headers 2021-02-01 21:52:51 +01:00
Veronica K. B. Olsen
c72e3a1585 Bumped version to 1.0.4 and updated changelog 2021-02-01 21:17:30 +01:00
Veronica K. B. Olsen
888a47e7a9 Merge branch 'release' into dev 2021-02-01 17:53:40 +01:00
Veronica K. B. Olsen
0df51d2d7c Merge branch 'main' into release 2021-02-01 17:53:17 +01:00
Veronica K. Berglyd Olsen
022945b0d1 Merge pull request #634 from vkbo/win_install
Windows Installation Improvements
2021-02-01 16:51:52 +00:00
Veronica K. B. Olsen
0e62284671 Allow the win-install option to keep icons for both stable and testing version 2021-02-01 17:30:21 +01:00
Veronica K. B. Olsen
704103f9f1 Reorganised and update install instruction in the docs 2021-02-01 17:12:59 +01:00
Veronica K. B. Olsen
1f2ffe7e76 Add win-install command to setup script 2021-02-01 14:14:38 +01:00
Veronica K. Berglyd Olsen
b763abdc76 Merge pull request #632 from vkbo/actions_refactoring
Menu Actions Refactoring and Extension
2021-01-31 22:07:09 +00:00
Veronica K. B. Olsen
af2fcbc059 Add a simple test for now 2021-01-31 23:01:36 +01:00
Veronica K. B. Olsen
0c4d278de2 Extract duplicate code into a new function 2021-01-31 22:53:58 +01:00
Veronica K. B. Olsen
9596d24cca Some final tweaks to the drag and drop feature 2021-01-31 22:29:39 +01:00
Veronica K. B. Olsen
a52b71ef43 Remove ToC.txt files from repo 2021-01-31 22:06:13 +01:00
Veronica K. B. Olsen
216289455e Merge branch 'dev' into actions_refactoring 2021-01-31 19:48:43 +01:00
Veronica K. B. Olsen
019d8cf756 Merge branch 'release' into dev 2021-01-31 19:47:22 +01:00
Veronica K. Berglyd Olsen
3a1c09f89c Merge pull request #596 from vkbo/release_1.1rc1
Release 1.1 RC1
2021-01-31 17:17:23 +00:00
Veronica K. B. Olsen
e9ed4a3f93 Updated changelog and added release notes 2021-01-31 18:12:35 +01:00
Veronica K. B. Olsen
164d6b1b6c Merge branch 'release' into release_1.1rc1 2021-01-31 17:46:37 +01:00
Veronica K. B. Olsen
2307dfaaac Add feature to undo last project tree move 2021-01-31 17:44:28 +01:00
Veronica K. B. Olsen
3cecc1229f Fix GUI blocking in tests 2021-01-31 13:44:44 +01:00
Veronica K. B. Olsen
cca895e418 Cleanup in main menu and move the Move Up/Down entries to the project menu 2021-01-31 13:35:40 +01:00
Veronica K. B. Olsen
ddda934eed Fix tests 2021-01-31 12:56:58 +01:00
Veronica K. B. Olsen
1d8c9ecfc4 Merge branch 'dev' into actions_refactoring 2021-01-31 12:53:03 +01:00
Veronica K. B. Olsen
1f20574520 Merge branch 'release' into dev 2021-01-31 12:51:57 +01:00
Veronica K. B. Olsen
da81bc3ba5 Merge branch 'main' into release 2021-01-31 12:51:36 +01:00
Veronica K. B. Olsen
013fb58267 Block document action if editor does not have focus 2021-01-31 12:50:42 +01:00
Veronica K. B. Olsen
f4f2feae3c Merge branch 'main' into actions_refactoring 2021-01-31 12:45:57 +01:00
Veronica K. Berglyd Olsen
ffad6e47ec Merge pull request #631 from vkbo/issue629_ctrl_del_action
Issue #629: ctrl del action
2021-01-31 11:27:40 +00:00
Veronica K. Berglyd Olsen
2b8f884c12 Merge pull request #630 from vkbo/revert-626-doc_meta
Revert "Add timestamp to document meta"
2021-01-31 11:20:21 +00:00
Veronica K. Berglyd Olsen
2df0d81d29 Revert "Add timestamp to document meta" 2021-01-31 11:59:24 +01:00
Veronica K. B. Olsen
b02c4904a9 Fix tests 2021-01-31 11:58:56 +01:00
Veronica K. B. Olsen
f73cdac9e2 Only allow the delete item command in the project tree if it has focus 2021-01-31 11:53:38 +01:00
Veronica K. Berglyd Olsen
de848511af Merge pull request #628 from vkbo/various_improvements
Various Improvements
2021-01-30 22:39:00 +00:00
Veronica K. B. Olsen
9e294529cf When a new file is added, automatically add the title line 2021-01-30 23:31:19 +01:00
Veronica K. B. Olsen
96d6accbde Add layout and class info to editor footer bar 2021-01-30 22:55:38 +01:00
Veronica K. B. Olsen
86e276ea94 Merge branch 'release' into dev 2021-01-30 22:38:55 +01:00
Veronica K. B. Olsen
8566d62aee Merge branch 'main' into release 2021-01-30 22:37:06 +01:00
Veronica K. Berglyd Olsen
0ccc78e90a Merge pull request #626 from vkbo/doc_meta
Add timestamp to document meta
2021-01-30 18:59:55 +00:00
Veronica K. Berglyd Olsen
3c86207d63 Merge pull request #627 from vkbo/load_project_order_bug
Fix "Open Project" list sorting issue
2021-01-30 18:59:24 +00:00
Veronica K. B. Olsen
c2a37c814d Fix Open Project list sorting issue 2021-01-30 19:43:00 +01:00
Veronica K. B. Olsen
4727866b15 Update test projects 2021-01-30 19:00:12 +01:00
Veronica K. B. Olsen
7a3c33fde3 Fix tests 2021-01-30 18:54:30 +01:00
Veronica K. B. Olsen
087735a08f Add timestamp to document meta data 2021-01-30 18:54:13 +01:00
Veronica K. B. Olsen
a3077d91ec Updated changelog 2021-01-30 15:21:16 +01:00
Veronica K. B. Olsen
649763f2b1 Merge branch 'release' into release_1.1rc1 2021-01-30 15:18:10 +01:00
Veronica K. Berglyd Olsen
f9b988a232 Merge pull request #620 from vkbo/item_layouts
Automatic Item Layouts
2021-01-30 14:16:14 +00:00
Veronica K. B. Olsen
ab45bcb121 Merge branch 'dev' into item_layouts 2021-01-30 15:13:13 +01:00
Veronica K. B. Olsen
e9190d01dc Merge branch 'release' into dev 2021-01-30 15:12:32 +01:00
Veronica K. B. Olsen
ba0e98fd4b Merge branch 'main' into release 2021-01-30 15:11:51 +01:00
Veronica K. Berglyd Olsen
40cc5b379b Merge pull request #624 from vkbo/prefs_fixes
Preferences Fixes
2021-01-30 14:06:37 +00:00
Veronica K. Berglyd Olsen
b1cb48aa9b Merge pull request #625 from vkbo/issue623_justify_prefs
Fix issue #623
2021-01-30 14:06:23 +00:00
Veronica K. B. Olsen
82d9165d92 Fix test 2021-01-30 15:00:51 +01:00
Veronica K. B. Olsen
39d4ee9ad8 More Preferences clarifications 2021-01-30 14:59:17 +01:00
Veronica K. B. Olsen
2cdd444e29 Fix issue #623 2021-01-30 14:48:47 +01:00
Veronica K. B. Olsen
d492f0f41f Rename Preferences variables to match those in the Config class 2021-01-30 14:41:04 +01:00
Veronica K. B. Olsen
943e085d37 Fix a bug and some misleading labels in Preferences 2021-01-30 14:24:06 +01:00
Veronica K. B. Olsen
0624f9103f Get test coverage of NWTree back to 100% 2021-01-30 01:28:05 +01:00
Veronica K. B. Olsen
cab1530afc Add debug log output for layout change 2021-01-30 01:03:54 +01:00
Veronica K. B. Olsen
90e63f1898 Merge branch 'dev' into item_layouts 2021-01-30 00:57:42 +01:00
Veronica K. B. Olsen
b2fdd92f9c Merge branch 'release' into dev 2021-01-30 00:57:22 +01:00
Veronica K. Berglyd Olsen
91701b484a Merge pull request #621 from vkbo/issue608_cursor_in_blank_doc
Issue #608: Missing Cursor
2021-01-29 22:08:59 +00:00
Veronica K. B. Olsen
9fdae1ac45 Fix missing cursor when opening empty document 2021-01-29 22:38:07 +01:00
Veronica K. B. Olsen
b7766946d8 Update index check and test 2021-01-29 20:43:04 +01:00
Veronica K. B. Olsen
9486749345 Merge branch 'dev' into item_layouts 2021-01-29 20:20:16 +01:00
Veronica K. Berglyd Olsen
a3bec4d5fc Merge pull request #619 from vkbo/index_check
More thorough index check
2021-01-29 19:18:06 +00:00
Veronica K. B. Olsen
d8cc091f94 Also use the new nwItem checkers in the NWItem class 2021-01-29 18:39:48 +01:00
Veronica K. B. Olsen
89ba4aeeaf Use the logException function in all places where exception messages are written to the error log 2021-01-29 18:29:50 +01:00
Veronica K. B. Olsen
a2f223a992 Perform a detailed check of the loaded index to make sure everything is in order 2021-01-29 18:15:00 +01:00
Veronica K. B. Olsen
286efade59 Add more check functions 2021-01-29 13:22:38 +01:00
Veronica K. B. Olsen
4e7888259f Add logging wrapper for exceptions 2021-01-29 13:17:31 +01:00
Veronica K. B. Olsen
8e3fa892e1 Modify conditions according to #618 2021-01-29 11:55:36 +01:00
Veronica K. B. Olsen
8de0c55b68 Fix broken tests 2021-01-29 01:14:58 +01:00
Veronica K. B. Olsen
4c27d2600a Update document layout during editor save process 2021-01-29 01:09:04 +01:00
Veronica K. B. Olsen
59cfb14a19 Add a first title index that tracks the level and location of the first title of a file 2021-01-29 00:57:34 +01:00
Veronica K. B. Olsen
6f7cf4f186 Bump dev version to 1.2-alpha0 2021-01-28 22:09:28 +01:00
Veronica K. B. Olsen
52454c50b7 Updated changelog 2021-01-28 21:49:29 +01:00
Veronica K. B. Olsen
c56219f5b4 Merge branch 'release' into release_1.1rc1 2021-01-28 21:41:35 +01:00
Veronica K. B. Olsen
99b6e1f93c Merge branch 'release' into dev 2021-01-28 21:35:43 +01:00
Veronica K. Berglyd Olsen
6ff1549d2e Merge pull request #616 from vkbo/issue610_save_doc_on_build
Issue #610: Save document before build
2021-01-28 20:33:20 +00:00
Veronica K. B. Olsen
1b05e8ddc9 Save current document before building project 2021-01-28 21:26:51 +01:00
Veronica K. Berglyd Olsen
4745877a63 Merge pull request #615 from vkbo/issue612_change_focus
Issue #612: Change Focus
2021-01-28 20:17:43 +00:00
Veronica K. B. Olsen
c81c7f5a33 Fix syntax check for release branch 2021-01-28 21:13:19 +01:00
Veronica K. B. Olsen
a23beddc66 Update documentation with new shortcut key 2021-01-28 21:07:58 +01:00
Veronica K. B. Olsen
045929681d Add Alt+4 focus key, and switch main tab on focus change 2021-01-28 21:04:22 +01:00
Veronica K. Berglyd Olsen
cf0cf52298 Merge pull request #607 from vkbo/odt_format
Open Document Export
2021-01-28 19:54:00 +00:00
Veronica K. B. Olsen
1ff7c8bdd5 Update reference files for build test 2021-01-28 20:48:49 +01:00
Veronica K. B. Olsen
7254f766d5 Remove div tags from HTML output and bring Tokenizer and ToHtml tests back to 100% 2021-01-28 20:42:39 +01:00
Veronica K. B. Olsen
83e07ec76c Fix tests 2021-01-28 17:04:33 +01:00
Veronica K. B. Olsen
c3a1f25894 Reshuffle build and preview in Build Novel Project tool 2021-01-28 17:04:14 +01:00
Veronica K. B. Olsen
750d8b0a25 Clean up ODT code and add some comments 2021-01-28 01:23:48 +01:00
Veronica K. B. Olsen
2e4558a5d3 Bypass html cache when not building html doc 2021-01-28 00:40:10 +01:00
Veronica K. B. Olsen
3e5813323b Drop the manifest.rdf file 2021-01-28 00:22:53 +01:00
Veronica K. B. Olsen
ecd858251f Add code for writing ODT files 2021-01-28 00:21:39 +01:00
Veronica K. B. Olsen
ac0847ffe3 Predefine some XML tags 2021-01-27 21:54:14 +01:00
Veronica K. B. Olsen
d1bf49790e Add exports for comments, synopsis and keywords 2021-01-27 21:48:20 +01:00
Veronica K. B. Olsen
815f24fbf5 Add release branch for release candidates 2021-01-27 19:53:53 +01:00
Veronica K. B. Olsen
d83352e16f Fix Build Novel Project test on Ubuntu 2021-01-27 19:49:21 +01:00
Veronica K. B. Olsen
8715ab9322 Add logic to apply formatting to text 2021-01-27 19:36:34 +01:00
Veronica K. B. Olsen
4df294f0a2 Add customised margin sizes 2021-01-27 16:22:59 +01:00
Veronica K. B. Olsen
cbbe1b4f47 Add ODT meta namespace, add font format to HTML, and merge page break settings 2021-01-27 13:36:09 +01:00
Veronica K. B. Olsen
8ccd6a8ed3 Fix setting font setting for ODT export 2021-01-27 12:38:31 +01:00
Veronica K. B. Olsen
cbd222fe30 Add code to save tabs and line breaks to ODT file 2021-01-27 02:35:19 +01:00
Veronica K. B. Olsen
1683567dda Restructure Build Novel Project tool to allow ODT save 2021-01-27 01:12:34 +01:00
Veronica K. B. Olsen
da2e40db4d Add ODT auto-style logic 2021-01-27 01:12:09 +01:00
Veronica K. B. Olsen
e3c37f003b Add main ODT style XML 2021-01-26 20:22:32 +01:00
Veronica K. B. Olsen
c9eebafb2d Add core structure for ODT class 2021-01-26 16:25:14 +01:00
Veronica K. Berglyd Olsen
751da877ee Merge pull request #604 from vkbo/insert_symbols
More Insert Symbols
2021-01-26 15:09:08 +00:00
Veronica K. B. Olsen
14d19b5117 Fix indentation of Project Details source file header 2021-01-26 16:06:36 +01:00
Veronica K. B. Olsen
41d4c883a3 Add horizontal bar 2021-01-26 16:03:30 +01:00
Veronica K. B. Olsen
09504508d9 Add proper minus sign, and change a few shortcuts to more sensible ones 2021-01-26 14:03:19 +01:00
Veronica K. B. Olsen
94c755a0e6 Fix tests and clean up a couple of minor things in HTML generator 2021-01-26 13:12:38 +01:00
Veronica K. B. Olsen
f21cff335b Drop the triangle bullet as it's not always available in fonts 2021-01-26 13:11:26 +01:00
Veronica K. B. Olsen
6947996c9a Correct name of HTML constant for cross symbol 2021-01-25 23:50:47 +01:00
Veronica K. B. Olsen
0756090081 Update documentations on new symbols 2021-01-25 23:45:28 +01:00
Veronica K. B. Olsen
95e03d2684 Add triangle and hyphen bullets 2021-01-25 23:45:11 +01:00
Veronica K. B. Olsen
fab5833cdf Add degree, times and divide symbols to insert menu, and simply the editor insert function 2021-01-25 23:05:41 +01:00
Veronica K. Berglyd Olsen
a011c10d4d Merge pull request #603 from vkbo/various_changes
Various Minor Changes
2021-01-25 16:24:50 +00:00
Veronica K. B. Olsen
14584bef55 Update docs and tests 2021-01-25 17:15:12 +01:00
Veronica K. B. Olsen
907a371bd4 Some minor improvements to the logging system 2021-01-25 17:11:05 +01:00
Veronica K. B. Olsen
a420c1749a Add more insert menu entries 2021-01-25 17:09:39 +01:00
Veronica K. B. Olsen
c29e9bb68d Project Details Content tree should not have selectable rows 2021-01-25 11:28:18 +01:00
Veronica K. B. Olsen
fd965e6022 Updated changelog 2021-01-25 11:24:37 +01:00
Veronica K. B. Olsen
2e8d7a20d0 Merge branch 'dev' into release_1.1rc1 2021-01-25 11:20:02 +01:00
Veronica K. Berglyd Olsen
8084ed191e Merge pull request #598 from vkbo/improve_details
Improve Project Details
2021-01-25 10:18:20 +00:00
Veronica K. B. Olsen
0b51e50c19 Add a title to the Contents tab in project Details 2021-01-24 22:57:32 +01:00
Veronica K. B. Olsen
659e056eeb Fix flake8 complaint 2021-01-24 22:54:40 +01:00
Veronica K. B. Olsen
c70023c066 Fix tests 2021-01-24 22:49:23 +01:00
Veronica K. B. Olsen
ba2bdf8ea4 Add page offset spinbox to Contents tab on Project Details dialog 2021-01-24 22:49:13 +01:00
Veronica K. B. Olsen
57330bb2cd Make sure project tree is updated before Project Details dialog is opened 2021-01-24 22:47:49 +01:00
Veronica K. B. Olsen
16fdef2d55 Merge branch 'dev' into release_1.1rc1 2021-01-24 14:52:59 +01:00
Veronica K. B. Olsen
31928d5ebb Merge branch 'main' into dev 2021-01-24 14:52:35 +01:00
Veronica K. Berglyd Olsen
8370b99302 Merge pull request #594 from vkbo/release_1.0.3
Release 1.0.3
2021-01-24 13:19:53 +00:00
Veronica K. B. Olsen
13f98e1675 Update changelog and release notes 2021-01-24 14:14:43 +01:00
Veronica K. B. Olsen
615804333e Merge branch 'main' into release_1.0.3 2021-01-24 13:56:26 +01:00
Veronica K. Berglyd Olsen
e1b9e113b1 Merge pull request #597 from vkbo/build_tweaks
HTML conversion tweaks
2021-01-24 12:55:56 +00:00
Veronica K. B. Olsen
dfbde3e41c Fix broken tests 2021-01-24 13:41:40 +01:00
Veronica K. B. Olsen
034b4feff4 HTML divs should end in a line break, and use hex values for binary flags 2021-01-24 13:41:26 +01:00
Veronica K. B. Olsen
949439361e Bump version to 1.1 RC1 and update changelog 2021-01-23 16:27:17 +01:00
Veronica K. Berglyd Olsen
163b6b3725 Merge pull request #577 from vkbo/issue546_multipar_quotes
Issue #546: Multi-Paragraph Quotes
2021-01-23 15:05:38 +00:00
Veronica K. B. Olsen
bdc6addf81 Fix a minor issue in the Preferences test 2021-01-23 16:00:06 +01:00
Veronica K. B. Olsen
fd7c1e24a3 Merge branch 'dev' into issue546_multipar_quotes 2021-01-23 15:44:01 +01:00
Veronica K. B. Olsen
a16ecbcebd Merge branch 'main' into dev 2021-01-23 15:43:24 +01:00
Veronica K. B. Olsen
0a1f6be4a5 Bump version and update changelog 2021-01-23 15:39:41 +01:00
Veronica K. Berglyd Olsen
98bf462e02 Merge pull request #593 from vkbo/minor_fixes
Minor Fixes
2021-01-23 14:21:20 +00:00
Veronica K. B. Olsen
86fa59e5e1 Easier to just make the scroll past end feature go to 90% 2021-01-23 15:19:01 +01:00
Veronica K. B. Olsen
1ddadeba5d Make the autoscroll feature also work for a very short document 2021-01-23 15:12:25 +01:00
Veronica K. B. Olsen
2e1d5d4d13 Windows installer for pyz should have a different name than the regular installer 2021-01-23 15:11:52 +01:00
Veronica K. Berglyd Olsen
31b29abf5f Merge pull request #584 from vkbo/simple_pack
Package for Windows without an .exe file
2021-01-23 13:55:22 +00:00
Veronica K. B. Olsen
16c428dbd5 Update docs to reflect that make.py has been merged into setup.py 2021-01-23 14:51:27 +01:00
Veronica K. Berglyd Olsen
54bc6550ee Merge branch 'main' into simple_pack 2021-01-23 13:46:31 +00:00
Veronica K. B. Olsen
a698cb6ef7 Automatically download the correct Python embed version 2021-01-23 14:43:54 +01:00
Veronica K. B. Olsen
5f86ab27bb Complete the zipapp packaging for Windows 2021-01-23 14:25:12 +01:00
Veronica K. Berglyd Olsen
f0b2c08a9e Merge pull request #592 from vkbo/update_texts
Update README.md and CONTRIBUTING.md
2021-01-23 13:22:00 +01:00
Veronica K. B. Olsen
3f8c705989 Fix some typos and reword some bits in README and CONTRIBUTING 2021-01-23 13:14:50 +01:00
Veronica K. B. Olsen
6f84574511 Also updated docs 2021-01-23 12:12:45 +01:00
Veronica K. B. Olsen
6a131977d3 Reorganise and update README 2021-01-23 11:43:22 +01:00
Veronica K. B. Olsen
4df0075b42 Add note on line length to contributing guide 2021-01-23 11:10:59 +01:00
Veronica K. B. Olsen
e3972c6205 Merge branch 'main' into simple_pack 2021-01-22 20:18:52 +01:00
Veronica K. B. Olsen
4e949f542c Re-organised the Preferences dialog as some pages were growing quite long 2021-01-22 20:18:03 +01:00
Veronica K. Berglyd Olsen
af38fd3ba3 Merge pull request #590 from mgrhm/setup-typo-fix
fix: Typos in setup.py file.
2021-01-22 19:53:57 +01:00
Mike Graham
d00ac278c6 Fixed typos in setup.py. 2021-01-22 18:24:19 +00:00
Veronica K. Berglyd Olsen
0e01303921 Merge pull request #587 from vkbo/issue581_os_relpath
Issue #581: os.path.relpath on Windows
2021-01-22 00:41:51 +01:00
Veronica K. B. Olsen
39eeaf06e5 Add explicit reference directory for os relpath calls to avoid issue #581 on Windows 2021-01-22 00:35:43 +01:00
Veronica K. B. Olsen
7c2c4b26b3 Merge make.py into setup.py 2021-01-21 17:24:54 +01:00
Veronica K. B. Olsen
2ea0703701 Preserve both methods for building Inno Setup installers 2021-01-21 16:45:16 +01:00
Veronica K. B. Olsen
d425cdc27d Added alternative packaging method for windows 2021-01-21 00:50:13 +01:00
Veronica K. B. Olsen
799c833a66 Add a simple packaging function 2021-01-20 18:25:51 +01:00
Veronica K. B. Olsen
96bc88d045 Added some smart filters for quote settings 2021-01-20 00:08:49 +01:00
Veronica K. Berglyd Olsen
da7bbc2b20 Merge pull request #578 from nullbasis/main
Added new GUI and editor themes
2021-01-19 23:39:03 +01:00
Null
7b4f6c3222 Add files via upload 2021-01-19 16:34:36 -06:00
Null
e3bc528647 Add files via upload 2021-01-19 16:32:32 -06:00
Null
29665203c0 Add files via upload 2021-01-19 16:19:16 -06:00
Null
7beb9afc36 Added Solarized Dark and Light GUI themes 2021-01-19 15:24:29 -06:00
Null
2fcb3a0131 Added Solarized Dark and Light editor themes 2021-01-19 15:23:44 -06:00
Veronica K. B. Olsen
0a9749726f Merge branch 'dev' into issue546_multipar_quotes 2021-01-19 21:34:23 +01:00
Veronica K. B. Olsen
c1e6d9c633 Merge branch 'main' into dev 2021-01-19 21:33:59 +01:00
Veronica K. Berglyd Olsen
4767d49e4d Fixed duplicate word in README 2021-01-19 21:25:02 +01:00
Veronica K. Berglyd Olsen
2bf7e8506c Merge pull request #564 from vkbo/release_1.0.2
Release 1.0.2
2021-01-19 20:59:38 +01:00
Veronica K. B. Olsen
447966e3b8 Changed release date and updated release notes 2021-01-19 20:56:29 +01:00
Veronica K. B. Olsen
adc17272dc Updated changelog with latest changes 2021-01-19 20:17:15 +01:00
Veronica K. B. Olsen
6e54f34419 Merge branch 'main' into release_1.0.2 2021-01-19 20:02:43 +01:00
Veronica K. Berglyd Olsen
4b4051a823 Merge pull request #576 from vkbo/issue570_install_docs
Issue #570: Clarify install instructions
2021-01-19 20:01:28 +01:00
Veronica K. B. Olsen
5c4e230f69 No need to duplicate instructions, but added a TLDR section 2021-01-19 19:55:25 +01:00
Veronica K. B. Olsen
2c191a9bd3 Minor modification to the macOS workflow 2021-01-19 19:30:35 +01:00
Veronica K. B. Olsen
ed9313759b Clarify install instructions on dependency install 2021-01-19 19:30:14 +01:00
Veronica K. Berglyd Olsen
70a7a72baa Merge pull request #575 from vkbo/issue574_user_dict_no_suggest
Issue #574: Show "Add Word to Dictionary" when there are no spell suggestions
2021-01-19 19:20:54 +01:00
Veronica K. B. Olsen
4d69025250 Fix lambda function syntax 2021-01-19 19:09:37 +01:00
Veronica K. B. Olsen
9f9028b7ce Fix "Add Word to Dictionary" missing when there are no spell suggestions 2021-01-19 19:08:51 +01:00
Veronica K. Berglyd Olsen
e9be3242b2 Merge pull request #573 from stranger-danger-zamu/patch-1
Issue #570
2021-01-19 18:37:57 +01:00
Veronica K. B. Olsen
6868b683d8 Added new quote setting to Preferences and updated tests 2021-01-19 18:37:19 +01:00
Veronica K. B. Olsen
4934ec2ea1 Add syntax highlighting for open-ended quotes 2021-01-19 18:36:47 +01:00
stranger-danger-zamu
211a06e9bc Issue #570 2021-01-19 11:44:44 -05:00
Veronica K. Berglyd Olsen
debca0a82d Merge pull request #565 from vkbo/gui_tweaks
GUI Tweaks
2021-01-18 19:05:55 +01:00
Veronica K. B. Olsen
92da954229 Drop the showGUI debug flag, removing test mode from beyond the main function 2021-01-18 18:55:32 +01:00
Veronica K. B. Olsen
91d96b162e Fixed and imrpoved margin calculations on GUI elements 2021-01-18 17:52:32 +01:00
Veronica K. B. Olsen
0907bf195e Bump version to 1.0.2 and update changelog 2021-01-17 21:11:51 +01:00
Veronica K. B. Olsen
f30b14a3da Merge branch 'main' into dev 2021-01-17 20:58:15 +01:00
Veronica K. B. Olsen
2030793a02 Latest release notes check should use hex version number instead of string version number 2021-01-17 20:52:34 +01:00
Veronica K. Berglyd Olsen
d09f561ef6 Merge pull request #563 from vkbo/source_code_maintenance
Source code maintenance
2021-01-16 18:14:38 +01:00
Veronica K. B. Olsen
2d1bede57e Fix test file header titles 2021-01-16 18:10:47 +01:00
Veronica K. B. Olsen
a947ec10e4 Move test files into subfolders with similar structure as source code 2021-01-16 17:59:29 +01:00
Veronica K. B. Olsen
fd04f94b76 Also update the newest test 2021-01-16 17:55:11 +01:00
Veronica K. B. Olsen
6881446e67 Merge branch 'dev' into source_code_maintenance 2021-01-16 17:53:58 +01:00
Veronica K. B. Olsen
bd0a9952ff Merge branch 'main' into dev 2021-01-16 17:53:13 +01:00
Veronica K. B. Olsen
c35255b82b Merge branch 'file_headers' into source_code_maintenance 2021-01-16 17:51:32 +01:00
Veronica K. B. Olsen
5e71e7d04d Add license header to test files 2021-01-16 17:50:14 +01:00
Veronica K. B. Olsen
cdf3c62d17 Reformat and update the source file header docstrings 2021-01-16 17:41:40 +01:00
Veronica K. Berglyd Olsen
e7e2176e64 Merge pull request #561 from vkbo/issue560_window_title
Issue #560: Window Title
2021-01-15 19:44:45 +01:00
Veronica K. B. Olsen
ecb9e92c48 Clear statusbar on new project, and change colors of saved indicators on light desktop 2021-01-15 19:27:19 +01:00
Veronica K. B. Olsen
053c2eb379 Set window title after new project is created, and also automatically call close if a project is open. 2021-01-15 10:47:50 +01:00
Veronica K. B. Olsen
bde2810c08 Clear window title when closing a project 2021-01-15 10:40:41 +01:00
Veronica K. B. Olsen
692159219e Fix an issue with generated files in test projects in the test suite 2021-01-15 10:40:19 +01:00
Veronica K. Berglyd Olsen
71b194cbcb Merge pull request #555 from vkbo/project_details
Project Details Dialog
2021-01-14 20:14:22 +01:00
Veronica K. B. Olsen
fb81c7e8e0 Minimal docs update, and add test for Project Details 2021-01-14 20:09:18 +01:00
Veronica K. B. Olsen
84878315d5 Minor GUI tweaks to Project Details and related items 2021-01-14 18:58:11 +01:00
Veronica K. B. Olsen
1bd675cce9 Merge branch 'dev' into project_details 2021-01-14 18:47:37 +01:00
Veronica K. B. Olsen
e77a0a9385 Merge branch 'main' into dev 2021-01-14 18:47:14 +01:00
Veronica K. Berglyd Olsen
d63da05e87 Merge pull request #559 from vkbo/fix_clear_treemeta
Backport from 1.1: clear project tree meta panel on close
2021-01-14 18:45:36 +01:00
Veronica K. B. Olsen
dece58faf6 Backport from 1.1: clear project tree meta panel on close 2021-01-14 18:36:39 +01:00
Veronica K. B. Olsen
0bfc166899 Added a few buttons below the project tree now that the tabs make room for it 2021-01-14 18:31:27 +01:00
Veronica K. B. Olsen
3bc8006028 Some minor improvements to the Project Detals dialog 2021-01-13 23:52:48 +01:00
Veronica K. B. Olsen
f6b7a35c81 Add some more unicode constants and rename thin non-breaking space variable 2021-01-13 23:52:09 +01:00
Veronica K. B. Olsen
5f17b28e05 Remove old details panel in Project Settings 2021-01-13 23:51:24 +01:00
Veronica K. B. Olsen
138099f11d Merge branch 'dev' into project_details 2021-01-11 21:21:16 +01:00
Veronica K. B. Olsen
beb425bbd0 Merge branch 'main' into dev 2021-01-11 21:19:56 +01:00
Veronica K. Berglyd Olsen
b5631aa1df Merge pull request #558 from vkbo/index_note_bug
Duplicate index entry issue
2021-01-11 21:16:14 +01:00
Veronica K. B. Olsen
2958881343 Fix issue with changing novel doc to note before indexing which produces duplicate entry 2021-01-11 21:05:55 +01:00
Veronica K. B. Olsen
981e26e1b6 Use actual novel word count in project details, and update index test 2021-01-11 21:02:45 +01:00
Veronica K. B. Olsen
b5e11f2303 Added more info to the forst tab of the Project Details dialog 2021-01-11 19:47:42 +01:00
Veronica K. Berglyd Olsen
6a159aa631 Merge pull request #557 from vkbo/docs_spelling
Spelling, typo, and wording update of the docs
2021-01-10 18:56:53 +01:00
Veronica K. B. Olsen
4b14a4bc50 Extend the texhnical doc to cover project meta data and cache 2021-01-10 18:52:23 +01:00
Veronica K. B. Olsen
2ca4b15154 Fix typos, grammars and improve wording of the docs 2021-01-10 18:30:58 +01:00
Veronica K. Berglyd Olsen
e02d602341 Merge pull request #553 from vkbo/release_1.0.1
Release 1.0.1
2021-01-10 16:04:16 +01:00
Veronica K. B. Olsen
8d218db35f Project Details page Overview populated 2021-01-10 15:54:36 +01:00
Veronica K. B. Olsen
f96d78e9b8 Contents tab now fully working 2021-01-10 15:09:34 +01:00
Veronica K. B. Olsen
28dd7e4ca7 Add Chapters tab to Project Details tool 2021-01-10 00:14:03 +01:00
Veronica K. B. Olsen
14a0e6bd6e Allow indexing of untitled pages, and add a ToC function to the index class 2021-01-10 00:13:26 +01:00
Veronica K. B. Olsen
f2b2952909 Added heading level 0 icon 2021-01-09 23:52:07 +01:00
Veronica K. B. Olsen
adc82bea85 Merge branch 'dev' into project_details 2021-01-09 22:25:57 +01:00
Veronica K. B. Olsen
778adc2f39 Merge branch 'main' into dev 2021-01-09 21:42:18 +01:00
Veronica K. B. Olsen
a92895d09d Update changelog and release notes 2021-01-09 20:40:09 +01:00
Veronica K. B. Olsen
dfb66cc41f Merge branch 'main' into release_1.0.1 2021-01-09 20:30:59 +01:00
Veronica K. Berglyd Olsen
065180e86c Merge pull request #554 from vkbo/doc_modified
Doc and Project Modified Status
2021-01-09 20:29:38 +01:00
Veronica K. B. Olsen
73cd7f7513 Improve doc changed checking and some code cleanup 2021-01-09 20:26:05 +01:00
Veronica K. B. Olsen
e2d5534959 Some minor code cleanup and redundant code removed 2021-01-09 20:21:32 +01:00
Veronica K. B. Olsen
a6cbdfc559 Fix initial setting of project word count 2021-01-09 20:07:09 +01:00
Veronica K. B. Olsen
7c643ea698 Make sure document edit status is not set on non-text changes 2021-01-09 19:53:42 +01:00
Veronica K. B. Olsen
39be3d0958 Merge branch 'main' into dev 2021-01-09 15:33:03 +01:00
Veronica K. B. Olsen
e693141f50 Bumped version to 1.0.1 and updated changelog 2021-01-07 22:31:58 +01:00
Veronica K. Berglyd Olsen
927dad4ff5 Merge pull request #552 from vkbo/edit_item_fix
Item Editor fixes
2021-01-07 21:38:47 +01:00
Veronica K. B. Olsen
885caa52db Code cleanup in the Item Settings constructor 2021-01-07 21:15:03 +01:00
Veronica K. B. Olsen
88776b4e00 Fix max length bug in Item Editor and let input boxes expand with dialog width 2021-01-06 22:09:20 +01:00
Veronica K. B. Olsen
8b963f3fe4 Use new novel class list to select status or importance list in Item Editor 2021-01-06 22:08:34 +01:00
Veronica K. B. Olsen
4a4ac1d6c8 Add a new constants class named nwLists 2021-01-06 21:53:42 +01:00
Veronica K. Berglyd Olsen
b5eef748b4 Merge pull request #551 from vkbo/install_instructions
Install instructions
2021-01-05 00:02:37 +01:00
Veronica K. B. Olsen
6ebe235dc3 Rewritten "Getting Started" section in the documentation 2021-01-04 23:58:57 +01:00
Veronica K. B. Olsen
bbde3159bb Updated install intructions in readme 2021-01-04 23:45:47 +01:00
Veronica K. B. Olsen
7e65aea6d9 Connected new dialog to menu 2021-01-03 21:46:53 +01:00
Veronica K. B. Olsen
e377675897 Added basic project details dialog 2021-01-03 18:14:00 +01:00
Veronica K. Berglyd Olsen
c3d40c9fb9 Merge pull request #538 from vkbo/novel_tab
Novel Tree Tab [v1.1]
2021-01-03 17:23:25 +01:00
Veronica K. B. Olsen
5efc61b155 Updated changelog 2021-01-03 17:21:06 +01:00
Veronica K. B. Olsen
323ab5498b Merge branch 'dev' into novel_tab 2021-01-03 17:17:30 +01:00
Veronica K. B. Olsen
b6e18e70bc Merge branch 'main' into dev 2021-01-03 17:14:16 +01:00
Veronica K. Berglyd Olsen
1496d9d931 Merge pull request #550 from vkbo/update_status
Update status of novelWriter to stable, from beta
2021-01-03 17:00:52 +01:00
Veronica K. B. Olsen
e0e35f5abf Update status of novelWriter to stable, from beta 2021-01-03 16:47:30 +01:00
Veronica K. B. Olsen
0b7e4d594e Fix a minor issue in the outline details class 2021-01-02 22:34:52 +01:00
Veronica K. B. Olsen
1bdf0b5500 Make index dictionaries internal 2021-01-02 22:28:30 +01:00
Veronica K. B. Olsen
acb6f1fc87 Add novel data extraction function to index 2021-01-02 22:22:05 +01:00
Veronica K. B. Olsen
a57e8f3a5d Remove GUI block in test 2021-01-02 22:05:17 +01:00
Veronica K. B. Olsen
4cb86b76e8 Add test of novel tree 2021-01-02 22:04:25 +01:00
Veronica K. B. Olsen
24f9511726 Prevent items from ending up in the wrong order in outline and novel tree 2021-01-02 22:04:08 +01:00
Veronica K. B. Olsen
e4d160ee0b Make novel structure function in index class an iterable function instead 2021-01-02 21:37:46 +01:00
Veronica K. B. Olsen
21d91193a2 Keep project tree and outline tree in sync 2021-01-02 17:33:53 +01:00
Veronica K. B. Olsen
4d7f925c5a Added timestamp to project tree, and made some class variables internal in various classes 2021-01-02 16:57:12 +01:00
Veronica K. B. Olsen
ad5f3f2450 Merge branch 'dev' into novel_tab 2021-01-02 13:18:08 +01:00
Veronica K. B. Olsen
a84fc734ff Merge branch 'main' into dev 2021-01-02 13:17:39 +01:00
Veronica K. B. Olsen
3d5a5e4d86 Selecting outline item should also select it in project tree 2021-01-01 15:08:11 +01:00
Veronica K. B. Olsen
2d14a74ec2 Merge branch 'main' into dev 2020-12-21 21:51:35 +01:00
Veronica K. B. Olsen
942a604b5b Merge branch 'main' into novel_tab 2020-12-21 21:51:17 +01:00
Veronica K. B. Olsen
e5ea8074d2 Copy the mouse press behaviour from the project tree to the novel tree 2020-12-20 17:18:54 +01:00
Veronica K. B. Olsen
2779c8e69f Use build time to update novel tree, and restore last selected item on tab change 2020-12-20 16:50:01 +01:00
Veronica K. B. Olsen
1d12014399 The basic functionality of the novel tree view is now in place 2020-12-20 16:27:42 +01:00
Veronica K. B. Olsen
d4b26025ed Add the basic structure for a novel tree 2020-12-20 15:50:01 +01:00
Veronica K. B. Olsen
597f177d5b Bump version for next stage of dev branch to 1.1 alpha 0 2020-12-20 14:40:25 +01:00
248 changed files with 52090 additions and 13627 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
# github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
ko_fi: jadzia626
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

24
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,24 @@
<!--
Please check the following before you make a pull request:
* The branch you are making the pull request from (in your own fork) has a unique and descriptive
name. Do not make a pull request directly from your copy of `main`.
* If you are submitting translation files, only submit the files that you have added translations
to, not the other .ts files that may have been updated in the process.
* Make sure your contribution follows the style guide and other requirements mentioned in the
CONTRIBUTING.md file in the repository.
* Fill in the Summary section below, and if relevant, mention the issue numbers related to the PR.
-->
**Summary:**
**Related Issue(s):**
**Reviewer's Checklist:**
* [ ] The header of all files contain a reference to the repository license
* [ ] The overall test coverage is increased or remains the same as before
* [ ] All tests are passing
* [ ] All flake8 checks are passing and the style guide is followed
* [ ] Documentation (as docstrings) is complete and understandable
* [ ] Only files that have been actively changed are committed

View File

@@ -2,16 +2,18 @@ name: flake8
on:
push:
branches: [ main, dev ]
branches:
- main
pull_request:
branches: [ main, dev ]
branches:
- main
jobs:
checkSyntax:
runs-on: ubuntu-latest
steps:
- name: Python Setup
uses: actions/setup-python@v1
uses: actions/setup-python@v2
with:
python-version: 3
architecture: x64
@@ -25,5 +27,5 @@ jobs:
flake8 tests --count --select=E9,F63,F7,F82 --show-source --statistics
- name: Coding Style Violations
run: |
flake8 nw --count --max-line-length=99 --ignore E203,E221,E226,E228,E241,E251,E261,E266,E302,E305 --show-source --statistics
flake8 tests --count --max-line-length=99 --ignore E203,E221,E226,E228,E241,E251,E261,E266,E302,E305 --show-source --statistics
flake8 nw --count --max-line-length=99 --ignore E221,E226,E228,E241 --show-source --statistics
flake8 tests --count --max-line-length=99 --ignore E221,E226,E228,E241 --show-source --statistics

View File

@@ -1,34 +1,38 @@
name: Linux (3.8)
name: Linux
on:
push:
branches: [ main, dev ]
branches:
- main
pull_request:
branches: [ main, dev ]
branches:
- main
jobs:
testLinux38:
testLinux:
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
runs-on: ubuntu-latest
steps:
- name: Python Setup
uses: actions/setup-python@v2
with:
python-version: 3.8
python-version: ${{ matrix.python-version }}
architecture: x64
- name: Install Packages
- name: Install Packages (apt)
run: |
sudo apt update
sudo apt install libenchant-dev qt5-default
sudo apt install libenchant-dev qttools5-dev-tools
- name: Checkout Source
uses: actions/checkout@v2
- name: Install Dependencies
- name: Install Dependencies (pip)
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-timeout
pip install pytest-cov
pip install pytest-qt
pip install codecov
pip install -r requirements-dev.txt
- name: Run Build Commands
run: python setup.py qtlrelease sample
- name: Run Tests
run: |
export QT_QPA_PLATFORM=offscreen

View File

@@ -1,33 +0,0 @@
name: Linux (3.6)
on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]
jobs:
testLinux36:
runs-on: ubuntu-latest
steps:
- name: Python Setup
uses: actions/setup-python@v2
with:
python-version: 3.6
architecture: x64
- name: Install Packages
run: |
sudo apt update
sudo apt install libenchant-dev qt5-default
- name: Checkout Source
uses: actions/checkout@v2
- name: Install Dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-timeout
pip install pytest-qt
- name: Run Tests
run: |
export QT_QPA_PLATFORM=offscreen
pytest -v --timeout=60

View File

@@ -1,33 +0,0 @@
name: Linux (3.7)
on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]
jobs:
testLinux37:
runs-on: ubuntu-latest
steps:
- name: Python Setup
uses: actions/setup-python@v2
with:
python-version: 3.7
architecture: x64
- name: Install Packages
run: |
sudo apt update
sudo apt install libenchant-dev qt5-default
- name: Checkout Source
uses: actions/checkout@v2
- name: Install Dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-timeout
pip install pytest-qt
- name: Run Tests
run: |
export QT_QPA_PLATFORM=offscreen
pytest -v --timeout=60

View File

@@ -1,37 +0,0 @@
name: Linux (3.9)
on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]
jobs:
testLinux39:
runs-on: ubuntu-latest
steps:
- name: Python Setup
uses: actions/setup-python@v2
with:
python-version: 3.9
architecture: x64
- name: Install Packages
run: |
sudo apt update
sudo apt install libenchant-dev qt5-default
- name: Checkout Source
uses: actions/checkout@v2
- name: Install Dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-timeout
pip install pytest-cov
pip install pytest-qt
pip install codecov
- name: Run Tests
run: |
export QT_QPA_PLATFORM=offscreen
pytest -v --cov=nw --timeout=60
- name: Upload to Codecov
uses: codecov/codecov-action@v1

View File

@@ -1,19 +1,21 @@
name: macOS (3.8)
name: macOS
on:
push:
branches: [ main, dev ]
branches:
- main
pull_request:
branches: [ main, dev ]
branches:
- main
jobs:
testMac38:
testMac:
runs-on: macos-latest
steps:
- name: Python Setup
uses: actions/setup-python@v2
with:
python-version: 3.8
python-version: 3.9
architecture: x64
- name: Install Packages
run: |
@@ -24,10 +26,8 @@ jobs:
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-timeout
pip install pytest-cov
pip install pytest-qt
pip install codecov
pip install -r requirements-dev.txt
pip install pyobjc
- name: Run Tests
run: |
export QT_QPA_PLATFORM=offscreen

View File

@@ -1,19 +1,21 @@
name: Windows (3.8)
name: Windows
on:
push:
branches: [ main, dev ]
branches:
- main
pull_request:
branches: [ main, dev ]
branches:
- main
jobs:
testWin38:
testWin:
runs-on: windows-latest
steps:
- name: Python Setup
uses: actions/setup-python@v2
with:
python-version: 3.8
python-version: 3.9
architecture: x64
- name: Checkout Source
uses: actions/checkout@v2
@@ -21,10 +23,7 @@ jobs:
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-timeout
pip install pytest-cov
pip install pytest-qt
pip install codecov
pip install -r requirements-dev.txt
- name: Run Tests
run: |
pytest -v --cov=nw --timeout=60

10
.gitignore vendored
View File

@@ -7,6 +7,13 @@
*.egg-info
setup.iss
novelwriter.desktop
novelWriter.pyw
# Translations
/nw/assets/i18n/*.qm
.qmake.stash
i18n/*.qm
i18n/*.qph
# Documentation
/docs/build/
@@ -21,8 +28,10 @@ __pycache__
/nw/assets/sample.zip
/sample/cache
/sample/meta
/sample/versions
*.bak
*.lock
ToC.txt
# PyTest
/prof/
@@ -38,3 +47,4 @@ __pycache__
# Coverage
/.coverage
/coverage.*

File diff suppressed because it is too large Load Diff

View File

@@ -1,106 +1,123 @@
# Contributing
# Contributing Guide
When contributing to this repository, please first discuss the change you wish to make via the
issue tracker with the owner of this repository before making a change. If you just want to make a
minor correction, like fix a typo or similar, feel free to just make a pull request directly.
issue tracker or the discussions page with the owner of this repository. Especially if it is
regarding new features. If you just want to make a minor correction, like fix a typo or similar,
feel free to just make a pull request directly.
There is a code of conduct. Please follow it in all your interactions with the project.
The following contributions are welcome:
## Pull Request Process
* Bugfixes for new or existing bugs. Please also report new bugs in the issue tracker even if you
also provide a fix. It makes it easier to keep track of what has been fixed and when.
* New translations. You can read more about contributing translations
[here](https://github.com/vkbo/novelWriter/blob/main/i18n/README.md).
* Improvements to the documentation. Particularly if the documentation is unclear. Please don't
make any larger changes to the documentation without discussing if with the maintainer first.
* Adaptations, installation or packaging features targeting specific operating systems.
1. Make sure your code passes all tests and conforms to the style guide. You can check that the code
conforms by running `flake8` from the root of the project folder.
2. Please provide a complete description of the changes in the pull request, and a summary that can
be copied into the [CHANGELOG](CHANGELOG.md). Remember to reference any issue related by
providing the issue number.
3. Do not change the version number unless asked to do so. Version numbers are bumped in separate
release pull requests by the maintainer.
Please do not:
* Make a pull request that restructures or reformats existing code. If you think some parts of the
code could be improved, please make an issue thread or start a discussion. The same applies to
any text document in the repository.
## Pull Requests
This project follows the [OneFlow](https://www.endoflineblog.com/oneflow-a-git-branching-model-and-workflow)
model. 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 own `main`
branch.
**Note:** If your contribution is a bugfix for a specific version, please make a bugfix branch from
the tag you want the fix to be applied to, not directly from the `main` branch. This is important.
Also check the following:
* Make sure your code passes all tests and conforms to the style guide. You can check that the
code generally conforms by running the Python linting tool `flake8` from the root of the project
folder, although it doesn't check everything. The same check is also run on pull requests by the
maintainer.
* Please provide a description of the changes in the pull request under the summary section of the
pull request template, and reference any related issues by providing the issue number.
* Do not change the version number.
* Do not submit files that were not actively changed but have otherwise been modifed. This is
mostly an issue with translation files. The language tool may update all files in the `i18n`
folder.
## Code of Conduct
There is a code of conduct. Please follow it in all your interactions with the project.
### Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers
pledge to making participation in our project and our community a harassment-free experience for
everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level
of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
everyone, regardless of age, body size, disability, ethnicity, gender identity and expression,
level of experience, nationality, personal appearance, race, religion, or sexual identity and
orientation.
Please see the [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) file for the full text.
## Code Style Guide
The source code of novelWriter broadly follows the [PEP8](https://www.python.org/dev/peps/pep-0008/)
style guide , but with a few modifications and exceptions.
The source code of novelWriter broadly follows the [PEP8](https://www.python.org/dev/peps/pep-0008)
style guide, but with a few exceptions. Some key points are listed below.
### Linting with flake8
**Line Length:**
An excellent tool for checking Python code for errors and coding style is `flake8`.
The documentation is available [here](https://flake8.pycqa.org/en/latest/).
* Source code lines can extend to the upper limit of 99 characters allowed by PEP8. 79 characters
is the recommended line length in PEP8, but this is often too restrictive. 99 characters are
acceptable when that is more practical. Readability has priority. Generally, if a code statement
requires multiple lines, the lines should wrap at 79 characters if possible. If wrapping can be
avoided by going to 99, then that is generally preferrable.
* For text files, the text should be wrapped at 99 character. The exception is markdown image tags
and urls which can run past that limit.
The `setup.cfg` file in the root of this project has the following settings:
**Variable and Function Names**
* PEP8 allows for camelCase for consistency with existing code. The Qt library uses camelCase, so
the Python the source code does too.
* The exception to the above is for constants. They should always be in upper snake case, like PEP8
states.
**Spaces, Indentation and Alignment**
* Only indentation by 4 spaces is allowed.
* No trailing spaces should occur on any line in the source code, including empty lines.
* Ideally, a function should end on the same indention level as it started. Exceptions are allowed
if it makes the code easier to follow.
* Aligning operators and attributes in columns with multiple spaces is not allowed by PEP8. The
rule is relaxed a bit here. Alignment is allowed when populating large dictionaries or setting
many class attributes. It does improve readability in such cases, but should not be overused.
### Linting with `flake8`
A good tool for checking Python code for errors and code style is `flake8`. The documentation is
available [here](https://flake8.pycqa.org/en/latest/).
The `setup.cfg` file in the root of this project has the following settings for `flake8` that
matches the above code style:
```conf
[flake8]
ignore = E203,E221,E226,E228,E241,E251,E261,E266,E302,E305
ignore = E221,E226,E228,E241
max-line-length = 99
exclude = docs/*
```
The command line equivalent, with reporting, is:
```bash
flake8 . --count --ignore E203,E221,E226,E228,E241,E251,E261,E266,E302,E305 --max-line-length=99 --show-source --statistics
flake8 . --count --ignore E221,E226,E228,E241 --max-line-length=99 --show-source --statistics
```
Passing this check is required before contributions are merged into the `main` branch. This is
checked automatically when you make a pull request. You can run the `flake8` command locally to
check beforehand. The full command will give you a detailed description of the code lines that do
not conform to the standard.
Passing this check is required before contributions are merged. This is checked automatically when
you make a pull request. You can run the `flake8` command locally to check beforehand. The full
command will give you a detailed description of the code lines that do not conform to the standard.
## Ignored Errors
Two of the ignored errors are due to the relaxed restriction on column alignment, these are the
E221 and E241 error codes.
Some errors are ignored in novelWriter, for various reasons. In addition, novelWriter uses camelCase
function and variable names due to this being the standard for the Qt libraries, and also because of
the author's personal preferences.
The reason behind the other ignored error codes are listed below. Many of them are due to PEP8 not
permitting column alignment as opposed to many other coding styles. I find them useful in regions of
bulk value assignments. There's a reason why tables are more readable than lists. They should be
used sparingly though.
The ignored errors are all `pycodestyle` errors, and they are documented
[here](https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes).
**E203:** whitespace before ‘:’
**Reason:** Column alignment. It is natural to align dictionary columns along the `:` character.
**E221:** multiple spaces before operator
**Reason:** Column alignment.
**E226:** missing whitespace around arithmetic operator
**Reason:** This doesn't actually follow the PEP8 recommendation of grouping longer equations by
operator precedence like `2*a + 3*b` instead of `a * a + 3 * b`. Generally, don't use spaces around
`*`, `/` and `**`, but do use spaces around `+` and `-`. For appending strings, the spaces can be
dropped. Don't use the `+` operator for appending multiple strings. Use formatting instead.
**E228** missing whitespace around modulo operator
**Reason:** See reason for E226. Formatting `%` like `/` and `*` should be possible.
**E241:** multiple spaces after ‘,’
**Reason:** Column alignment.
**E251:** unexpected spaces around keyword / parameter equals
**Reason:** Column alignment.
**E261:** at least two spaces before inline comment
**Reason:** With syntax highlighting, this one doesn't make much sense.
**E266:** too many leading ‘#’ for block comment
**Reason:** In the source multiple `#`s is sometimes used to indicate importance or heading level,
like markdown headers.
**E302:** expected 2 blank lines, found 0
**Reason:** Applies to classes. Instead, end classes with a comment like `# END Class ClassName` to
make it easier to see which class just ended. The double line break is then redundant.
**E305:** expected 2 blank lines after end of function or class
**Reason:** Instead, _always_ end a function with a `return`, preferably indented at function
level. The end of the function is then clear.
The code E226 is ignored becuse it doesn't actually follow the
[PEP8 recommendation](https://www.python.org/dev/peps/pep-0008/#other-recommendations)
of grouping longer equations by operator precedence like `2*a + 3*b` instead of `a * a + 3 * b`.
Generally, don't use spaces around `*`, `/` and `**`, but _do_ use spaces around `+` and `-`.
The same applies to the modulo operator `%`, hence E228 is also ignored.

42
CREDITS.md Normal file
View File

@@ -0,0 +1,42 @@
# Credits
## Main Developer
* Veronica Berglyd Olsen (@vkbo)
## Main Contributors
* Concept: Marian Lückhof (@Number042)
* Internationalisation: Bruno Meneguello (@bkmeneguello)
## Translations
* French: Jan Lüdke (@jyhelle)
* Norwegian: Veronica Berglyd Olsen (@vkbo)
* Portuguese: Bruno Meneguello (@bkmeneguello)
* Simplified Chinese: Qianzhi Long (@longqzh)
## Libraries
The following libraries are dependencies of novelWriter:
* Qt5 by [Qt Company](https://www.qt.io/)
* PyQt5 by [Riverbank Computing](https://www.riverbankcomputing.com/software/pyqt/)
* lxml by [Martijn Faassen](https://lxml.de/)
* Enchant by [Dom Lachowicz](https://abiword.github.io/enchant/)
* PyEnchant by [Dimitri Merejkowsky](https://pyenchant.github.io/pyenchant/)
## Assets
Some of the assets bundled with novelWriter were adapted from the following sources:
* Typicons icons by Stephen Hutchings (CC BY-SA 4.0)
* Cantarell font by Dave Crossland (OPEN FONT LICENSE Version 1.1)
* Tomorrow syntax themes by Chris Kempson (MIT License)
* Owl syntax themes by Sarah Drasner (MIT License)
* Solarized themes by Ethan Schoonover, added by @nullbasis (MIT License)
## Special Mentions
Additional thanks to @johnblommers who was an early user and who has provided a lot of very useful
feedback over the years.

View File

@@ -1,4 +1,6 @@
include setup.py
include LICENSE.md
include CHANGELOG.md
recursive-include setup *
recursive-include nw/assets *
recursive-include sample *.nwx *.nwd

389
README.md
View File

@@ -1,293 +1,220 @@
# novelWriter
[![Linux (3.6)](https://github.com/vkbo/novelWriter/workflows/Linux%20(3.6)/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions)
[![Linux (3.7)](https://github.com/vkbo/novelWriter/workflows/Linux%20(3.7)/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions)
[![Linux (3.8)](https://github.com/vkbo/novelWriter/workflows/Linux%20(3.8)/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions)
[![Linux (3.9)](https://github.com/vkbo/novelWriter/workflows/Linux%20(3.9)/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions)
[![Windows (3.8)](https://github.com/vkbo/novelWriter/workflows/Windows%20(3.8)/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions)
[![macOS (3.8)](https://github.com/vkbo/novelWriter/workflows/macOS%20(3.8)/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions)
[![Linux](https://github.com/vkbo/novelWriter/actions/workflows/test_linux.yml/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions/workflows/test_linux.yml)
[![Windows](https://github.com/vkbo/novelWriter/actions/workflows/test_win.yml/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions/workflows/test_win.yml)
[![macOS](https://github.com/vkbo/novelWriter/actions/workflows/test_mac.yml/badge.svg?branch=main)](https://github.com/vkbo/novelWriter/actions/workflows/test_mac.yml)
[![flake8](https://github.com/vkbo/novelWriter/workflows/flake8/badge.svg)](https://github.com/vkbo/novelWriter/actions)
[![codecov](https://codecov.io/gh/vkbo/novelWriter/branch/main/graph/badge.svg)](https://codecov.io/gh/vkbo/novelWriter)
[![docs](https://readthedocs.org/projects/novelwriter/badge/?version=latest)](https://novelwriter.readthedocs.io/en/latest/?badge=latest)
[![docs](https://readthedocs.org/projects/novelwriter/badge/?version=latest)](https://novelwriter.readthedocs.io/en/latest/?badge=latest)
[![release](https://img.shields.io/github/v/release/vkbo/novelwriter)](https://github.com/vkbo/novelWriter/releases)
[![pypi](https://img.shields.io/pypi/v/novelwriter)](https://pypi.org/project/novelWriter)
[![python](https://img.shields.io/pypi/pyversions/novelwriter)](https://pypi.org/project/novelWriter)
<img align="left" style="margin: 0 16px 4px 0;" src="https://raw.githubusercontent.com/vkbo/novelWriter/main/setup/icons/scaled/icon-novelwriter-96.png">
novelWriter is a Markdown-like text editor designed for writing novels and larger projects of many
smaller plain text documents. It uses its own flavour of Markdown that supports a meta data syntax
for comments, synopsis, and cross-referencing between files. It's designed to be a simple text
editor that allows for easy organisation of text files and notes, built on plain text files for
robustness.
novelWriter is a plain text editor designed for writing novels assembled from many smaller text
documents. It uses a minimal formatting syntax inspired by Markdown, and adds a meta data syntax
for comments, synopsis, and cross-referencing. It's designed to be a simple text editor that allows
for easy organisation of text and notes, using human readable text files as storage for robustness.
The plain text storage is suitable for version control software, and also well suited for file
synchronisation tools. The core project structure is stored in a project XML file. Other meta data
is primarily saved in JSON files.
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 primarily saved as
JSON files.
The full documentation is available at
[novelwriter.readthedocs.io](https://novelwriter.readthedocs.io/).
The contributing guide is available in [CONTRIBUTING](CONTRIBUTING.md).
### Development Status
The application is still under initial development, but all core features have now been added.
The core functionality has been in place for a while, and novelWriter is being used for writing
projects by the author and collaborators.
No new major features will be added at this time, until the application is stable. Until then,
novelWriter is in a _beta_ state. Please report any issues you encounter via the repository's issue
tracker.
You should be able to use novelWriter for real projects, but as with all software, please make
regular backups of your data. There is a built in backup feature that can pack the entire project
into a zip file each time the main window or the project is closed. Please check the documentation
for further details.
The full documentation is available on [readthedocs.io](https://novelwriter.readthedocs.io).
The full credits are listed in [CREDITS.md](https://github.com/vkbo/novelWriter/blob/main/CREDITS.md).
## Implementation
The application is written in Python 3 using Qt5 via PyQt5. It is developed on Linux, but it should
in principle work fine on other operating systems as well as long as dependencies are met. The unit
tests are run on the latest versions of Ubuntu Linux, Windows Server and macOS.
The application is written in Python 3 (3.6+) using Qt5 and PyQt5 (5.3+). It is developed on Linux,
but should in principle work fine on other operating systems as well as long as dependencies are
met. It is regularly tested on Debian and Ubuntu Linux, Windows, and macOS.
## Project Contributions
# Installing and Running
Please don't make feature pull requests without first having discussed them with the maintainer.
You can make a feature request in the issue tracker, or if the idea isn't fully formed, start a
discussion on the discussion page. Please also don't make pull requests to reformat or rewrite
existing code unless there is a very good reason for doing so.
novelWriter is available on [pypi.org](https://pypi.org/project/novelWriter/), and can be installed
with:
```bash
pip install novelwriter
```
Fixes and patches are welcome. Contributions related to packaging and installing novelWriter will
also be appreciated, but please make an issue or a discussion topic first. Before contributing any
code, please read the full [Contributing Guide](https://github.com/vkbo/novelWriter/blob/main/CONTRIBUTING.md).
To upgrade an existing installation, use:
```bash
pip install --upgrade novelwriter
```
New translations are always welcome. Please read the additional
[instructions](https://github.com/vkbo/novelWriter/blob/main/i18n/README.md) for further details.
Dependencies are installed automatically, but can generally be installed with:
```bash
pip install -r requirements.txt
```
## Key Features
Below are some brief instructions on how to get started on different operating systems.
Some key features of novelWriter are listed below. Consult the
[documentation](https://novelwriter.readthedocs.io) for more information.
### Formatting Codes
## Linux
Although novelWriter is a plain text editor, it uses a Markdown-like syntax to allow for a minimal
set of formatting that is useful for the specific task of writing novels.
Either download the source, or install with pip.
| Code | Usage | Description |
|------------|----------|-------------|
| `#` | Prefix | Headings level 1 to 4. |
| `_` | Wrapped | Emphasised (italicised) text. |
| `**` | Wrapped | Strongly emphasised (bold) text. |
| `~~` | Wrapped | Strikethrough text. |
| `%` | Prefix | A comment; does not count towards the word count.<sup>1</sup> |
| `@` | Prefix | The following text is parsed as a keyword/value command for meta data. |
| `>` | Prefix | The paragraph is indented one tab width from the left.<sup>2</sup> |
| `<` | Suffix | The paragraph is indented one tab width from the right.<sup>2</sup> |
| `>>` | Prefix | The paragraph is right-aligned.<sup>2</sup> |
| `<<` | Suffix | The paragraph is left-aligned.<sup>2</sup> |
| `>>`, `<<` | Wrapped | The paragraph is centred.<sup>2</sup> |
If you run from source, install the dependencies via pip, or directly from the OS repo. There are
very few dependencies, and they should be available in the standard repo. The Python packages
needed are `pyqt5`, `lxml` and `pyenchant`.
<sup>1</sup> If the first word of the comment is `synopsis:`, the comment is indexed and treated as the
synopsis for the section of text where it occurs. These synopsis comments can be used to build an
outline and exported to external documents.
### Installing from Source
<sup>2</sup> The indent and alignment codes are available from version 1.4.
You can also install novelWriter from source with:
```bash
python3 setup.py sample
sudo python3 setup.py install
sudo python3 setup.py launcher
```
In additions:
The last line will install the application icons and set up a launcher for novelWriter. The method
uses hardcoded paths, so it may or may not work for your Linux distro. If you have any issues,
please submit a ticket so the script can be tuned.
* A variety of thin and non-breaking spaces are supported. Some of them depend on the system
running at least Qt 5.9. Earlier versions of Qt will unfortunately strip them out when saving.
* Tabs can be used in the text, and should be properly aligned in both editor and viewer. This can
be used to make simple tables and lists. Note that for HTML exports, most browsers will treat a
tab as a space, so it may not show up like expected. Open Document exports should produce the
expected result.
The script may prompt you to choose which executable to configure if it finds more than one.
### Export Formats
### Running from Source
If you want to run directly from the source, the application can be started with:
```bash
./novelWriter.py
```
You can also create a launcher for running directly from source with:
```bash
python3 setup.py xdg-install
```
This will install the launcher and icons for the current user. To install them system-wide, run the
above command with `sudo` or as root.
For more install options, see [Build and Install novelWriter](setup/README.md).
## macOS
These instructions assume you're using brew, and have Python and pip set up. If not, see the
[brew docs](https://docs.brew.sh/Homebrew-and-Python) for help.
Main requirements are installed via the requirements file. You also need to install the `pyobjc`
package on macOS, so you must run:
```bash
pip3 install --user -r requirements.txt
pip3 install --user pyobjc
```
For spell checking you may also need to install the enchant package. It comes with a lot of default
dictionaries.
```bash
brew install enchant
```
## Windows
On Windows, you may first need to install Python. See the [python.org](https://www.python.org/)
website for download packages. It is recommended that you install the latest version of Python 3.8.
To install dependencies, run:
```bash
pip install --user -r requirements.txt
```
**Note:** On Windows, make sure Python3 is in your PATH if you want to launch novelWriter from
command line. You can also right click the `novelWriter.py` file, create a shortcut, then right
click again, select "Properties" and change the target to your python executable and
`novelWriter.py`.
It should look something like this:
```
C:\...\AppData\Local\Programs\Python\Python38\python.exe novelWriter.py
```
You can also run the `make.py` script to generate a single executable, or an installer.
See [Build and Install novelWriter](setup/README.md) for more details.
## Package Versions
Exporting to Markdown requires PyQt/Qt 5.14. There are no known minimum for `lxml`, but the code
was originally written with 4.2. The optional spell check library must be at least 3.0.0 to work
with Windows 64 bit systems. On Linux, 2.0.0 also works fine.
If no external spell checking tool is installed, novelWriter will use a basic spell checker based
on standard Python package `difflib`. Currently, only English dictionaries are available for this
spell checker, but more can be added to the `nw/assets/dict` folder. See the
[README](nw/assets/dict/README.md) file in that folder for how to generate more dictionaries. Note
that the difflib-based option is both slow and limited.
## Debugging
If you need to debug novelWriter, you must run it from command line. It takes a few parameters,
which can be listed with the switch `--help`. The `--info`, `--debug` or `--verbose` flags are
particularly useful for increasing logging output for debugging.
# Key Features
Some features of novelWriter are listed below. Consult the documentation for more information.
### Markdown Flavour
novelWriter is _not_ a full-feature Markdown editor. It allows for a minimal set of formatting
needed for writing text documents for novels. These are currently limited to:
* Headings level 1 to 4 using the `#` syntax only.
* Emphasised and strong text. These are rendered as italicised and bold.
* Strikethrough text.
* Hard line breaks using two or more spaces at the end of a line.
That is it. Features not supported in the editor are also not exported when using the export tool.
In addition, novelWriter adds the following, which is otherwise not supported by Markdown:
* A line starting with `%` is treated as a comment and not rendered on exports unless requested.
Comments do not count towards the word count. If the first word of the comment is `synopsis:`,
the comment is indexed and treated as the synopsis for the section of text under the same header.
These synopsis comments can be used to build an outline and exported to external documents.
* A set of meta data keyword/values starting with the character `@`. This is used for tagging
and inter-linking documents, and can be used to generate a project outline.
* Non-breaking spaces are supported as long as your system is using at least Qt 5.9. For earlier
version, non-breaking spaces are converted to normal spaces when saving the document. This is
done by the Qt library.
* Thin spaces are also supported, as well as non-breaking thin spaces, with the same library
version restriction as above.
* Tabs can be used in the text, and should be properly aligned. The width of a tab in pixels can be
changed in Preferences. Note that for the HTML format, most browsers will treat a tab as a space,
so it may not show up like expected. If you import the HTML file to Libre Office, for instance,
they should appear as expected.
The core export format of novelWriter is HTML5. You can also export the entire project as a single
novelWriter Markdown-flavour document. In addition, other exports to Open Document, PDF, and plain
text is offered through the Qt library, although with limitations to formatting.
The HTML format is well suited for file conversion tools and import into other text editors.
The core export formats of novelWriter are Open Document and HTML5. Open Document is an open
standard for office type documents that is supported by most office applications. See
[Open Document > Application Support](https://en.wikipedia.org/wiki/OpenDocument#Application_support)
for more details.
You can also export the entire project as a single novelWriter-flavour document. These can later be
imported again into novelWriter. In addition, printing and export to PDF is offered through the Qt
library, although with limitations to formatting.
### Colour Themes
The editor has syntax highlighting for the features it supports, and includes a set of different
syntax highlighting themes. The GUI also has an optional dark theme in addition to the default
system theme.
New themes can easily be added to the `nw/assets/themes` folder. Have a look in the existing
folders for examples of how to define the colours.
syntax highlighting themes. Optional GUI themes are also available, including dark themes.
### Easy Organising of Project Files
The structure of the project is shown on the left hand side of the main GUI. Project files are
The structure of the project is shown on the left hand side of the main window. Project files are
organised into root folders, indicating what class of file they are. The most important root folder
is the Novel folder, which contains all of the files that makes up the finished novel. Each root
folder can have subfolders. Folders have no impact on the final project structure, they are purely
tools for organising the files in whatever way the user needs.
is the `Novel` folder, which contains all of the files that make up the novel itself. Each root
folder can have subfolders. Subfolders have no impact on the final project structure, they are
there for you to organise your files in whatever way you want.
The editor supports four levels of headings, which determines what level the following text belongs
The editor supports four levels of headings, which determine what level the following text belongs
to. Headings of level one signify a book or partition title. Headings of level two signify the
start of a new chapter. Headings of level three signify the start of a new scene. Headings of level
four can be used internally in each scene to separate sections.
four can be used internally in each scene to create separate sections.
Each novel file can be assigned a layout format, which shows up as a flag next to the item in the
project tree. These are mostly to help the user track what they contain, but they also have some
impact on the format of the exported document. See the documentation for further details.
impact on the layout of the exported document. See the
[documentation](https://novelwriter.readthedocs.io) for further details.
### Project Notes
#### Project Notes
Supporting note files can be added for the story plot, characters, locations, story timeline, etc.
These have their separate root folders. These are optional files.
Supporting notes can be added for the story plot, characters, locations, story timeline, etc. These
have their separate root folders and are optional to use.
### Visualisation of Story Elements
The different notes can be assigned tags, which other files can refer back to using the `@` meta
keywords. This information can be used to display an outline of the story, showing where each scene
connects to the plot, and which characters, etc. occur in them. In addition, the tags themselves
are clickable in the document view pane, and control-clickable in the editor. They make it possible
to quickly navigate between the documents while editing.
The different notes can be assigned tags, which other files can refer back to using `@`-prefixed
meta keywords. This information can be used to display an outline of the story, showing where each
scene connects to the plot, and which characters, etc. occur in them. In addition, the tags
themselves are clickable in the document view pane, and control-clickable in the editor. They make
it possible to quickly navigate between the documents while writing.
## Standard Installation
For a regular installation, it is recommended that you download one of the minimal zip files from
the [Releases](https://github.com/vkbo/novelWriter/releases) page or the
[novelwriter.io](https://novelwriter.io/) website.
The [documentation](https://novelwriter.readthedocs.io/) has detailed install instructions for
[Linux](https://novelwriter.readthedocs.io/en/latest/setup_linux.html),
[Windows](https://novelwriter.readthedocs.io/en/latest/setup_windows.html), and
[macOS](https://novelwriter.readthedocs.io/en/latest/setup_mac.html).
They are pretty straightforward.
## Running from Source
If you want to run novelWriter directly from the source code, you must run the `novelWriter.py`
file from command line.
**Note:** You may need to replace `python` with `python3` and `pip` with `pip3` in the instructions
below on some systems. You may also want to add the `--user` flag for `pip` to install in your user
space only.
### Dependencies
Dependencies can generally be installed from PyPi with:
```bash
pip install -r requirements.txt
```
### Additional Steps for Linux
On Linux, you can most likely find the dependencies in your distribution's repository. On Ubuntu
and Debian, run:
```bash
sudo apt install python3-pyqt5 python3-lxml python3-enchant
```
If you want to set up a launcher and icons on Linux, you can run:
```bash
python setup.py xdg-install
```
### Additional Steps for macOS
First, make sure you have properly set up Python3 with Homebrew. If not, check their
[documentation](https://docs.brew.sh/Homebrew-and-Python).
In addition, the following steps are necessary to install all dependencies:
```bash
brew install enchant
pip3 install --user -r requirements.txt
pip3 install --user pyobjc
```
### Additional Steps for Windows
Windows does not by default come with Python installed. If you haven't installed it already, get it
from [python.org/downloads](https://www.python.org/downloads/). Remember to select "Add Python to
PATH" during the installation.
The script `windows_install.bat` in the `setup` folder can be used to create desktop and start menu
icons for novelWriter. The script will also install dependencies for you from PyPi.
### Internationalisation
If you install from source, you must build the translation files yourself if you want to switch to
a different GUI language than British English. This requires that you have the Qt translation
framework installed. Check the specific instruction in the README in the `i18n` source folder for
how to build the translation files.
## Debugging
If you need to debug novelWriter, you must run it from the command line. It takes a few parameters,
which can be listed with the switch `--help`. The `--info`, `--debug` or `--verbose` flags are
particularly useful for increasing logging output for debugging.
## Licenses
This is Open Source software, and novelWriter is licensed under GPLv3. See the
[GNU General Public License website](https://www.gnu.org/licenses/gpl-3.0.en.html) for more
details, or consult the [LICENSE](LICENSE.md) file.
details, or consult the [LICENSE](https://github.com/vkbo/novelWriter/blob/main/LICENSE.md) file.
Bundled assets have the following licenses:
Bundled assets and their licenses are listed in
[CREDITS](https://github.com/vkbo/novelWriter/blob/main/CREDITS.md).
* The Typicon-based icon themes by Stephen Hutchings are licensed under
[CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/). The icons have been altered in
size and colour for use with novelWriter, and some additional icons added. The original icon set
is available at
[stephenhutchings/typicons.font](https://github.com/stephenhutchings/typicons.font).
* The Cantarell font by Dave Crossland is licensed under
[OPEN FONT LICENSE Version 1.1](http://scripts.sil.org/OFL).
It is available at [Google Fonts](https://fonts.google.com/specimen/Cantarell).
* The Tomorrow syntax themes use colour schemes taken from Chris Kempson's collection of code
editor themes, licensed with the
[MIT License](https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md),
and the main repo is available at
[chriskempson/tomorrow-theme](https://github.com/chriskempson/tomorrow-theme).
* Likewise, the Owl syntax themes use colours from Sarah Drasner's code editor themes, licensed
with the [MIT License](https://github.com/sdras/night-owl-vscode-theme/blob/master/LICENSE), and
the main repo is available at
[sdras/night-owl-vscode-theme](https://github.com/sdras/night-owl-vscode-theme).
## Screenshot
## Screenshots
**novelWriter with default system theme:**
![Screenshot 1](https://raw.githubusercontent.com/vkbo/novelWriter/main/docs/source/images/screenshot_default.png)

View File

@@ -21,3 +21,7 @@
white-space: normal !important;
vertical-align: text-top;
}
pre span.go {
color: #333333 !important;
}

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
@@ -25,9 +24,9 @@ copyright = "2018–2021, Veronica Berglyd Olsen"
author = "Veronica Berglyd Olsen"
# The short X.Y version
version = "1.0"
version = "1.4"
# The full version, including alpha/beta/rc tags
release = "1.0"
release = "1.4"
# -- General configuration ---------------------------------------------------
@@ -47,7 +46,6 @@ language = None
exclude_patterns = []
pygments_style = None
# -- Options for HTML output -------------------------------------------------
html_theme = "sphinx_rtd_theme"
@@ -75,13 +73,11 @@ html_css_files = [
# "searchbox.html"]``.
# html_sidebars = {}
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = "novelWriterDoc"
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
@@ -110,7 +106,6 @@ latex_documents = [(
author, "manual"
)]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
@@ -119,7 +114,6 @@ man_pages = [(
master_doc, "novelwriter", "novelWriter Documentation", [author], 1
)]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
@@ -130,7 +124,6 @@ texinfo_documents = [(
"novelWriter", "Markdown-like editor for novels.", "Miscellaneous"
)]
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.

View File

@@ -41,8 +41,8 @@ meta data is primarily saved as JSON files.
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
too. novelWriter can be run directly from the Python source, or installed from the pip tool or via
the provided setup script. A setup.exe is provided for Windows. See :ref:`a_started` for further
details.
the provided setup script. See :ref:`a_started`, or one or the setup instructions for your
operating system for further details.
**Useful Links**
@@ -57,22 +57,26 @@ details.
.. toctree::
:maxdepth: 2
:caption: First Steps
:caption: Introduction
int_introduction
int_started
int_interface
int_typography
setup_linux
setup_mac
setup_windows
.. toctree::
:maxdepth: 2
:caption: Writing Novels
:caption: Usage
write_projects
write_structure
write_notes
write_export
usage_interface
usage_shortcuts
usage_projects
usage_structure
usage_notes
usage_export
usage_typography
.. toctree::

View File

@@ -1,439 +0,0 @@
.. _a_ui:
**************
User Interface
**************
The user interface is kept as simple as possible to avoid distractions when writing. This page
lists all the main GUI elements, and explains what they do.
.. _a_ui_tree:
The Project Tree
================
The main window contains a project tree in the left-most panel. It shows the entire structure of
the project. It has four columns:
:guilabel:`Label`
The first column shows the item icon and its label. The labels can be edited from the
:guilabel:`Project` menu, or by pressing :kbd:`F2` or :kbd:`Ctrl`:kbd:`E`. The label is not the
same as the title you set inside the document, but it will appear in the header above the
document text itself.
:guilabel:`Words`
The second column shows the word count of the document, or the sum of words in the child items
if it is a folder. If the counts seem incorrect, they can be updated by rebuilding the project
index from the :guilabel:`Tools` menu, or by pressing :kbd:`F9`.
:guilabel:`Inc`
The third column indicates whether the document is included in the final project build or not.
You may want to filter out documents that you no longer want to keep in the final manuscript,
but want to keep in the project for reference.
:guilabel:`Flags`
The fourth column shows various meta data flags for the item. The first is an icon indicating
the importance or status of the document. These are colour coded status levels that you control
and define yourself. They can be changed in :guilabel:`Project Settings` from the
:guilabel:`Project` menu. The first character after the icon indicates the class of the item,
that is ``N`` for **Novel**, ``C`` for **Character**, etc (see :ref:`a_struct_tags`). The second
character indicates the document layout type (see :ref:`a_proj_roots`).
Below the project tree you will find a small details panel showing the full information of the
currently selected item. This panel also includes the latest paragraph and character counts in
addition to the word count.
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.
.. _a_ui_tree_dnd:
Project Tree Drag and Drop
--------------------------
The project tree allows drag and drop to a certain extent. This feature is primarily intended for
rearranging the order of your documents within each root folder, and has only limited support for
moving documents elsewhere in the project tree. In general, bulk actions are not allowed. This is
deliberate to avoid accidentally messing up your project. The project tree has no undo function.
Documents and their folders can be rearranged freely within their root folders. Novel documents
cannot be moved out of the :guilabel:`Novel` folder, except to :guilabel:`Trash` and the
:guilabel:`Outtakes` folder. Notes can be moved freely between root folders.
Folders cannot be moved at all outside their root tree. Neither can a folder containing documents
be deleted. You must first delete the containing documents.
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 eachother from the :guilabel:`Tools` menu or the
right-click context menu, or by pressing :kbd:`Ctrl`:kbd:`Shift` and the :kbd:`Up` or :kbd:`Down`
key.
.. _a_ui_edit:
Editing and Viewing Documents
=============================
To edit a document, double-click it in the project tree, or press the :kbd:`Return` key while
having it selected. This will open the document in the document editor. The editor uses a
simplified markdown format. The format is described in the :ref:`a_ui_md` section below. The editor
has a maximise button (activates :guilabel:`Distraction Free Mode`) and a close button in the
top-right corner.
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`:kbd:`R`, or select :guilabel:`View Document` in the
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 currently being edited. However,
If you *are* viewing the same document, pressing :kbd:`Ctrl`:kbd:`R` again will update the document
with your latest changes. You can also press the reload button in the top-right corner of the view
panel next to the close button to achieve the same thing.
Both the document editor and viewer will show the label of the 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 the :guilabel:`Preferences` dialog from the :guilabel:`Tools` menu. Clicking on the document
title bar will select and reveal its location in the project tree, making it easier to find in a
large project.
Any reference to a tag in the editor can be opened in the viewer by moving the cursor to the label
and pressing :kbd:`Ctrl`:kbd:`Return`. In the viewer, the references become clickable links.
Clicking them will replace the content of the viewer with the content of the document the reference
points to. The document viewer keeps a history of viewed documents that you can navigate with the
arrow buttons in the top-left corner of the viewer. If your mouse has navigation buttons, these can
be used as well.
At the bottom of the view panel there is a :guilabel:`References` panel. (If it is hidden, click
the icon to reveal it.) This panel will show links to all documents referring back to it, if any
has been defined. The :guilabel:`Sticky` button will freeze the content of the panel to the current
document, even if you navigate to another document. This is convenient if you want to quickly look
through all documents in the list in the :guilabel:`References` panel.
.. note::
The :guilabel:`References` panel relies on an up-to-date index of the project. 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`.
.. _a_ui_edit_auto:
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`.
.. tip::
If you don't like auto-replacement, all symbols inserted by this feature are also available in
the :guilabel:`Insert` menu, and via convenient :ref:`a_ui_shortcuts_ins`.
The editor is able to replace two and three hyphens with short and long dashes, triple points with
ellipsis, and replace straight single and double quotes with user-defined quote symbols. It will
also try to determine whether to use the opening or closing symbol, but this feature isn't always
accurate.
.. tip::
If the editor changes a symbol when you did not want it to change, pressing :kbd:`Ctrl`:kbd:`Z`
immediately after the auto-replacement will undo it without undoing the character you typed.
.. _a_ui_md:
Markdown Format
===============
The document editor uses a simplified markdown format. That is, it supports basic formatting like
emphasis (italic), strong importance (bold) and strikethrough text, as well as four levels of
headings.
Some non-standard markdown features have been added. For instance, novelWriter allows for comments,
a synopsis tag, and a set of keyword and value sets used for tags and references.
.. _a_ui_md_head:
Headings
--------
Four levels of headings are allowed. For documents of layout "Note", they are free to be used as
you see fit, but for all other layouts used for the novel text itself, they indicate the structural
level of the novel. See :ref:`a_struct_heads` for more details.
``# Title``
Heading level one. If the document is a novel file, the header level indicates the start of a
new partition. This heading level can also be used for the title page novel title.
``## Title``
Heading level two. If the document is a novel file, the header level indicates the start of a
new chapter.
``### Title``
Heading level three. If the document is a novel file, the header level indicates the start of a
new scene.
``#### Title``
Heading level four. If the document is a novel file, the header level indicates the start of a
new section.
.. note::
The space after the ``#`` characters is mandatory. The syntax highlighter will change colour and
font size when the heading is correctly formatted.
.. _a_ui_md_emph:
Text Emphasis
-------------
A minimal set of text emphasis styles are supported.
``_text_``
The text is rendered as emphasised text (italicised).
``**text**``
The text is rendered as strongly important text (bold).
``~~text~~``
Strikethrough text.
In markdown guides it is often recommended to differentiate between strong importance 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
recommendation.
In addition, the following rules apply:
1. The emphasis and strikethrough formatting tags do not allow spaces between the words and the tag
itself. That is, ``**text**`` is valid, ``**text **`` is not.
2. More generally, the delimiters must be on the outer edge of words. That is, ``some **text in
bold** here`` is valid, ``some** text in bold** here`` is not.
3. If using both ``**`` and ``_`` to wrap the same text, the underscore must be the inner wrapper.
This is due to the underscore also being a valid word character, so if they are on the outside,
they violate rule 2.
4. Text emphasis does not span past line breaks. If you need to add emphasis to multiple lines or
paragraphs, you must apply it to each of them in turn.
.. _a_ui_md_comm:
Comments and Synopsis
---------------------
In addition to these standard markdown features, novelWriter also allows for comments in document.
The text of the comment is ignored by the word counter and not exported or, optionally, hidden when
viewing the document. If the first word of a comment is ``Synopsis:`` (with the colon), the comment
is treated specially 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...``
A comment. The text is not exported by default (this can be overridden), seen in the Viewer, or
counted towards word counts.
``% Synopsis: text...``
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 exporting the project to for instance generate an outline document
of the whole project.
.. note::
Only one comment can be flagged as a synopsis comment for each heading. If multiple comments are
flagged as synopsis comments, the last one will be used.
.. _a_ui_md_tags:
Tags and References
-------------------
The document editor supports a minimal set of keywords used for setting tags, and making references
between documents. The tags and references can be set once per section defined by a heading. Using
them multiple times under the same heading will just override the previous setting.
``@keyword: value``
A keyword argument followed by a value, or a comma separated list of values.
The available tag and reference keywords are listed in the :ref:`a_struct_tags` section. They can
also be inserted at the cursor position in the editor via the :guilabel:`Insert` menu.
.. _a_ui_md_add:
Additional Markdown and Non-Standard Features
---------------------------------------------
The editor and viewer also supports markdown standard hard line breaks, and preserves non-breaking
spaces if running with Qt 5.9 or higher. For older versions, the non-breaking spaces are lost when
the document is saved. This is unfortunately hard-coded in the Qt text editor.
* A hard line break is achieved by leaving two or more spaces at the end of the line.
Alternatively, the user can press :kbd:`Ctrl`:kbd:`K`, :kbd:`Return` to insert this.
* A non-breaking space is inserted with :kbd:`Ctrl`:kbd:`K`, :kbd:`Space`.
* Thin spaces are also supported, and can be inserted with :kbd:`Ctrl`:kbd:`K`,
:kbd:`Shift`:kbd:`Space`.
* Non-breaking thin space can be inserted with :kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`Space`.
These are all insert features, and the :guilabel:`Insert` menu has more. They are also listed
in :ref:`a_ui_shortcuts_ins`.
Both hard line breaks and non-breaking spaces are highlighted by the syntax highlighter as an
alternate coloured background, depending on the selected theme.
.. _a_ui_outline:
Project Outline View
====================
The project's Outline view is available as the second tab on the right hand side of the main window
labelled :guilabel:`Outline`. 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.
The document containing the heading can also be displayed as a separate column, as well as the line
number where it occurs. Double-clicking an entry will open the corresponding document in the
editor.
.. note::
Since the internal structure of the novel does not depend directly on the folder and document
structure of the project tree, these will not necessarily look the same, depending how you
choose to organise your documents. See the :ref:`a_struct` page for more details.
Various meta data and information extracted from tags can be displayed in columns in the outline.
A default set of such columns is visible, but you can turn on or off more columns by right clicking
the header and selecting the columns you want to show. The order of the columns can also be
rearranged by dragging them to a different position.
.. note::
The :guilabel:`Title` column cannot be disabled or moved.
The information viewed in the outline is based on the project's main index. While novelWriter does
its best to keep the index up to date when content changes, you can always rebuild it manually by
pressing :kbd:`F9` if something isn't right.
The outline view itself can be regenerated by pressing :kbd:`F10`. You can also enable automatic
updating in the :guilabel:`Tools` menu, which will trigger an update whenever the index is updated
and the :guilabel:`Outline` tab is active. You may want to disable this feature if your project is
very large,
The :guilabel:`Synopsis` column of the outline view takes its information from a specially
formatted comment. See :ref:`a_ui_md_comm`.
.. _a_ui_shortcuts:
Keyboard Shortcuts
==================
Most features are available as keyboard shortcuts. These are as follows:
.. csv-table:: Keyboard Shortcuts
:header: "Shortcut", "Description"
:widths: 30, 70
:class: "tight-table"
":kbd:`Alt`:kbd:`1`", "Switch focus to the project tree."
":kbd:`Alt`:kbd:`2`", "Switch focus to document editor."
":kbd:`Alt`:kbd:`3`", "Switch focus to document viewer."
":kbd:`Alt`:kbd:`Left`", "Move backward in the view history of the document viewer."
":kbd:`Alt`:kbd:`Right`", "Move forward in the view history of the document viewer."
":kbd:`Ctrl`:kbd:`.`", "Open menu to correct word under cursor."
":kbd:`Ctrl`:kbd:`,`", "Open the :guilabel:`Preferences` dialog."
":kbd:`Ctrl`:kbd:`/`", "Change block format to comment."
":kbd:`Ctrl`:kbd:`-`", "Strikethrough selected text, or word under cursor."
":kbd:`Ctrl`:kbd:`0`", "Remove block formatting for block under cursor."
":kbd:`Ctrl`:kbd:`1`", "Change block format to header level 1."
":kbd:`Ctrl`:kbd:`2`", "Change block format to header level 2."
":kbd:`Ctrl`:kbd:`3`", "Change block format to header level 3."
":kbd:`Ctrl`:kbd:`4`", "Change block format to header level 4."
":kbd:`Ctrl`:kbd:`A`", "Select all text in the document."
":kbd:`Ctrl`:kbd:`B`", "Format selected text, or word under cursor, with strong emphasis (bold)."
":kbd:`Ctrl`:kbd:`C`", "Copy selected text to clipboard."
":kbd:`Ctrl`:kbd:`D`", "Wrap selected text, or word under cursor, in double quotes."
":kbd:`Ctrl`:kbd:`E`", "If in the project tree, edit a document or folder settings. (Same as :kbd:`F2`.)"
":kbd:`Ctrl`:kbd:`F`", "Open the search bar and search for the selected word, if any is selected."
":kbd:`Ctrl`:kbd:`G`", "Find next occurrence of search word in current document. (Same as :kbd:`F3`.)"
":kbd:`Ctrl`:kbd:`H`", "Open the search and replace bar and search for the selected word, if any is selected. (On Mac, this is :kbd:`Cmd`:kbd:`=`.)"
":kbd:`Ctrl`:kbd:`I`", "Format selected text, or word under cursor, with emphasis (italic)."
":kbd:`Ctrl`:kbd:`K`", "Activate the insert commands. The commands are listed in :ref:`a_ui_shortcuts_ins`."
":kbd:`Ctrl`:kbd:`N`", "Create new document."
":kbd:`Ctrl`:kbd:`O`", "Open selected document."
":kbd:`Ctrl`:kbd:`Q`", "Exit novelWriter."
":kbd:`Ctrl`:kbd:`R`", "If in the project tree, open a document for viewing. If the editor has focus, open current document for viewing."
":kbd:`Ctrl`:kbd:`S`", "Save the current document in the document editor."
":kbd:`Ctrl`:kbd:`V`", "Paste text from clipboard to cursor position."
":kbd:`Ctrl`:kbd:`W`", "Close the current document in the document editor."
":kbd:`Ctrl`:kbd:`X`", "Cut selected text to clipboard."
":kbd:`Ctrl`:kbd:`Y`", "Redo latest undo."
":kbd:`Ctrl`:kbd:`Z`", "Undo latest changes."
":kbd:`Ctrl`:kbd:`F7`", "Toggle spell checking."
":kbd:`Ctrl`:kbd:`F10`", "Toggle automatic updating of project outline."
":kbd:`Ctrl`:kbd:`Del`", "If in the project tree, move a document to trash, or delete a folder."
":kbd:`Ctrl`:kbd:`Enter`", "Open the tag or reference under the cursor in the Viewer."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`,`", "Open the :guilabel:`Project Settings` dialog."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`/`", "Remove block formatting for block under cursor."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`1`", "Replace occurrence of search word in current document, and search for next occurrence."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`A`", "Select all text in current paragraph."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`D`", "Wrap selected text, or word under cursor, in single quotes."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`G`", "Find previous occurrence of search word in current document. (Same as :kbd:`Shift`:kbd:`F3`.)"
":kbd:`Ctrl`:kbd:`Shift`:kbd:`I`", "Import text to the current document from a text file."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`N`", "Create new folder."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`O`", "Open a project."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`R`", "Close the document viewer."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`S`", "Save the current project."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`W`", "Close the current project."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`Z`", "Alternative sequence for redo last undo."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`Up`", "Move item one step up in the project tree."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`Down`", "Move item one step down in the project tree."
":kbd:`F1`", "Open the documentation. This will either open the Qt Assistant, if available, or send you to the documentation website."
":kbd:`F2`", "If in the project tree, edit a document or folder settings. (Same as :kbd:`Ctrl`:kbd:`E`)"
":kbd:`F3`", "Find next occurrence of search word in current document. (Same as :kbd:`Ctrl`:kbd:`G`)"
":kbd:`F5`", "Open the :guilabel:`Build Novel Project` dialog."
":kbd:`F6`", "Open the :guilabel:`Writing Statistics` dialog."
":kbd:`F7`", "Re-run spell checker."
":kbd:`F8`", "Activate :guilabel:`Focus Mode`, hiding the project tree and document viewer."
":kbd:`F9`", "Re-build the project index."
":kbd:`F10`", "Re-build the project outline."
":kbd:`F11`", "Activate full screen mode."
":kbd:`Shift`:kbd:`F1`", "Open the online documentation in the system default browser."
":kbd:`Shift`:kbd:`F3`", "Find previous occurrence of search word in current document. (Same as :kbd:`Ctrl`:kbd:`Shift`:kbd:`G`.)"
":kbd:`Return`", "If in the project tree, open a document for editing."
.. note::
On macOS, replace :kbd:`Ctrl` with :kbd:`Cmd`.
.. _a_ui_shortcuts_ins:
Insert Shortcuts
----------------
A set of insert features are also available through shortcuts, but they require a double
combination of key sequences. The insert feature is activated with :kbd:`Ctrl`:kbd:`K`, followed by
a key or combination for the inserted character or punctuation.
.. csv-table:: Keyboard Shortcuts
:header: "Shortcut", "Description"
:widths: 40, 60
:class: "tight-table"
":kbd:`Ctrl`:kbd:`K`, :kbd:`-`", "Insert a short dash (en dash)."
":kbd:`Ctrl`:kbd:`K`, :kbd:`_`", "Insert a long dash (em dash)."
":kbd:`Ctrl`:kbd:`K`, :kbd:`.`", "Insert an ellipsis."
":kbd:`Ctrl`:kbd:`K`, :kbd:`1`", "Insert a left single quote."
":kbd:`Ctrl`:kbd:`K`, :kbd:`2`", "Insert a right single quote."
":kbd:`Ctrl`:kbd:`K`, :kbd:`3`", "Insert a left double quote."
":kbd:`Ctrl`:kbd:`K`, :kbd:`4`", "Insert a right double quote."
":kbd:`Ctrl`:kbd:`K`, :kbd:`'`", "Insert a modifier apostrophe."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Return`", "Insert a hard line break."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Space`", "Insert a non-breaking space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Shift`:kbd:`Space`", "Insert a thin space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`Space`", "Insert a thin non-breaking space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`G`", "Insert a @tag keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`V`", "Insert a @pov keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`C`", "Insert a @char keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`P`", "Insert a @plot keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`T`", "Insert a @time keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`L`", "Insert a @location keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`O`", "Insert a @object keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`E`", "Insert a @entity keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`X`", "Insert a @custom keyword."

View File

@@ -7,20 +7,20 @@ Introduction
novelWriter is a simple, multi-document plain text editor using a modified markdown syntax to apply
simple formatting to the text. It is designed for writing novels, and allows for the component
documents to be ordered freely to create the desired structure of the novel. More details about how
projects are structured is covered on the :ref:`a_struct` page.
projects are structured is covered in :ref:`a_struct`.
In addition, the project can contain notes on the various plot elements, characters, locations,
etc, that make up the story. These notes are organised in a set of category-specific top-level
folders (root folders), and each entry can be tagged and cross-referenced from within the novel
documents and notes. These tags make it possible to inter-link documents, and generate an overview
of the entire novel project and how the various documents and plot elements are interconnected.
This is covered on the :ref:`a_proj` and :ref:`a_notes` pages.
folders referred to as "root" folders, and each entry can be tagged and cross-referenced from
within the novel documents and notes. These tags make it possible to inter-link documents, and
generate an overview of the entire novel project and how the various documents and plot elements
are interconnected. The tag and reference syntax is covered in :ref:`a_proj` and :ref:`a_notes`.
These additional features are not standard in markdown, but are available through special meta
keywords described in :ref:`a_struct_tags`. Syntax highlighting is provided to make it easier to
verify that the markdown tags are used correctly.
An overview of the supported markdown syntax is covered on the :ref:`a_ui` page.
An overview of the supported markdown syntax is covered in :ref:`a_ui`.
.. _a_intro_design:
@@ -36,30 +36,36 @@ at the same time provide a complete set of features needed for writing a novel.
links, tables, and other complex structures and objects often needed for such documents.
Formatting is limited to headers, and bold, italicised and strikethrough text.
The main window does not have a toolbar like most other applications do. This reduces clutter, and
.. tip::
If you do need to align information in rows and columns in your notes, you can achieve this with
tabs and line breaks. The tab stop width can be specified in :guilabel:`Preferences`.
The main window does not have a toolbar like many other applications do. This reduces clutter, and
since the documents are formatted with markdown tags, is more or less redundant. However, all
formatting features supported are available through convenient keyboard shortcuts. They are also
available in the main menu. A full list of shortcuts can be found in the :ref:`a_ui_shortcuts`
section.
available in the main menu so you don't have to look up the syntax every time until you've
memorised it. A full list of shortcuts can be found in the :ref:`a_kb` section.
In addition, novelWriter offers a :guilabel:`Distraction Free Mode` where all the user interface
elements other than the document editor itself are hidden away.
In addition, novelWriter has a :guilabel:`Focus Mode` where all the user interface elements other
than the document editor itself are hidden away.
The colour scheme of the user interface defaults to that of the host operating system. In addition,
a dark theme is provided, and can be enabled in :guilabel:`Preferences` from the :guilabel:`Tools`
menu. A number of syntax highlighting themes are also available in :guilabel:`Preferences`. A set
of icon themes in colour and greyscale are also offered. The icons are based on the Typicons_ icon
set designed by Stephen Hutchings.
other light and dark themes are provided, and can be enabled in :guilabel:`Preferences` from the
:guilabel:`Tools` menu. A number of syntax highlighting themes are also available in
:guilabel:`Preferences`. A set of icon themes in colour and greyscale are also offered. The icons
are based on the Typicons_ icon set designed by Stephen Hutchings.
The main window is split in two, or optionally three, panels. The left-most contains the project
tree and all the documents in your project. The second panel is the document editor, and the
optional third panel is a document viewer which can view any document in your project.
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, and
the optional third panel is a document viewer which can view any document in your project
independently of the document editor. It is not intended as a preview window, although you can use
it for this, but for viewing your notes next to your editor while you're writing.
A second tab is also available on the main window. This is the :guilabel:`Outline` tab where the
entire novel structure can be displayed, with all the tags and references listed. Depending on how
you structure your novel documents, this outline can be quite different from your project tree.
Your project tree lists individual documents, your Outline tree lists the structure of the novel
itself as it appears in the text of the documents.
itself in terms of partitions, chapters and scenes as it appears in the text of the documents.
.. _Typicons: https://github.com/stephenhutchings/typicons.font
@@ -69,7 +75,7 @@ itself as it appears in the text of the documents.
Project Layout
==============
You are free to structure your project documents as you wish in subfolders, and split the text
You are free to organise your project documents as you wish into subfolders, and split the text
between documents in whatever way suits you. All that matters to novelWriter is the linear order
the documents appear at in the project tree (top to bottom). The chapters, scenes and sections of
the novel are determined by the headings within those documents.
@@ -83,7 +89,7 @@ The four heading levels (**H1** to **H4**) are treated as follows:
This header level structure is only taken into account for novel documents. For the project notes,
the header levels have no structural meaning, and the user is free to do whatever they want. See
the :ref:`a_struct` and :ref:`a_notes` pages for more details.
:ref:`a_struct` and :ref:`a_notes` for more details.
.. _a_intro_export:
@@ -92,13 +98,12 @@ Project Export
==============
The project can at any time be exported to a range of different formats through the
:guilabel:`Build Novel Project` tool. Natively, novelWriter supports export to plain text file,
HTML document, novelWriter flavoured markdown, standard markdown (requires Qt 5.14), and to a basic
Open Document format.
:guilabel:`Build Novel Project` tool. Natively, novelWriter supports export to Open Document,
HTML5, and various flavours of Markdown.
In addition, printing and printing to PDF is also possible. The best supported export format is
HTML, which can be imported or converted by a number of other tools like Pandoc, or simply imported
into Libre Office Writer and similar word processors.
The HTML5 export 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. In addition, printing
and printing to PDF is also possible.
It is also possible to export the content of the project to a JSON file. This is useful if you want
to write your own processing script in for instance Python as the entire novel can be read into a
@@ -106,8 +111,7 @@ Python dictionary with a couple of lines of code.
A number of filter options can be applied to the produced document, allowing you to export a draft
manuscript, a reference document of notes, an outline based on chapter and scene titles with a
synopsis each, and so on. See the :ref:`a_export` page for more details on export features and
formats.
synopsis each, and so on. See :ref:`a_export` for more details on export features and formats.
.. _a_intro_screenshots:

View File

@@ -4,69 +4,28 @@
Getting Started
***************
This is a brief guide to how you can get novelWriter running on your computer. These are the
methods currently supported by the developer. Packages may also be available in other package
managers, but those are not managed by the developer. A Windows installer file is also provided on
the GitHub page and main website.
As novelWriter matures, more options for how to install it and get it running will be added. For
non-Windows users the install process is at the present time best suited for people used to working
with the command line.
.. note::
The text below assumes the command ``python`` corresponds to a Python 3 executable. For
operating systems with both Python 2 and 3, the command ``python3`` may be needed instead. On
Linux, the scripts can also be made executable and run without the ``python`` command.
.. _a_started_install:
Installation
============
You can download the latest version of novelWriter from the source repository on GitHub_. You can
also install it directly from PyPi with ``pip install novelwriter``, or download the packages
directly from the PyPi_ project page.
Latest version of novelWriter is |release|.
.. _main website: https://novelwriter.io
.. _GitHub: https://github.com/vkbo/novelWriter/releases
.. _PyPi: https://pypi.org/project/novelWriter/
This section contains brief guides to how you can get novelWriter running on your computer. These
are the methods currently supported by the developer. Packages may also be available in other
package managers, but those are not managed by the developer. No installers are provided at this
time, but it is fairly straightforward to set up novelWriter with the provided install scripts.
.. _a_started_install_win:
As novelWriter matures, more options for how to install it and get it running will be added. For
non-Windows users the install process is at the present time best suited for people used to working
with the command line. But even if you're not, the install process is fairly straightforward.
Windows Installer
-----------------
The next pages have specific install instructions for the various operating systems novelWriter can
run on. The instructions below are supplementary information, instructions for alterbative methods,
and additional build options.
You can run novelWriter directly from source on Windows, but a Windows installer is also provided
for 64-bit Windows on the `main website`_ and GitHub_ page. This installer bundles all that is
needed for novelWriter to run, including Python and the xml and Qt libraries.
.. _main website: https://novelwriter.io
.. _a_started_install_source:
Install from Source on Linux
----------------------------
For Linux systems, novelWriter can be installed from source with the provided ``setup.py`` script.
To install novelWriter into the system's default Python install locations, run:
.. code-block:: console
python setup.py install
To set up the novelWriter desktop launcher, the icons and the project file association, run:
.. code-block:: console
python setup.py xdg-install
By default, these commands installs novelWriter and its icons for the current user only. To install
for all users, run the script with the ``sudo`` command. Other options are also available. Run
``python setup.py help`` for a full list of install options.
.. note::
The text below assumes the command ``python`` corresponds to a Python 3 executable. Python 2 is
now deprecated, but many systems still have both Python 2 and 3. For such systems, the command
``python3`` may be needed instead. On Linux, the scripts can also be made executable and run
without the ``python`` command. Likewise, ``pip`` may need to be replaced with ``pip3``.
.. _a_started_depend:
@@ -74,70 +33,115 @@ for all users, run the script with the ``sudo`` command. Other options are also
Dependencies
============
novelWriter has been designed to rely on as few dependencies as possible. Aside from the package(s)
novelWriter has been designed to rely on as few dependencies as possible. Aside from the packages
needed to communicate with the Qt GUI libraries, only one package is required for handling the XML
format of the main project file. Everything else is handled with standard Python libraries.
The following Python packages are needed to run novelWriter:
* ``pyqt5`` – needed for connecting with the Qt5 libraries.
* ``lxml`` – needed for full XML support.
* ``pyenchant`` – needed for efficient spell checking (optional).
PyQt/Qt should be at least 5.3, but ideally 5.10 or higher for nearly all features to work. For
instance, searching using regular expressions with full Unicode support requires 5.13. There is no
known minimum version requirement for package ``lxml``, but the code was originally written with
4.2, which is therefore set as the minimum. It may work on lower versions. You have to test it.
Optionally, a package can be installed to interface with the Enchant spell checking libaries, but
this isn't strictly required. If no external spell checking library is available, novelWriter falls
back to using the internal ``difflib`` of Python to check spelling. This is a much slower approach,
and it is less sophisticated than full spell checking libaries, but if you only work with small
files, the performance loss is not noticeable.
back to using the internal ``difflib`` of Python to check spelling. This is a slower and less
sophisticated spell checker than the full spell checking libaries. The spell check library must be
at least 3.0 to work with Windows. On Linux, 2.0 also works fine.
.. _a_started_depend_packages:
Package Installation
--------------------
If you already have Python installed, all you need to do is install the dependencies. To do this,
you need to open your command line tool, find the folder where you extracted novelWriter, and run
the following command:
If you install from PyPi, these dependencies should be installed automatically. If you install from
source, dependencies can still be installed from PyPi with:
.. code-block:: console
pip install -r requirements.txt
This will install all the dependencies and recommended packages.
The following Python packages are required to run novelWriter:
.. _a_started_install:
* ``pyqt5``, needed for connecting with the Qt5 libraries.
* ``lxml``, needed full XML support.
Installing via PyPi
===================
You can of course also install these packages from your operating system's package repository.
The application is written in Python 3 using Qt5 via PyQt5. It is developed on Linux, but it should
in principle work fine on other operating systems as long as dependencies are met.
PyQt/Qt should be at least 5.2.1, but ideally 5.10 or higher for nearly all features to work.
Exporting to standard Markdown, for instance, requires PyQt/Qt 5.14. Searching using regular
expressions requires 5.3, and for full Unicode support, 5.13. There is no known minimum version
requirement for package ``lxml``, but the code was originally written with 4.2, which is therefore
set as the minimum. It may work on lower versions. You have to test it.
You can download the latest version of novelWriter from the source repository on GitHub_.
novelWriter is also hosted on PyPi_, and can be installed on all operating systems that support Qt5
and Python 3. It is regularly tested on Linux, Windows and macOS. The latest version of novelWriter
is |release|.
The spell checking extension is optional, but recommended:
To install from PyPi you must first have the ``python`` and ``pip`` commands available on your
system. If you don't, see specific instructions for your operating system in this documentation.
To install novelWriter from PyPi, use the following command:
* ``pyenchant``, needed for efficient spell checking.
.. code-block:: console
The optional spell check library must be at least 3.0 to work with Windows. On Linux, 2.0 also
works fine.
pip install novelwriter
To upgrade an existing installation, use:
.. code-block:: console
pip install --upgrade novelwriter
When installing via pip, novelWriter can be launched from command line with:
.. code-block:: console
novelWriter
Make sure the install location for pip is in your PATH variable. This is not always the case by
default.
.. _a_started_depend_docs:
.. _a_started_i18n:
Building the Translation Files
==============================
If you installed novelWriter from a package, the translation files should be pre-built and
included. If you're running novelWriter from the source code, you will need to generate the files
yourself. The files you need will be written to the ``nw/assets/i18n`` folder, and will have the
``.qm`` file extension.
You can build the ``.qm`` files with:
.. code-block:: console
python3 setup.py qtlrelease
This requires that the Qt Linguist tool is installed on your system. On Ubuntu and Debian, the
needed package is called `qttools5-dev-tools`.
.. note::
If you want to improve novelWriter with translation files for another language, or update an
existing translation, instructions for how to contribute can be found in the README file in the
``i18n`` folder of the source code.
.. _a_started_docs:
Building the Documentation
--------------------------
==========================
If you installed novelWriter from a package, the documentation should be included. If you're
running novelWriter from the source code, a local copy of this documentation can be generated. It
requires the following Python packages on Debian and Ubuntu.
If you installed novelWriter from a package, the documentation should be bre-built and included. If
you're running novelWriter from the source code, a local copy of this documentation can be
generated. It requires the following Python packages on Debian and Ubuntu.
* ``python3-sphinx``
* ``python3-sphinx-rtd-theme``
* ``python3-sphinxcontrib.qthelp``
Or from PyPi:
.. code-block:: console
pip install sphinx sphinxcontrib-qthelp
pip install sphinx sphinx-rtd-theme sphinxcontrib-qthelp
The documentation can then be built from the ``docs`` folder in the source code by running:
@@ -145,7 +149,8 @@ The documentation can then be built from the ``docs`` folder in the source code
make html
If successful, the documentation should then be available in the ``docs/build/html`` folder.
If successful, the documentation should be available in the ``docs/build/html`` folder and you can
open the ``index.html`` file in your browser.
The documentation can also be built for the Qt Assistant. To build the help packages from the
documentation source, run the following from the root source folder:
@@ -163,54 +168,3 @@ locally first, then send you to the website as a fallback.
In order for the local version of help to work, the Qt Assistant must be installed on the local
computer. If it isn't available, or novelWriter cannot find it, the help feature will fall back
to redirecting you to the documentation website.
.. _a_started_running:
Running from Source
===================
If all the required dependencies are met, you can run novelWriter from the command line:
.. code-block:: console
python novelWriter.py
A few switches are supported from the command line, mostly to assist in debugging if an error is
encountered. To list all options, run:
.. code-block:: console
python novelWriter.py --help
.. _a_started_standalone:
Building a Standalone Executable
================================
A standalone executable can be built with ``pyinstaller``, using the provided python script
``make.py`` in the source folder. This script can install dependencies, build a standalone
executable of novelWriter, or build a ``setup.exe`` file with Inno Setup.
For a full list of the script's options, run ``python make.py help``.
.. _a_started_standalone_win:
Additional Instructions for Windows
-----------------------------------
If you don't have Python installed, you can download it from the python.org website. The installers
for Windows are available at https://www.python.org/downloads/windows/
novelWriter should work with Python 3.6 or higher, and the executable installer is the easiest to
install.
Also, make sure you select the "Add Python to PATH" option.
.. image:: images/python_win_install.png
:width: 600
Once Python is set up and running, you can either run novelWriter from the folder where you
extracted it, or you can build an executable and run that from a desktop icon instead.

110
docs/source/setup_linux.rst Normal file
View File

@@ -0,0 +1,110 @@
.. _a_setup_linux:
**************
Setup on Linux
**************
.. _GitHub: https://github.com/vkbo/novelWriter/releases
.. _main website: https://novelwriter.io
This is a brief guide to how you can get novelWriter running on a Linux computer. There are
currently no install package of novelWriter for Linux, so it is recommended that you download
either the full source or minimal package and extract it to a practical location on your system and
run the ``setup.py`` script.
Running from Source
===================
To run novelWriter from source, download the latest source package from the release page on
GitHub_ or the `main website`_, or if you have git running on your computer, you can also clone the
repository.
Step 1: Installing Dependencies
-------------------------------
The dependencies of novelWriter are generally available from Linux distro repositories. For Debian
and Ubuntu, they can be installed with:
.. code-block:: console
sudo apt install python3-pyqt5 python3-lxml python3-enchant
If you prefer to install dependencies via PyPi, or the repository dependencies are out of date, you
can install them with:
.. code-block:: console
pip3 install --user -r requirements.txt
Step 2: Install Package (Optional)
----------------------------------
You can install novelWriter to the default location for Python packages using ``setuptools``. This
step is optional as you can also just put the novelWriter program folder wherever you like
yourself. For instance in ``/opt/novelWriter``, and then run Step 3 to set up icons and launcher.
To install novelWriter to the default location, it requires that you have ``setuptools`` installed
on your system. If you don't have it installed, it can usually be installed from your distro's
repository. For Debian and Ubuntu this is achieved with:
.. code-block:: console
sudo apt install python3-setuptools
The package is also available from PyPi:
.. code-block:: console
pip3 install --user setuptools
With ``setuptools`` in place, novelWriter can be installed to the user space with:
.. code-block:: console
./setup.py install --user
This should install novelWriter as ``~/.local/bin/novelWriter``. If you instead want to install for
all users, i.e. as ``/usr/local/bin/novelWriter``, run:
.. code-block:: console
sudo ./setup.py install
This is equivalent to what the ``pip`` installer does. It puts novelWriter in the location on your
system where Python packages are usually kept. This is not really the best suited location for a
GUI application like novelWriter, so you may instead copy the entire source to a suiteable location
yourself.
Step 3: Create Launcher Icons
-----------------------------
Regardless of where you extract or install the source files, you can set up a standard icon and a
launcher. To set up this desktop launcher, the needed icons, and the project file association,
run the following from inside the novelWriter folder at the installed or final location:
.. code-block:: console
./setup.py xdg-install
By default, this command installs the launcher and icons for the current user only. To install for
all users, run the script with the ``sudo`` command.
.. tip::
All options of the setup script can be listed with: ``./setup.py help``.
Uninstalling Icons
==================
The steps taken by the ``xdg-install`` step can be reversed by running:
.. code-block:: console
./setup.py xdg-uninstall
This will remove the desktop launcher and icons from the system. As above, whether this is done on
the current user, or system wide, depends on whether this command is called with ``sudo`` or not.

74
docs/source/setup_mac.rst Normal file
View File

@@ -0,0 +1,74 @@
.. _a_setup_mac:
**************
Setup on macOS
**************
.. _GitHub: https://github.com/vkbo/novelWriter/releases
.. _main website: https://novelwriter.io
.. _brew docs: https://docs.brew.sh/Homebrew-and-Python
This is a brief guide to how you can get novelWriter running on macOS. There are currently no
install package of novelWriter for macOS, so it is recommended that you download either the full
source or minimal package and extract it to a practical location on your system and
run it.
Running from Source
===================
To run novelWriter from source, download the latest source package from the release page on
GitHub_ or the `main website`_, or if you have git running on your computer, you can also clone the
repository.
Step 1: Installing Dependencies
-------------------------------
These instructions assume you're using brew, and have Python and pip set up. If not, see the
`brew docs`_ for help. Main requirements are installed via the requirements file. You also need to
install the ``pyobjc`` package, so you should run:
.. code-block:: console
pip3 install --user -r requirements.txt
pip3 install --user pyobjc
For spell checking you may also need to install the enchant package. It comes with a lot of default
dictionaries.
.. code-block:: console
brew install enchant
With the dependencies in place, you can launch the ``novelWriter.py`` script directly to run
novelWriter.
Step 2: Install Package (Optional)
----------------------------------
You can install novelWriter to the correct location for Python packages with:
.. code-block:: console
./setup.py install --user
This requires that the package ``setuptools`` is installed on your system. If not, it can be
installed with:
.. code-block:: console
pip3 install --user setuptools
This is method of install is equivalent to what the ``pip`` installer does. It puts novelWriter in
the location on your system where Python packages are usually kept. This is not really the best
suited location for a GUI application like novelWriter, so you may instead copy the entire source
to a suiteable location yourself.
After this, you should be able to launch novelWriter by running ``novelWriter`` in a command line
window.
.. note::
Right now there isn't a better integration with macOS available. Contributions from someone more
familiar with macOS would be very much appreciated.

View File

@@ -0,0 +1,149 @@
.. _a_setup_win:
****************
Setup on Windows
****************
This is a brief guide to how you can get novelWriter running on a Windows computer.
Unlike other operating systems, Windows does not come prepared with an environment to run Python
applications, so you must first install Python. After that, running novelWriter is straightforward.
.. tip::
If you have any problems, you can always open a question on the project's discussions_ page.
This requires a GitHub account.
.. _discussions: https://github.com/vkbo/novelWriter/discussions
.. _a_setup_win_installer:
Using the Installer
===================
The installer for Windows is no longer provided. See the `installer issue`_ for more info on why.
You can still create the installer yourself if you want to. It can be generated with the provided
``setup.py`` script. use the script's ``help`` command to get further instructions.
Please use the "Running from Source" option below instead. It has been improved and a script has
been added that does nearly the same thing.
.. _installer issue: https://github.com/vkbo/novelWriter/issues/640
.. _a_setup_win_source:
Running from Source
===================
To run novelWriter from source, download the latest source zip file from the release page on
GitHub_, or from the `main website`_. You can download the "Minimal Windows" zip file. It is a
minimal version of the source that contains only the files needed for running on Windows. You can
also download the full source if you wish.
In order to make novelWriter run on your system, you must first have Python installed (Step 1).
Thereafter, a script will do the rest of the job (Step 2). Alternatively, you can run this step
manually from the command prompt if you wish to.
.. tip::
If your system already has all the dependencies installed, you can run novelWriter directly from
the extracted folder by double-clicking the ``novelWriter.pyw`` file. However, running the
script also adds start icons.
.. _GitHub: https://github.com/vkbo/novelWriter/releases
.. _main website: https://novelwriter.io
Step 1: Installing Python
-------------------------
If you already have Python installed, you can skip this step. If you don't have it installed, you
can download it from the python.org_ website. novelWriter should work with Python 3.6 or higher,
but it is recommended that you install the latest version of Python.
Make sure you select the "Add Python to PATH" option during installation, otherwise the ``python``
command will not work in the command line window.
.. image:: images/python_win_install.png
:width: 600
.. _python.org: https://www.python.org/downloads/windows
Step 2: Dependencies and Icons
------------------------------
**Alternative A: By Script**
Open the folder where you extracted novelWriter, and double-click the file named
``windows_install.bat``. This should open a command line window and run the setup script to install
dependencies, and add desktop and start menu icons.
.. note::
If you downloaded the full source package, the file may be in the ``setup`` subfolder.
The script will also check that it can find Python on your system and alert you if it cannot run
it. If you are sure you have installed it, but the script cannot find it, you probably didn't
install it with the "Add Python to PATH" option mentioned in Step 1.
.. note::
If you upgrade Python to a newer version and the path to ``pythonw.exe`` has therefore changed,
you may need to run this script again. You can also run it to upgrade dependencies to the latest
version.
**Alternative B: Manual Installation**
The above alternative can also be run manually.
Open the windows command prompt. It can be launched by pressing the :kbd:`Win` key and typing "cmd".
The "Command Prompt" app should then be in the list of applications.
With the command prompt open, navigate to the folder where you extracted the novelWriter source,
and run the following commands:
.. code-block:: console
pip install --user pywin32 -r requirements.txt
python setup.py win-install
The first command will install the dependencies on your system from the `Python Package Index`_,
and the second command will create a desktop icon and a start menu icon. That should be all that
you need.
.. _Python Package Index: https://pypi.org/
Uninstalling
============
**Alternative A: By Script**
Open the folder where you keep the novelWriter files, and double-click the file named
``windows_uninstall.bat``. This should open a command line window and run the setup script to
remove the main dependency packages and remove desktop and start menu icons.
.. note::
If you downloaded the full source package, the file may be in the ``setup`` subfolder.
If you plan to also remove Python from your system, you must run the above script first as it needs
Python in order to run.
.. note::
Due to limitations of the ``pip`` installer, dependencies of the dependencies will not be
removed, only the ones the setup script directly installed.
**Alternative B: Manual Uninstallation**
Like for the install process, the script just runs two commands. You can of course run them
yourself if you wish. They are:
.. code-block:: console
python setup.py win-uninstall
pip uninstall -r requirements.txt
There may be other packages on your system installed by ``pip``. To list all packages, run:
.. code-block:: console
pip freeze --user

View File

@@ -7,8 +7,8 @@ Technical Information
This section contains details of how novelWriter stores and handles the project data.
How Data is Stored
==================
How Project Data is Stored
==========================
All novelWriter files are written with utf-8 encoding. Since Python automatically converts Unix
line endings to Windows line endings on Windows systems, novelWriter does not make any adaptations
@@ -20,13 +20,14 @@ operating systems.
Main Project File
-----------------
The project itself requires a dedicated folder for storing its files, where novelWriter will create
The project itself requires a dedicated folder for storing its files where novelWriter will create
its own "file system" where the folder and file hierarchy is described in a project XML file. This
is the main project file in the project's root folder with the name ``nwProject.nwx``. This file
also contains all the meta data required for the project, and a number of related project settings.
If this file is lost or corrupted, the structure of the project is lost. It is important to keep
this file backed up, either through the built-in backup tool, or your own backup solution.
If this file is lost or corrupted, the structure of the project is lost, although not the text
itself. It is important to keep this file backed up, either through the built-in backup tool, or
your own backup solution.
.. tip::
The novelWriter project folder is structured so that it can easily be added to a version control
@@ -36,27 +37,26 @@ this file backed up, either through the built-in backup tool, or your own backup
The project XML file is indent-formatted, suitable for diff tools and version control since most of
the file will stay static, although a timesetamp is set in the meta section on line 2 each time the
file is saved.
file is saved, and various meta data entries are incremented on each save.
Project Documents
-----------------
The project documents are saved in a folder in the main project folder named ``content``. Each
All the project documents are saved in a folder in the main project folder named ``content``. Each
document has a file handle taken from the first 13 characters of a SHA256 hash of the system time
when the document was first created. The documents are saved with a filename assembled from this
hash and the file extension ``.nwd``.
If you wish to find the physical 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
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, or look in the ``ToC.txt`` file in the root of the project folder.
The ``ToC.txt`` file has a list of all document files in the project and where they are saved.
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
what the user names the document within the project, or changes it to. The file meta data in the
project tree is mainly saved in the project XML file, although some basic meta data is added to the
header of each document file.
what the user names the document within the project, or changes it to.
Each document file contains a plain text version of the text from the editor. The file can in
principle be edited in any text editor, and is suitable for diffing and version control if so
@@ -83,3 +83,63 @@ For the project XML file, a ``.bak`` file is in addition kept, which will always
previous version of the file, although when auto-save is enabled, they may have the same content.
If the opening of a project file fails, novelWriter will automatically try to open the ``.bak``
file instead.
Project Meta Data
=================
The project folder contains a subfolder named ``meta``, containing a number of files. The meta
folder contains semi-important files. That is, they can be lost with only minor impact to the
project.
If you use version control software on your project, you can exclude this folder, although you may
want to track the session log file. The JSON files within this folder can safely be ignored as they
will be automatically regenerated if lost.
The Project Index
-----------------
Between writing sessions, the project index is saved in a JSON file in ``meta/tagsIndex.json``.
This file is not critical. If it is lost, it can be rebuilt from within novelWriter from the
:guilabel:`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
project, and the word counts within each header section.
The integrity of the index is checked when the file is loaded. It is possible to corrupt the index
if the file is manually edited and manipulated, so the check is important to avoid sudden crashes
of novelWriter. if the file contains errors, novelWriter will automatically build it anew. If the
check somehow fails and novelWriter keeps crashing, you can delete the file manually and rebuild
the index. If this too fails, you have likely encountered a bug.
Cached GUI Options
------------------
A file named ``meta/guiOptions.json`` contains the latest state of various GUI buttons, switches,
dialog window sizes, column sizes, etc, from the GUI. These are the GUI settings that are specific
to the project. Global GUI settings are stored in the main config file.
The file is not critical, but if it is lost, all such GUI options will revert back to their default
settings.
Session Stats
-------------
The writing progress is saved in the ``meta/sessionStats.log`` 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.
Project Cache
=============
The project ``cache`` folder contains non-critical files. If these files are lost, there is no
impact on the functionality of novelWriter or the history of the project. It contains temporary
files, like the preview document in the :guilabel:`Build Novel Project` tool.
It should be excluded from version control tools if such are used.

View File

@@ -14,7 +14,7 @@ Header Formatting
=================
The titles for the five types of titles (the chapter headings come in a numbered and unnumbered
version) of story structure can be formatted collectively in the export tool. This is done through
version) of story structure can be formatted collectively in the build tool. This is done through
a series of keyword–replace steps. They are all on the format ``%keyword%``.
``%title%``
@@ -22,20 +22,20 @@ a series of keyword–replace steps. They are all on the format ``%keyword%``.
your document.
``%ch%``
This is replaced by a chapter number. The number is incremented by one each time the build tool
sees a new heading of level two in a document with layout :guilabel:`Chapter`. If the document
has layout :guilabel:`Unnumbered`, the counter is *not* incremented. The latter is useful for
for instance Prologue and Epilogue chapters.
This will be replaced by a chapter number. The number is incremented by one each time the build
tool sees a new heading of level two in a document with layout :guilabel:`Chapter`. If the
document has layout :guilabel:`Unnumbered`, the counter is *not* incremented. The latter is
useful for for instance Prologue and Epilogue chapters. Adding an asterisk (``*``) in front of
the title text of a level two heading will also disable the chapter counter for that heading.
``%chw%``
This is like ``%ch%``, but the number is expressed as a word like for instance "One", "Two",
etc.
Behaves like ``%ch%``, but the number is represented as a number word.
``%chi%``
This is also like ``%ch%``, but the number is represented as a lower case Roman number.
Begaves like ``%ch%``, but the number is represented as a lower case Roman number.
``%chI%``
This is also like ``%ch%``, but the number is represented as an upper case Roman number.
Behaves like ``%ch%``, but the number is represented as an upper case Roman number.
``%sc%``
This is the number counter equivalent for scenes. These are incremented each time a heading of
@@ -43,8 +43,8 @@ a series of keyword–replace steps. They are all on the format ``%keyword%``.
used for counting scenes within a chapter.
``%sca%``
This is like ``%sc%``, but the number is *not* reset to 1 for each chapter. Instead it runs from
1 from the beginning of the novel.
Behaves like ``%sc%``, but the number is *not* reset to 1 for each chapter. Instead it runs from
1 from the beginning of the novel to produce an absolute scene count.
``\\``
This inserts a line break within the title.
@@ -67,11 +67,12 @@ Scene Separators
================
If you don't want any titles for your scenes (or for your sections if you have them), you can leave
the boxes empty. If so, an empty paragraph will be inserted between the scenes or sections instead.
the formatting boxes empty. If so, an empty paragraph will be inserted between the scenes or
sections instead.
Alternatively, if you want a separator between them, like the common ``* * *``, you can also enter
that in the box. In fact, if the format is a piece of static text, it will always be treated as a
separator.
Alternatively, if you want a separator between them, like the common ``* * *``, you can enter the
desired separator text in the formatting box. In fact, if the format is a piece of static text, it
will always be treated as a separator.
.. _a_export_files:
@@ -82,8 +83,8 @@ File Selection
Which documents and notes are selected for export can be controlled from the options on the left
side of the dialog window. The switch for :guilabel:`Include novel files` will select any document
that isn't classified as a note. The switch for :guilabel:`Include note files` will select any
document that *is* a note. This is allows for exporting just the novel, just your notes, or both,
as you see fit.
document that *is* a note. This allows for exporting just the novel, just your notes, or both, as
you see fit.
In addition, you can select to export the synopsis comments, regular comments, keywords, and even
exclude the body text itself.
@@ -101,6 +102,16 @@ document has a checkmark after the status icon in the :guilabel:`Flags` column.
override these settings.
.. _a_export_print:
Printing
========
The print button allows you to print the content in the preview window. You can either print to one
of your system's printers, or print directly to file. You can also print to file from the regular
print dialog. The direct to file option is just a shortcut.
.. _a_export_formats:
Export Formats
@@ -108,35 +119,25 @@ Export Formats
Currently, six formats are supported for exporting.
OpenDocument Format
This produces an open document ``.odt`` file. The document produced has very little formatting,
and may require further editing afterwards. For a better formatted office document, you may get
a better result with exporting to HTML and then import that HTML document into your office word
processor. They are generally very good at importing HTML documents.
PDF Format
The PDF export is just a shortcut for print to file. For a better PDF result, you may instead
want to export to HTML, and use a word processor to convert the HTML document to PDF.
Open Document Format
The Build tool can produce either an ``.odt`` file, or an ``.fodt`` file. The latter is just a
flat version of the document format as a single XML file.
novelWriter HTML
The HTML export format writes a single ``.htm`` file with minimal style formatting. The exported
HTML document is suitable for further processing by document conversion tools like Pandoc, for
importing in word processors, or for printing from browser. It is generally the best formatted
export option and supports all features of novelWriter since it is entirely geenrated by the
application and doesn't depend on Qt library features.
importing in word processors, or for printing from browser.
novelWriter Markdown
This is simply a concatenation of the project documents selected by the filters. The documents
are stacked together in the order they appear in the project tree, with comments, tags, etc.
are stacked together in the order they appear in the project tree, with comments, tags, etc.
included if they are selected. This is a useful format for exporting the project for later
import back into novelWriter.
Standard Markdown
If you have Qt 5.14 or higher, the option to export to plain markdown is available. This feature
uses Qt's own markdown export feature.
Plain Text
The plain text export format writes a simple ``.txt`` file without any formatting at all.
Standard/GitHub Markdown
The Markdown export format comes in both Standard and GitHub flavour. The *only* difference in
terms of novelWriter functionality is the support of strikethrough text, which is not supported
by the Standard flavour, but *is* supported by the GitHub flavour.
.. _a_export_options:
@@ -146,11 +147,11 @@ Additional Export Options
In addition to the above document formats, the novelWriter HTML and Markdown formats can also be
wrapped in a JSON file. These files will have a meta data entry and a body entry. For HTML, also
accompanying css styles are exported.
the accompanying css styles are exported.
The text body is saved in a two-level list. The outer list contains one entry per exported file, in
the order they appear in the project tree. Each file is then split up into a list as well, with one
entry per paragraph in the document.
The text body is saved in a two-level list. The outer list contains one entry per exported
document, in the order they appear in the project tree. Each document is then split up into a list
as well, with one entry per paragraph it contains.
These files are mainly intended for scripted post-processing for those who want that option. A JSON
file can be imported directly into a Python dict object or a PHP array, to mentions a few options.

View File

@@ -0,0 +1,437 @@
.. _a_ui:
**************
User Interface
**************
The user interface is kept as simple as possible to avoid distractions when writing. This page
lists all the main GUI elements, and explains what they do.
.. _a_ui_tree:
The Project Tree
================
The main window contains a project tree in the left-most panel. It shows the entire structure of
the project. It has four columns:
:guilabel:`Label`
The first column shows the item icon and its label. The labels can be edited from the
:guilabel:`Project` menu, or by pressing :kbd:`F2` or :kbd:`Ctrl`:kbd:`E`. The label is not the
same as the title you set inside the document, but it will appear in the header above the
document text itself.
:guilabel:`Words`
The second column shows the word count of the document, or the sum of words of the child items
if it is a folder. If the counts seem incorrect, they can be updated by rebuilding the project
index from the :guilabel:`Tools` menu, or by pressing :kbd:`F9`.
:guilabel:`Inc`
The third column indicates whether the document is included in the final project build or not.
You may want to filter out documents that you no longer want to keep in the final manuscript,
but want to keep in the project for reference.
:guilabel:`Flags`
The fourth column shows various meta data flags for the item. The first is an icon indicating
the importance or status of the document. These are colour coded status levels that you control
and define yourself. They can be changed in :guilabel:`Project Settings` from the
:guilabel:`Project` menu. The first character after the icon indicates the class of the item,
that is ``N`` for **Novel**, ``C`` for **Character**, etc (see :ref:`a_struct_tags`). The
characters after the dot indicate the document layout type (see :ref:`a_proj_roots`).
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.
Below the project tree you will find a small details panel showing the full information of the
currently selected item. This panel also includes the latest paragraph and character counts in
addition to the word count.
.. _a_ui_tree_novel:
The Novel Tree
--------------
An alternative way to view the project structure is the novel tree. You can switch to this view by
selecting the :guilabel:`Novel` tab under the project tree. This view is a simplified version of
the view in the :guilabel:`Outline`. 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 tree as that would imply restructuring the
content of the document files.
.. _a_ui_tree_status:
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 in their respective tabs in :guilabel:`Project Settings`. The
"Status" flag is intended to tag a Novel document as for instance a draft or as completed, and the
"Importance" flag is intended to tag character notes, or other notes, as for instance a main, major
or minor character.
Whether a document uses a "Status" or "Importance" flag depends on which root folder it lives in.
If it's in the :guilabel:`Novel` folder, it uses the "Status" flag, otherwise it uses an
"Importance" flag. Some folders, like :guilabel:`Trash` and :guilabel:`Outtakes` allow both.
.. _a_ui_tree_dnd:
Project Tree Drag & Drop
------------------------
The project tree allows drag & drop to a certain extent. This feature is primarily intended for
rearranging the order of your documents within each root folder, and has only limited support for
moving documents elsewhere in the project tree. In general, bulk actions are not allowed. This is
deliberate to avoid accidentally messing up your project. If you make a mistake, the last move
action can be undone by pressing :kbd:`Ctrl`:kbd:`Shift`:kbd:`Z`.
Documents and their folders can be rearranged freely within their root folders. Novel documents
cannot be moved out of the :guilabel:`Novel` folder, except to :guilabel:`Trash` and the
:guilabel:`Outtakes` folders. Notes can be moved freely between all root folders, but keep in mind
that if you move a note into a :guilabel:`Novel`, its "Importance" setting will be reset to the
default "Status" setting. See :ref:`a_ui_tree_status`.
Folders cannot be moved at all outside their root tree. Neither can a folder containing documents
be deleted. You must first delete the containing documents.
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 eachother from the :guilabel:`Project` menu, the
right-click context menu, or by pressing :kbd:`Ctrl`:kbd:`Shift` and the :kbd:`Up` or :kbd:`Down`
key.
.. _a_ui_edit:
Editing and Viewing Documents
=============================
To edit a document, double-click it in the project tree, or press the :kbd:`Return` key while
having it selected. This will open the document in the document editor. The editor uses a
simplified markdown format. The format is described in the :ref:`a_ui_md` section below. The editor
has a maximise button (toggles the :guilabel:`Focus Mode`) and a close button in the top-right
corner.
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`:kbd:`R`, or select :guilabel:`View Document` in the
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 currently being edited. However,
If you *are* viewing the same document, pressing :kbd:`Ctrl`:kbd:`R` again will update the document
with your latest changes. You can also press the reload button in the top-right corner of the view
panel next to the close button to achieve the same thing.
Both the document editor and viewer will show the label of the 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` from the :guilabel:`Tools` menu. Clicking on the document title bar
will select and reveal its location in the project tree, making it easier to locate in a large
project.
Any tag reference in the editor can be opened in the viewer by moving the cursor to the label and
pressing :kbd:`Ctrl`:kbd:`Return`. You can also control-click them with your mouse. In the viewer,
the references become clickable links. Clicking them will replace the 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 back and forward navigation buttons, these can be used as well. They work just like
the backward and forward features in a browser.
At the bottom of the view panel there is a :guilabel:`References` panel. (If it is hidden, click
the icon to reveal it.) This panel will show links to all documents referring back to the one
you're currently viewing, if any has been defined. The :guilabel:`Sticky` button will freeze the
content of the panel to the current document, even if you navigate to another document. This is
convenient if you want to quickly look through all documents in the list in the
:guilabel:`References` panel without losing the list in the process.
.. note::
The :guilabel:`References` panel relies on an up-to-date 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`.
.. _a_ui_edit_search:
Search & Replace
----------------
The document editor has a search and replace bar that can be activated with :kbd:`Ctrl`:kbd:`F` for
search mode or :kbd:`Ctrl`:kbd:`H` for search/replace mode.
Pressing :kbd:`Return` while in the search box will search for the next occurrence of the word, and
:kbd:`Shift`:kbd:`Return` for the previous. Pressing :kbd:`Return` in the replace box, will replace
the highlighted text and move to the next word.
There are a number of settings for the search bar available as toggle switches above the search
box. They allows you to search for, in order:,: matched case only, whole word results only, search
using regular expressions, loop search when reaching the end of the document, and move to the next
document when reaching the end. There is also a switch that will try to match the case of the word
when the replacement is made. That is, it will try to keep the word upper, lower, or capitalised to
match the word being replaced.
The regular expression search is somewhat dependant on which version of Qt your system has. If you
have Qt 5.13 or higher, there is better support for unicode symbols in the search.
.. _a_ui_edit_auto:
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.
.. tip::
If you don't like auto-replacement, all symbols inserted by this feature are also available in
the :guilabel:`Insert` menu, and via convenient :ref:`a_kb_ins`. You may also be using a
`Compose Key`_ setup, which means you may not need the auto-replace feature.
.. _Compose Key: https://en.wikipedia.org/wiki/Compose_key
The editor is able to replace two and three hyphens with short and long dashes, triple points with
ellipsis, and replace straight single and double quotes with user-defined quote symbols. It will
also try to determine whether to use the opening or closing symbol, although this feature isn't
always accurate. Especially distinguishing between closing single quote and apostrophe can be
tricky for languages that use the same symbol for these.
.. tip::
If the auto-replace feature changes a symbol when you did not want it to change, pressing
:kbd:`Ctrl`:kbd:`Z` immediately after the auto-replacement will undo it without undoing the
character you typed.
.. _a_ui_md:
The Markdown-Like Format
========================
The editor itself is a plaintext editor that uses formatting codes for setting meta data values and
allowing for some text formatting. The syntax is based on Markdown, but novelWriter is *not* a
Markdown editor. It supports basic formatting like emphasis (italic), strong importance (bold)
and strikethrough text, as well as four levels of headings.
In addition to formatting codes, novelWriter allows for comments, a synopsis tag, and a set of
keyword and value sets used for tags and references.
.. _a_ui_md_head:
Headings
--------
Four levels of headings are allowed. For documents of layout ``Note``, they are free to be used as
you see fit, but for all other layouts used for the novel text itself, they indicate the structural
level of the novel. See :ref:`a_struct_heads` for more details.
``# Title``
Heading level one. If the document is a novel file, the header level indicates the start of a
new partition. This heading level can also be used for the title page's novel title.
``## Title``
Heading level two. If the document is a novel file, the header level indicates the start of a
new chapter. Chapter numbers can be inserted automatically when exporting the manuscript.
``### Title``
Heading level three. If the document is a novel file, the header level indicates the start of a
new scene. Scene numbers or scene separators can be inserted automatically when exporting the
manuscript, so you can use the title field as a working title for your scenes if you wish.
``#### Title``
Heading level four. If the document is a novel file, the header level indicates the start of a
new section. Section titles can be replaced by separators or removed when exporting the
manuscript, so you can use the title field as a working title for your sections if you wish.
.. note::
The space after the ``#`` characters is mandatory. The syntax highlighter will change colour and
font size when the heading is correctly formatted.
.. tip::
If you do use the automatic numbering feature for exports, you can tell the export tool to skip
assigning a number to a specific chapter by adding a ``*`` as the first character of the title
itself. See :ref:`a_struct_heads_unnum` for more details.
.. _a_ui_md_text:
Text Paragraphs
---------------
A text paragraph is indicated by a blank line. That is, you need two line breaks to separate two
fragments of text into two paragraphs. Single line breaks are treated as line breaks within a
paragraph.
In addition, the editor supports a few additional types of whitespaces.
* A non-breaking space can be inserted with :kbd:`Ctrl`:kbd:`K`, :kbd:`Space`.
* Thin spaces are also supported, and can be inserted with :kbd:`Ctrl`:kbd:`K`,
:kbd:`Shift`:kbd:`Space`.
* Non-breaking thin space can be inserted with :kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`Space`.
These are all insert features, and the :guilabel:`Insert` menu has more. They 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.
.. tip::
Non-breaking spaces are the correct type of space to separate a number from its unit. Generally,
it prevents the line wrapping algorithms from adding line breaks where it shouldn't.
.. _a_ui_md_align:
Paragraphs Alignment and Indentation
------------------------------------
Aside from Title Page and Partition which by default have its text centred, all document layouts
have the text by default aligned to the left ot justified, depending on your 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
the paragraph, and they will "push" the text towards the edge the brackets point towards. This
should be fairly intuitive.
Indentation uses a similar syntax. But here you use a single ``>`` or ``<`` to push the text away
from the edge.
Examples:
.. csv-table:: Text Alignment and Indentation
:header: "Syntax", "Description"
:widths: 40, 60
:class: "tight-table"
"``>> Right aligned text``", "The text paragraph is right-aligned."
"``Left aligned text <<``", "The text paragraph is left-aligned."
"``>> Centred text <<``", "The text paragraph is centred."
"``> Indented text``", "The text has an increased left margin."
"``Indented text <``", "The text has an increased right margin."
"``> Indented text <``", "The text has an both margins increased."
.. note::
The text editor will not show the alignment and indentation live. But the viewer will show them
when you open the document in the viewer. It will of course also be reflected in the document
generated from the build tool.
.. _a_ui_md_emph:
Text Emphasis
-------------
A minimal set of text emphasis styles are supported.
``_text_``
The text is rendered as emphasised text (italicised).
``**text**``
The text is rendered as strongly important text (bold).
``~~text~~``
Strikethrough text.
In markdown guides it is often recommended to differentiate between strong importance 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
recommendation.
In addition, the following rules apply:
1. The emphasis and strikethrough formatting tags do not allow spaces between the words and the tag
itself. That is, ``**text**`` is valid, ``**text **`` is not.
2. More generally, the delimiters must be on the outer edge of words. That is, ``some **text in
bold** here`` is valid, ``some** text in bold** here`` is not.
3. If using both ``**`` and ``_`` to wrap the same text, the underscore must be the inner wrapper.
This is due to the underscore also being a valid word character, so if they are on the outside,
they violate rule 2.
4. Text emphasis does not span past line breaks. If you need to add emphasis to multiple lines or
paragraphs, you must apply it to each of them in turn.
.. _a_ui_md_comm:
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
exporting or viewing the document.
If the first word of a comment is ``Synopsis:`` (with the colon included), the comment is treated
specially 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...``
This is a comment. The text is not exported by default (this can be overridden), seen in the
document viewer, or counted towards word counts.
``% Synopsis: 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 exporting the project to for instance generate an outline
document of the whole project.
.. note::
Only one comment can be flagged as a synopsis comment for each heading. If multiple comments are
flagged as synopsis comments, the last one will be used and the rest ignored.
.. _a_ui_md_tags:
Tags and References
-------------------
The document editor supports a minimal set of keywords used for setting tags, and making references
between documents. The tags and references can be set once per section defined by a heading. Using
them multiple times under the same heading will just override the previous setting.
``@keyword: value``
A keyword argument followed by a value, or a comma separated list of values.
The available tag and reference keywords are listed in the :ref:`a_struct_tags` section. They can
also be inserted at the cursor position in the editor via the :guilabel:`Insert` menu.
.. _a_ui_outline:
Project Outline View
====================
The project's Outline view is available as the second tab on the right hand side of the main window
labelled :guilabel:`Outline`. 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 it occurs. Double-clicking an entry will open the corresponding document in the
editor.
.. note::
Since the internal structure of the novel does not depend directly on the folder and document
structure of the project tree, these will not necessarily look the same, depending on how you
choose to organise your documents. See the :ref:`a_struct` page for more details.
Various meta data and information extracted from tags can be displayed in columns in the outline.
A default set of such columns is visible, but you can turn on or off more columns by right clicking
the header and selecting the columns you want to show. The order of the columns can also be
rearranged by dragging them to a different position.
.. note::
The :guilabel:`Title` column cannot be disabled or moved.
The information viewed in the outline is based on the project's main index. While novelWriter does
its best to keep the index up to date when contents change, you can always rebuild it manually by
pressing :kbd:`F9` if something isn't right.
The outline view itself can be regenerated by pressing :kbd:`F10`. You can also enable automatic
updating in the :guilabel:`Tools` menu, which will trigger an update whenever the index is updated
and the :guilabel:`Outline` tab is active. You may want to disable this feature if your project is
very large,
The :guilabel:`Synopsis` column of the outline view takes its information from a specially
formatted comment. See :ref:`a_ui_md_comm`.

View File

@@ -4,16 +4,18 @@
Project Notes
*************
novelWriter doesn't have a database and complicated forms to fill in all details about plot
novelWriter doesn't have a database and complicated forms for filling in details about plot
elements, characters, and all sorts of additional information that isn't a part of the novel text
itself. Instead, all such information is saved in notes. The relation between all these additional
elements is extracted from these documents by the project indexer based on the tags and references
you set.
itself. Instead, all such information is saved in notes that are written and maintained just like
all other text in your project.
These notes are not required, but making at least minimal files for each such plot element, and
adding a tag to them, makes it possible to use the :guilabel:`Outline` feature to see how each
element intersects with each section of the novel itself, and adds clickable cross-references
between documents in the editor and viewer.
The relation between all these additional elements is extracted from the documents and notes by the
project indexer, based on the tags and references you set within them.
Using notes is not required, but making at least minimal notes for each plot element, and adding a
tag to them, makes it possible to use the :guilabel:`Outline` feature to see how each element
intersects with each section of the novel itself, and adds clickable cross-references between
documents in the editor and viewer.
.. _a_notes_tags:
@@ -24,7 +26,8 @@ Tags in Notes
Each new heading in a note can have a tag associated with it. The format of a tag is
``@tag: tagname``, where tagname is a unique identifier. Tags can then be referenced in the novel
documents, or cross-referenced in other notes, and will show up in the outline view and in the
back-reference panel when a document is being viewed.
back-reference panel when a document is being viewed. See :ref:`a_struct_tags` for how to reference
notes.
The syntax highlighter will alert the user that the keyword is correctly used and that the tag is
allowed, that is, the tag is unique. Duplicate tags should be detected as long as the index is up
@@ -43,5 +46,5 @@ meaningful if you want to be able to click-navigate between them.
.. tip::
If you cross-reference between notes and export your project as an HTML document using the
:guilabel:`Build Novel Project` tool, the cross-references become clickable in the exported
HTML document as well.
:guilabel:`Build Novel Project` tool, the cross-references become clickable links in the
exported HTML document.

View File

@@ -4,18 +4,20 @@
Novel Projects
**************
A novelWriter project requires a dedicated folder for storing its files on the local file system.
See the :ref:`a_tech` page for further details on how files are organised.
A new project can be created from the :guilabel:`Project` menu by selecting
:guilabel:`New Project`. This will open the :guilabel:`New Project Wizard` that will assist you in
creating a barebone project suited to your needs.
creating a barebone project suited to your needs. A novelWriter project requires a dedicated folder
for storing its files on the local file system. See :ref:`a_tech` for further details on how files
are organised.
A list of recently opened projects is maintained, and displayed in the :guilabel:`Open Project`
dialog. A project can be removed from this list by selecting it and pressing the :kbd:`Del` key.
dialog. A project can be removed from this list by selecting it and pressing the :kbd:`Del` key or
by clicking the :guilabel:`Remove` button.
The 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.
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,
including word counts, and a table of contents with word and page counts, is available through the
:guilabel:`Project Details` dialog.
.. _a_proj_roots:
@@ -28,7 +30,7 @@ the project tree at the left side of the main window.
The core novel documents go into a root folder of type :guilabel:`Novel`. Other supporting
documents go into the other root folders. These other root folder types are intended for your notes
on the various elements of your story. Using these is of course entirely optional.
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
:guilabel:`Create Root Folder` in the :guilabel:`Project` menu.
@@ -38,8 +40,8 @@ no restrictions are enforced by the application. You can use them however you wa
:guilabel:`Novel`
This is the root folder of all text that goes into the final novel. This class of documents have
other rules and features than other documents in the project. See the :ref:`a_struct` page for
more details.
other rules and features than other documents in the project. See :ref:`a_struct` for more
details.
:guilabel:`Plot`
This is the root folder where main plots can be outlined. It is optional, but adding at least
@@ -49,8 +51,9 @@ no restrictions are enforced by the application. You can use them however you wa
:guilabel:`Characters`
Character notes go in this root folder. These are especially important if one wants to use the
Outline view to see which character appears where, and which part of the story is told from a
specific character's point-of-view. Tags in this folder can be references using the ``@pov``
keyword for point-of-view characters, or the ``@char`` keyword for other characters.
specific character's point-of-view or focusing on a particular character's storyline. Tags in
this 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 characters.
:guilabel:`Locations`
The locations folder is for various scene locations that you want to track. Tags in this folder
@@ -79,8 +82,8 @@ information about the tags listed, see :ref:`a_struct_tags`.
.. tip::
You can rename root folders to whatever you want. The first character in the :guilabel:`Flags`
column will still indicate what type they are, and so will the icon if you are using one of the
Typicons icon sets.
column in the project tree will still indicate what type they are, and so will the icon if you
are using one of the optional icon sets.
.. _a_proj_roots_del:
@@ -95,7 +98,7 @@ referenced.
Folders and root folders can only be deleted when they are empty. Recursive deletion is not
supported. A document or a folder can be deleted from the :guilabel:`Project` menu, or by pressing
:kbd:`Ctrl`:kbd:`Del`.
:kbd:`Ctrl`:kbd:`Shift`:kbd:`Del`.
.. _a_proj_roots_out:
@@ -105,9 +108,9 @@ Archived Documents (Outtakes)
If you don't want to delete a document, or put it in the :guilabel:`Trash` folder where it may be
deleted, but still want it out of your main project tree, you can create an :guilabel:`Outtakes`
root folder from the :guilabel:`Project` menu. You are not allowed to move folders to this root
folder, only documents. If you need folders in it to organise your documents, you can of course
create new ones there.
root folder from the :guilabel:`Project` menu. You are not allowed to move entire folders to this
root folder, only documents. If you need folders in it to organise your documents, you can of
course create new ones there.
You can drag any document to this folder and preserve its settings. The document will always be
excluded from the :guilabel:`Build Novel Project` builds. It is also removed from the project
@@ -157,7 +160,8 @@ this warning, and continue opening the project at your own risk.
If you choose to ignore the warning and continue opening the project, and multiple instances of
the project are in fact open, you are likely to cause inconsistencies and create diverging
project files, potentially resulting in loss of data and orphaned files. You are not likely to
lose any actual text unless both instances have the same document open in the editor,
lose any actual text unless both instances have the same document open in the editor, and
novelWriter will try to resolve inconsistencies the next time you open the project.
.. _a_proj_roots_dirs:
@@ -174,9 +178,9 @@ and to be able to collapse and hide them in the project tree when you're not wor
documents.
.. tip::
You can use folders to sort your scene documents into chapters. You will then need to add a
chapter documents as the first item of your folder, and the scene documents as the following
items.
You can use folders to sort your scene documents into chapters. You will still need to add a
chapter document as the first item of your chapter folder, and the scene documents as the
following items. Another way to use folders is to make a folder for each act.
.. _a_proj_files:
@@ -208,7 +212,7 @@ Word Counts
A character, word and paragraph count is maintained for each document, as well as for each section
of a document following a header. 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 project tree for any document selected in the project tree.
panel below the project tree for any document selected in the project or novel tree.
The word counts are not updated in real time, but run in the background every five seconds for as
long as the document is being actively edited.
@@ -243,13 +247,9 @@ The :guilabel:`Book Title` and :guilabel:`Book Authors` settings are currently n
anything, so setting then is just for the benefit of the author. Future features may be using them,
and they are exported on some export formats in the :guilabel:`Build Novel Project` tool.
Details Tab
-----------
This tab presents an overview of meta data for the project. It states where on your file system the
project is saved, how may times it has been saved, how many folders and documents it contains, and
how many words exist in the entire project.
If your project is in a different language than your main spell checking is set to, you can
override the default spell checking language here. You can also override the automatic backup
setting.
Status and Importance Tabs
@@ -265,6 +265,8 @@ use these to indicate at what stage of completion each novel document is, or how
content of a note is to the plot. You don't have to use them this way, that's just what they were
intended for, but you can make them whatever you want.
See also :ref:`a_ui_tree_status`.
.. note::
The status or importance level currently in use by one or more documents cannot be deleted, but
they can be edited.
@@ -277,13 +279,14 @@ A set of automatically replaced keywords can be added in this tab. The keywords
will be replaced by the text in the right column when documents are opened in the viewer. They will
also be applied to exports.
The auto-replace feature will replace text in angle brackets that are also in this list. The syntax
highlighter will add an alternate colour to text marching the syntax.
The auto-replace feature will replace text in angle brackets that are in this list. The syntax
highlighter will add an alternate colour to text marching the syntax, but it doesn't check if the
text is in this list.
.. note::
A keyword cannot contain any spaces. The angle brackets are added by default, and when used in
the text are a part of the keyword to be replaced. This is to ensure that parts of the text
aren't unintentionally replaced by the content of the list.
A keyword cannot contain spaces. The angle brackets are added by default, and when used in the
text are a part of the keyword to be replaced. This is to ensure that parts of the text aren't
unintentionally replaced by the content of the list.
.. _a_proj_backup:
@@ -295,9 +298,9 @@ An automatic backup system is built into novelWriter. In order to use it, a back
the backup files are to be stored must be provided in :guilabel:`Preferences`.
Backups can be run automatically when a project is closed, which also implies it is run when the
application is closed. Backups are date stamped zip files of the entire project folder, and are
stored in a subfolder of the backup path with the same name as the project :guilabel:`Working
Title` set in :ref:`a_proj_settings`.
application itself is closed. Backups are date stamped zip files of the entire project folder, and
are stored in a subfolder of the backup path. The subfolder will have the same name as the project
:guilabel:`Working Title` set 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 backup for a given project in :guilabel:`Project
@@ -306,7 +309,7 @@ Settings`.
.. note::
For the backup to be able to run, the :guilabel:`Working Title` must be set in
:guilabel:`Project Settings`. This value is used to generate the folder name for the zip files.
Without it, the backup will not run at all, but produce a warning message.
Without it, the backup will not run at all, but it will produce a warning message.
.. _a_proj_stats:
@@ -325,3 +328,8 @@ A tool to view the content of this file is available in the :guilabel:`Tools` me
The tool will show a list of all your sessions, and a set of filters to apply to it. You can also
export the filtered data to a JSON file or to a CSV file that can be opened by a spreadsheet
application like for instance Libre Office Calc.
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, and 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`.

View File

@@ -0,0 +1,147 @@
.. _a_kb:
******************
Keyboard Shortcuts
******************
Most features in novelWriter are available as keyboard shortcuts.
.. _a_kb_main:
Main Shortcuts
==============
The main shorcuts are as follows:
.. csv-table:: Keyboard Shortcuts
:header: "Shortcut", "Description"
:widths: 30, 70
:class: "tight-table"
":kbd:`Alt`:kbd:`1`", "Switch focus to the project tree. On Windows, use :kbd:`Ctrl`:kbd:`Alt`:kbd:`1`."
":kbd:`Alt`:kbd:`2`", "Switch focus to document editor. On Windows, use :kbd:`Ctrl`:kbd:`Alt`:kbd:`2`."
":kbd:`Alt`:kbd:`3`", "Switch focus to document viewer. On Windows, use :kbd:`Ctrl`:kbd:`Alt`:kbd:`3`."
":kbd:`Alt`:kbd:`4`", "Switch focus to outline view. On Windows, use :kbd:`Ctrl`:kbd:`Alt`:kbd:`4`."
":kbd:`Alt`:kbd:`Left`", "Move backward in the view history of the document viewer."
":kbd:`Alt`:kbd:`Right`", "Move forward in the view history of the document viewer."
":kbd:`Ctrl`:kbd:`.`", "Open menu to correct word under cursor."
":kbd:`Ctrl`:kbd:`,`", "Open the :guilabel:`Preferences` dialog."
":kbd:`Ctrl`:kbd:`/`", "Toggle block format as comment."
":kbd:`Ctrl`:kbd:`0`", "Remove block formatting for block under cursor."
":kbd:`Ctrl`:kbd:`1`", "Change block format to header level 1."
":kbd:`Ctrl`:kbd:`2`", "Change block format to header level 2."
":kbd:`Ctrl`:kbd:`3`", "Change block format to header level 3."
":kbd:`Ctrl`:kbd:`4`", "Change block format to header level 4."
":kbd:`Ctrl`:kbd:`5`", "Change block alignment to left-aligned."
":kbd:`Ctrl`:kbd:`6`", "Change block alignment to centred."
":kbd:`Ctrl`:kbd:`7`", "Change block alignment to right-aligned."
":kbd:`Ctrl`:kbd:`8`", "Add a left margin to the block."
":kbd:`Ctrl`:kbd:`9`", "Add a right margin to the block."
":kbd:`Ctrl`:kbd:`A`", "Select all text in the document."
":kbd:`Ctrl`:kbd:`B`", "Format selected text, or word under cursor, with strong emphasis (bold)."
":kbd:`Ctrl`:kbd:`C`", "Copy selected text to clipboard."
":kbd:`Ctrl`:kbd:`D`", "Strikethrough selected text, or word under cursor."
":kbd:`Ctrl`:kbd:`E`", "If in the project tree, edit a document or folder settings. (Same as :kbd:`F2`.)"
":kbd:`Ctrl`:kbd:`F`", "Open the search bar and search for the selected word, if any is selected."
":kbd:`Ctrl`:kbd:`G`", "Find next occurrence of search word in current document. (Same as :kbd:`F3`.)"
":kbd:`Ctrl`:kbd:`H`", "Open the search and replace bar and search for the selected word, if any is selected. (On Mac, this is :kbd:`Cmd`:kbd:`=`.)"
":kbd:`Ctrl`:kbd:`I`", "Format selected text, or word under cursor, with emphasis (italic)."
":kbd:`Ctrl`:kbd:`K`", "Activate the insert commands. The commands are listed in :ref:`a_kb_ins`."
":kbd:`Ctrl`:kbd:`N`", "Create new document."
":kbd:`Ctrl`:kbd:`O`", "Open selected document."
":kbd:`Ctrl`:kbd:`Q`", "Exit novelWriter."
":kbd:`Ctrl`:kbd:`R`", "If in the project tree, open a document for viewing. If the editor has focus, open current document for viewing."
":kbd:`Ctrl`:kbd:`S`", "Save the current document in the document editor."
":kbd:`Ctrl`:kbd:`V`", "Paste text from clipboard to cursor position."
":kbd:`Ctrl`:kbd:`W`", "Close the current document in the document editor."
":kbd:`Ctrl`:kbd:`X`", "Cut selected text to clipboard."
":kbd:`Ctrl`:kbd:`Y`", "Redo latest undo."
":kbd:`Ctrl`:kbd:`Z`", "Undo latest changes."
":kbd:`Ctrl`:kbd:`F7`", "Toggle spell checking."
":kbd:`Ctrl`:kbd:`F10`", "Toggle automatic updating of project outline."
":kbd:`Ctrl`:kbd:`Up`", "Move item one step up in the project tree."
":kbd:`Ctrl`:kbd:`Down`", "Move item one step down in the project tree."
":kbd:`Ctrl`:kbd:`Del`", "Delete next word in editor."
":kbd:`Ctrl`:kbd:`Backspace`", "Delete previous word in editor."
":kbd:`Ctrl`:kbd:`'`", "Wrap selected text, or word under cursor, in single quotes."
":kbd:`Ctrl`:kbd:`""`", "Wrap selected text, or word under cursor, in double quotes."
":kbd:`Ctrl`:kbd:`Retrun`", "Open the tag or reference under the cursor in the Viewer."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`,`", "Open the :guilabel:`Project Settings` dialog."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`/`", "Remove block formatting for block under cursor."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`1`", "Replace occurrence of search word in current document, and search for next occurrence."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`A`", "Select all text in current paragraph."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`G`", "Find previous occurrence of search word in current document. (Same as :kbd:`Shift`:kbd:`F3`.)"
":kbd:`Ctrl`:kbd:`Shift`:kbd:`I`", "Import text to the current document from a text file."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`N`", "Create new folder."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`O`", "Open a project."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`R`", "Close the document viewer."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`S`", "Save the current project."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`W`", "Close the current project."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`Z`", "Undo move of project tree item."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`Del`", "If in the project tree, move a document to trash, or delete a folder."
":kbd:`F1`", "Open the documentation. This will either open the Qt Assistant, if available, or send you to the documentation website."
":kbd:`F2`", "If in the project tree, edit a document or folder settings. (Same as :kbd:`Ctrl`:kbd:`E`)"
":kbd:`F3`", "Find next occurrence of search word in current document. (Same as :kbd:`Ctrl`:kbd:`G`)"
":kbd:`F5`", "Open the :guilabel:`Build Novel Project` dialog."
":kbd:`F6`", "Open the :guilabel:`Writing Statistics` dialog."
":kbd:`F7`", "Re-run spell checker."
":kbd:`F8`", "Activate :guilabel:`Focus Mode`, hiding the project tree and document viewer."
":kbd:`F9`", "Re-build the project index."
":kbd:`F10`", "Re-build the project outline."
":kbd:`F11`", "Activate full screen mode."
":kbd:`Shift`:kbd:`F1`", "Open the online documentation in the system default browser."
":kbd:`Shift`:kbd:`F3`", "Find previous occurrence of search word in current document. (Same as :kbd:`Ctrl`:kbd:`Shift`:kbd:`G`.)"
":kbd:`Shift`:kbd:`F6`", "Open the :guilabel:`Project Details` dialog."
":kbd:`Return`", "If in the project tree, open a document for editing."
.. note::
On macOS, replace :kbd:`Ctrl` with :kbd:`Cmd`.
.. _a_kb_ins:
Insert Shortcuts
================
A set of insert features are also available through shortcuts, but they require a double
combination of key sequences. The insert feature is activated with :kbd:`Ctrl`:kbd:`K`, followed by
a key or key combination for the inserted content.
.. csv-table:: Keyboard Shortcuts
:header: "Shortcut", "Description"
:widths: 40, 60
:class: "tight-table"
":kbd:`Ctrl`:kbd:`K`, :kbd:`−`", "Insert a short dash (en dash)."
":kbd:`Ctrl`:kbd:`K`, :kbd:`_`", "Insert a long dash (em dash)."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`_`", "Insert a horizontal bar (quotation dash)."
":kbd:`Ctrl`:kbd:`K`, :kbd:`~`", "Insert a figure dash (same width as a number)."
":kbd:`Ctrl`:kbd:`K`, :kbd:`1`", "Insert a left single quote."
":kbd:`Ctrl`:kbd:`K`, :kbd:`2`", "Insert a right single quote."
":kbd:`Ctrl`:kbd:`K`, :kbd:`3`", "Insert a left double quote."
":kbd:`Ctrl`:kbd:`K`, :kbd:`4`", "Insert a right double quote."
":kbd:`Ctrl`:kbd:`K`, :kbd:`'`", "Insert a modifier apostrophe."
":kbd:`Ctrl`:kbd:`K`, :kbd:`.`", "Insert an ellipsis."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`'`", "Insert a prime."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`""`", "Insert a double prime."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Space`", "Insert a non-breaking space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Shift`:kbd:`Space`", "Insert a thin space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`Space`", "Insert a thin non-breaking space."
":kbd:`Ctrl`:kbd:`K`, :kbd:`*`", "Insert a list bullet."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`−`", "Insert a hyphen bullet (alternative bullet)."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`*`", "Insert a flower mark (alternative bullet)."
":kbd:`Ctrl`:kbd:`K`, :kbd:`%`", "Insert a per mille symbol."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`O`", "Insert a degree symbol."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`X`", "Insert a times sign."
":kbd:`Ctrl`:kbd:`K`, :kbd:`Ctrl`:kbd:`D`", "Insert a division sign."
":kbd:`Ctrl`:kbd:`K`, :kbd:`G`", "Insert a ``@tag`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`V`", "Insert a ``@pov`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`F`", "Insert a ``@focus`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`C`", "Insert a ``@char`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`P`", "Insert a ``@plot`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`T`", "Insert a ``@time`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`L`", "Insert a ``@location`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`O`", "Insert an ``@object`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`E`", "Insert an ``@entity`` keyword."
":kbd:`Ctrl`:kbd:`K`, :kbd:`X`", "Insert a ``@custom`` keyword."

View File

@@ -18,20 +18,22 @@ Importance of Headings
Subfolders under root folders have no impact on the structure of the novel itself. The structure is
instead dictated by the heading level of the headers within the documents.
Four levels of headings are supported, signified by the number of hashes preceding the title. See
also the :ref:`a_ui_md` section for more details about the markdown syntax.
Four levels of headings are supported, signified by the number of hashes (``#``) preceding the
title. See also the :ref:`a_ui_md` section for more details about the markdown syntax.
.. note::
The header levels are not only important when generating the exported novel file, they are also
used by the indexer when building the outline tree in the :guilabel:`Outline` tab. Each heading
also starts a new region where new references to tags can be set.
used by the indexer when building the outline tree in the :guilabel:`Outline` tab as well as the
:guilabel:`Novel` tab of the project tree. Each heading also starts a new region where new
references and tags can be defined.
The different header levels are interpreted as specific section types of the novel in the following
way:
``# Header1``
Header level one signifies that the text refers to either the novel title or the name of a top
level partition useful when you want to split the manuscript up into books, parts, or acts.
level partition. The latter is useful when you want to split the manuscript up into books,
parts, or acts.
``## Header2``
Header level two signifies a chapter level partition. Each time you want to start a new chapter,
@@ -47,10 +49,10 @@ way:
manuscript.
``#### Header4``
Header level four signifies a sub-scene level partition, usually called just a section in the
documentation and user interface. These can be useful if you want to change tag references
Header level four signifies a sub-scene level partition, usually called a "section" in the
documentation and the user interface. These can be useful if you want to change tag references
mid-scene, like if you change the point-of-view character. You are free to use sections as you
wish, and can filter the titles out of the final manuscript just like with scene titles.
wish, and can filter them out of the final manuscript just like with scene titles.
.. tip::
There are multiple options of how to process novel titles when exporting the manuscript. For
@@ -67,13 +69,13 @@ If you use layout types for your documents, the automatic numbering feature for
controlled by whether you use the :guilabel:`Chapter` or :guilabel:`Unnumbered` layout type for
your document. However, if you have a different document layout where this isn't practical, you can
also switch off chapter numbering for a chapter by making the first character of the chapter title
an ``*``. Like so:
an asterisk (``*``). Like so:
``## *Unnumbered Chapter Title``
The leading asterisk is only considered by the :guilabel:`Build Novel Project` tool, and will be
removed before inserted at the location of the ``%title%`` label. See the :ref:`a_export` page for
more details.
removed before the title is inserted at the location of the ``%title%`` label. See the
:ref:`a_export` page for more details.
.. note::
If you need the first character of the title to be an actual asterisk, you must escape it:
@@ -85,10 +87,11 @@ more details.
Tag References
==============
Each text partition indicated by a heading of any level, can contain references to tags set in the
supporting notes of the project. The references are gathered by the indexer and used to generate
the outline view on the :guilabel:`Outline` tab of how the different parts of the novel are
connected.
Each text partition, indicated by a heading of any level, can contain references to tags set in the
supporting notes of the project. The references are gathered by the indexer and used to generate an
outline view on the :guilabel:`Outline` tab of how the different parts of the novel are connected.
This section covers how to set references to tags. See :ref:`a_notes_tags` for how to define tags
the references can point to.
References and tags are also clickable in the document editor and viewer, making it easy to
navigate between reference notes while writing. Clicked links are always opened in the view panel.
@@ -101,28 +104,33 @@ allow multiple values.
The point-of-view character for the current section. The target must be a note tag in the
:guilabel:`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 the
:guilabel:`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 character(s).
Other characters in the current section. The target must be a note tag in the
:guilabel:`Character` type root folder. This should not include the point-of-view character.
``@plot``
The plot or subplot advanced in the current section. The target must be a note tag in a
The plot or subplot advanced in the current section. The target must be a note tag in the
:guilabel:`Plot` type root folder.
``@time``
The timelines touched by the current section. The target must be a note tag in a
The timelines touched by the current section. The target must be a note tag in the
:guilabel:`Timeline` type root folder.
``@location``
The location the current section takes place in. The target must be a note tag in a
The location the current section takes place in. The target must be a note tag in the
:guilabel:`Locations` type root folder.
``@object``
Objects present in the current section. The target must be a note tag in an :guilabel:`Object`
Objects present in the current section. The target must be a note tag in the :guilabel:`Object`
type root folder.
``@entity``
Entities present in the current section. The target must be a note tag in an
Entities present in the current section. The target must be a note tag in the
:guilabel:`Entities` type root folder.
``@custom``
@@ -142,15 +150,15 @@ the index for a document is regenerated when it is saved, so this shouldn't norm
Novel Document Layout
=====================
All documents in a novelWriter project can have a layout format set. These layouts are important
when the project is exported as they indicate how to treat the content in terms of formatting,
All documents in the project can have a layout format set. These layouts are important when the
project is exported as they indicate how to treat the content in terms of text formatting,
headings, and page breaks. The layout for each document is indicated as the last set of characters
in the :guilabel:`Flags` column of the project tree.
Not all layout types are actually treated differently, they also help to indicate what each
document is for in your project. The :guilabel:`Book` layout is a generic novel document layout
that is formatted identically to :guilabel:`Chapter` and :guilabel:`Scene` layout documents, but
may help to indicate what each document does in your project.
document is intended for in your project. The :guilabel:`Book` layout is a generic novel document
layout that is formatted identically to :guilabel:`Chapter` and :guilabel:`Scene` layout documents,
but may help to indicate what each document does in your project.
You can for instance lay out your project using :guilabel:`Book` documents for each act, and then
later split those into chapter or scene documents by using the :guilabel:`Split Document` tool.
@@ -163,15 +171,15 @@ Some layouts *do* have implications on how the project is exported. Documents wi
contained within it. The latter is convenient for Prologue and Epilogue type chapters.
The above layout formats are only usable in the Novel root folder. Documents that are not a part of
the novel itself should have the Note layout. These documents are not getting any special
formatting, and it is possible to collectively filter them out during export. Notes can be used
anywhere in the project, also in the Novel root folder.
the novel itself should have the :guilabel:`Note` layout. These documents are not getting any
special formatting, and it is possible to collectively filter them out during export. Notes can be
used anywhere in the project, also in the :guilabel:`Novel` root folder.
Below is an overview of all available layout formats.
:guilabel:`Title Page`
The title page layout. The title should be formatted as a heading level one. All text is
automatically centred on exports.
The title page layout. The title should be formatted as a heading level one. All text is centred
on export.
:guilabel:`Plain Page`
A plain page layout useful for instance for front matter pages. Heading levels are ignored for
@@ -184,7 +192,7 @@ Below is an overview of all available layout formats.
produce the same result as a collection of :guilabel:`Partition`, :guilabel:`Chapter` and
:guilabel:`Scene` layout documents. However, it does not provide the functionality of the
:guilabel:`Unnumbered` layout format by default, but this can still be achieved by prefixing the
chapter title with a ``*``.
chapter title with an asterisk (``*``). See :ref:`a_struct_heads_unnum` for more details.
:guilabel:`Partition`
A partition can be used to split the novel into parts. Partition titles are indicated with a
@@ -200,8 +208,8 @@ Below is an overview of all available layout formats.
text.
:guilabel:`Unnumbered`
Same as :guilabel:`Chapter`, but when exporting the documents and automatic chapter numbering is
enabled, documents with this layout will not increment the chapter number. It also has a
Same as :guilabel:`Chapter`, but when exporting the project, and automatic chapter numbering is
enabled, documents with this layout will not increment and apply a chapter number. It also has a
separate title formatting setting. This makes the layout suitable for Prologue and Epilogue type
chapters.
@@ -210,18 +218,33 @@ Below is an overview of all available layout formats.
headers of level four, but there are no layout specifically for sections.
:guilabel:`Note`
A generic document that is optionally ignored when the novel is exported. Use this layout for
descriptions of content in the supporting root folders. Notes can also be added to the
:guilabel:`Novel` root folder if you need to insert notes there. Note headers receive no special
formatting when building the project. They are always exported as-is.
A generic document that is optionally ignored when the novel project is exported. Use this
layout for descriptions of content in the supporting root folders. Notes can also be added to
the :guilabel:`Novel` root folder if you need to insert notes there. Note headers receive no
special formatting when building the project. They are always exported as-is.
.. note::
The layout granularity is entirely optional. In principle, you can write the entire novel in a
single document with layout :guilabel:`Book`. You can also have a single document per chapter if
that suits you better. The :guilabel:`Outline` will show your structure of chapters and scenes
regardless of how your documents are organised.
regardless of how your documents are organised. So will the novel tree.
.. tip::
You can always start writing with a coarse layout with one or a few documents, and then later
use the split tool to automatically split the documents into separate chapter and scene
documents.
documents. The split tool will try to select the correct layout for each of the new documents.
.. _a_struct_layout_auto:
Novel Layout Automation
-----------------------
When a document is saved from the document editor, novelWriter will check if the level of the first
header of the document matches the selected document layout. If the header level is inconsistent
with the layout, the layout will automatically be corrected if it can be unambiguously determined.
This means that for instance saving a document with header level three, when the layout is set to
:guilabel:`Chapter`, the layout will automatically be changed to :guilabel:`Scene`. If, however,
the layout was set to :guilabel:`Book`, no change will be made because the :guilabel:`Book` layout
is not associated with a specific header level.

View File

@@ -7,7 +7,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
keyboard shortcuts. See :ref:`a_ui_shortcuts_ins`.
keyboard shortcuts. See :ref:`a_kb_ins`.
This chapter provides some additional information on how novelWriter handles these symbols.
@@ -17,7 +17,7 @@ This chapter provides some additional information on how novelWriter handles the
Special Notes on Symbols
========================
Some additional notes on these symbols.
Some additional notes on the available symbols.
Dashes and Ellipsis
@@ -28,41 +28,58 @@ automatically to short and long dashes, and three dots to ellipsis. The last aut
always be reverted with the undo command :kbd:`Ctrl`:kbd:`Z`, reverting the text to what you typed
before the automatic replacement occurred.
In addition, "Figure Dash" is available. The Figure Dash is a dash that has the same width as the
numbers of the same font, for most fonts. It helps to align numbers align nicely in columns when
you need to use a dash in them.
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 the :guilabel:`Preferences`.
settings can be found in :guilabel:`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 the
for highlighting dialogue between characters. This feature can be disabled in
:guilabel:`Preferences` if this feature isn't wanted.
The editor distinguishes between text wrapped in straight quotes and with 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 can be used to
The editor distinguishes between text wrapped in regular straight quotes and with 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 can be used to
re-format a selected section of text with the correct quote symbols.
.. _Quotation Mark: https://en.wikipedia.org/wiki/Quotation_mark
Modifier Letter Apostrophes
---------------------------
Single and Double Prime
------------------------
Both single and double prime symbols are available in the :guilabel:`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 renderred similarly by the font, but they have different
codes. Using these correctly will also prevent the auto-replace and dialogue highlighting features
misunderstanding their meaning in the text.
.. _Prime: https://en.wikipedia.org/wiki/Prime_(symbol)
Modifier Letter Apostrophe
--------------------------
The auto-replace feature will consider any right-facing single straight quote as a quote symbol,
even if it's intended as an apostrophe. This also includes the syntax highlighter, which may assume
the first following apostrophe is the closing symbol of a single quoted region of text.
even if it is intended as an apostrophe. This also includes the syntax highlighter, which may
assume the first following apostrophe is the closing symbol of a single quoted region of text.
To get around this, an alternative apostrophe is available. It is a special Unicode character that
is not categorised as punctuation, but as a modifier. It is usually renderred the same way as right
single quotation marks, but not always, depending on the font. There is a Wikipedia article for the
is not categorised as punctuation, but as a modifier. It is usually renderred the same way as the
right single quotation marks, depending on the font. There is a Wikipedia article for the
`Modifier letter apostrophe`_ with more details.
.. note::
On export with the :guilabel:`Build Novel Project` tool, these apostrophes will be replaced
automatically with the corresponding right hand quote symbols as is generally recommended.
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 highlighting.
.. _Modifier letter apostrophe: https://en.wikipedia.org/wiki/Modifier_letter_apostrophe
@@ -82,6 +99,6 @@ All non-breaking spaces are highlighted with a differently coloured background t
spot them in the text. The colour will depend on the selected colour theme.
The thin and non-breaking spaces are converted to their corresponding HTML codes on export to HTML
format. For plain text, they are exported as regular spaces.
format.
.. _thin space: https://en.wikipedia.org/wiki/Thin_space

85
i18n/README.md Normal file
View File

@@ -0,0 +1,85 @@
# novelWriter Internationalisation
The `i18n` folder contains the translation files for the Qt5 GUI. There are two types of files
involved: the `nw_XX.ts` and the `nw_XX.qm` files. The `nw_XX.ts` files are located in the `i18n`
folder at the root of the repository, and the `nw_XX.qm` together with the `project_XX.json` files
are located in `nw/assets/i18n`. The latter are JSON translation maps for the novelWriter projects,
used by the Build Novel Project tool.
**Note**
When making a new translation, or updating an existing one, only commit the `nw_XX.ts` you have
made changes to. The `qtlupdate` command mentioned below will likely modify all `nw_XX.ts`
slightly, but please _don't_ commit those changes to the pull request.
## Qt GUI Localisation
The `.qm` files are the actual files used by the application to translate the GUI into another
language other than the default British English. The files are not generated by default. They can
be built with:
```bash
python3 setup.py qtlrelease
```
To add a new translation file, first add a new entry in the `novelWriter.pro` file under the
`TRANSLATIONS` variable. Please use the underscore syntax for file names as the importer expects
this format.
After adding the entry in the `.pro` file, run:
```bash
python3 setup.py qtlupdate
```
This will build a new `i18n/nw_XX.ts` file for the language you just added. The file can then be
edited with the Qt 5 Linguist application provided by Qt. This is by far easier than manually
editing the `.ts` file. Please select "English" and "United Kingdom" as the source langauge when
prompted by Qt 5 Linguist.
When you're done editing, you can build the `nw/assets/i18n/nw_XX.qm` file and test it in
novelWriter. The Preferences dialog should list the newly added language, and you can select it and
test it.
Please do not submit the `.qm` files to the repository. Only the `.ts` file you just added in the
`i18n` folder is needed.
**Note**
These commands require that you have the tools Qt 5 Linguist and the PyQt5 tool `pylupdate5`
installed on your system.
For Ubuntu/Debian, run:
```bash
sudo apt install qttools5-dev-tools pyqt5-dev-tools
```
### Missing QtBase Translations
The default Qt dialogs also have translations, for instance for standard buttons like "Yes", "No",
"Ok", "Cancel", etc. Generally, these translations files are installed with the Qt libraries on
your system, and novelWriter will collect those translations from there. However, these
translations are missing for many languages.
As a starting point, there is no need to translate any entries in the `.ts` files that are under
elements starting with the letter "Q", like "QPlatformTheme", "QWizard", etc. If these turn up in
English in novelWriter after activating a translation, it means they are probably missing in the Qt
library, and you may also need to translate these.
These additional translation entries are generated from a file named `i18n/qtbase.py`, which is not
a file that novelWriter uses. It is there only to generate these additional entries for the `.ts`
files.
## Project Localisation
Projects can have a different language setting than the GUI itself. The files with format
`project_XX.json` in `nw/assets/i18n` are simple translation maps for text that goes into the
exported documents generated by the Build Novel Project tool.
The files are loaded based on the language setting in the build tool. At the present time, no other
parts of the application use these files. Since these are used as replacement lookups, they are
maintained as plain JSON files. The main usage is to generate chapter headers as number words.
Adding new translations for these files is easy. Just copy the `project_en.json` file, rename it to
the appropriate language coded filename, and edit it. Please use the underscore as separator if a
language needs to be localised to a specific country under a language. The importer will for
instance look for `en_US` first, then use `en` if it is not found. If there are no matching files,
the project falls back to using English.

5023
i18n/nw_en_US.ts Normal file

File diff suppressed because it is too large Load Diff

5024
i18n/nw_fr.ts Normal file

File diff suppressed because it is too large Load Diff

5023
i18n/nw_nb_NO.ts Normal file

File diff suppressed because it is too large Load Diff

4943
i18n/nw_pt.ts Normal file

File diff suppressed because it is too large Load Diff

5025
i18n/nw_zh_CN.ts Normal file

File diff suppressed because it is too large Load Diff

73
i18n/qtbase.py Normal file
View File

@@ -0,0 +1,73 @@
"""
Qt Base Translation File
========================
This file causes Qt Linguist to generate translation entries for the Qt
elements that need translation in novelWriter for those languages who do
not yet have a qtbase_xx.qm file shipped with Qt.
If a qtbase_xx.qm file already exists, do not add a translation for the
entries generated from this file.
"""
from PyQt5.QtCore import QT_TRANSLATE_NOOP
# QDialogButtonBox
# ================
QT_TRANSLATE_NOOP("QDialogButtonBox", "OK")
# QGnomeTheme
# ===========
QT_TRANSLATE_NOOP("QGnomeTheme", "&OK")
QT_TRANSLATE_NOOP("QGnomeTheme", "&Save")
QT_TRANSLATE_NOOP("QGnomeTheme", "&Cancel")
QT_TRANSLATE_NOOP("QGnomeTheme", "&Close")
QT_TRANSLATE_NOOP("QGnomeTheme", "Close without Saving")
# QGuiApplication
# ===============
QT_TRANSLATE_NOOP("QGuiApplication", (
"Translate this string to the string 'LTR' in left-to-right languages or to "
"'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout."
))
# QPlatformTheme
# ==============
QT_TRANSLATE_NOOP("QPlatformTheme", "OK")
QT_TRANSLATE_NOOP("QPlatformTheme", "Save")
QT_TRANSLATE_NOOP("QPlatformTheme", "Save All")
QT_TRANSLATE_NOOP("QPlatformTheme", "Open")
QT_TRANSLATE_NOOP("QPlatformTheme", "&Yes")
QT_TRANSLATE_NOOP("QPlatformTheme", "Yes to &All")
QT_TRANSLATE_NOOP("QPlatformTheme", "&No")
QT_TRANSLATE_NOOP("QPlatformTheme", "N&o to All")
QT_TRANSLATE_NOOP("QPlatformTheme", "Abort")
QT_TRANSLATE_NOOP("QPlatformTheme", "Retry")
QT_TRANSLATE_NOOP("QPlatformTheme", "Ignore")
QT_TRANSLATE_NOOP("QPlatformTheme", "Close")
QT_TRANSLATE_NOOP("QPlatformTheme", "Cancel")
QT_TRANSLATE_NOOP("QPlatformTheme", "Discard")
QT_TRANSLATE_NOOP("QPlatformTheme", "Help")
QT_TRANSLATE_NOOP("QPlatformTheme", "Apply")
QT_TRANSLATE_NOOP("QPlatformTheme", "Reset")
QT_TRANSLATE_NOOP("QPlatformTheme", "Restore Defaults")
# QWizard
# =======
QT_TRANSLATE_NOOP("QWizard", "Go Back")
QT_TRANSLATE_NOOP("QWizard", "< &Back")
QT_TRANSLATE_NOOP("QWizard", "Continue")
QT_TRANSLATE_NOOP("QWizard", "&Next")
QT_TRANSLATE_NOOP("QWizard", "&Next >")
QT_TRANSLATE_NOOP("QWizard", "Commit")
QT_TRANSLATE_NOOP("QWizard", "Done")
QT_TRANSLATE_NOOP("QWizard", "&Finish")
QT_TRANSLATE_NOOP("QWizard", "Cancel")
QT_TRANSLATE_NOOP("QWizard", "Cancel")
QT_TRANSLATE_NOOP("QWizard", "Help")
QT_TRANSLATE_NOOP("QWizard", "&Help")

333
make.py
View File

@@ -1,333 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This make script is intended for building distributable packages of
novelWriter. These are either:
* A single file executable named dist/novelWriter(.exe). This is a
quite slow option, and the file is fairly big.
* A single directory named dist/novelWriter with a novelWriter(.exe),
and all dependecies included.
* The latter can be combined with a build stage of a setup.exe file if
on Windows. This requires Inno Setup to be installed and in path.
In addition, providing the pip otion will cause the script to try to
install all dependencies needed for runing the build, and for running
novelWriter itself.
"""
import os
import sys
import shutil
import subprocess
OS_NONE = 0
OS_LINUX = 1
OS_WIN = 2
OS_DARWIN = 3
# =============================================================================================== #
# Package Installer
# =============================================================================================== #
def installPackages(hostOS):
"""Install package dependencies both for this script and for running
novelWriter itself.
"""
print("")
print("Installing Dependencies")
print("#######################")
print("")
installQueue = ["pip", "pyinstaller", "-r requirements.txt"]
if hostOS == OS_DARWIN:
installQueue.append("pyobjc")
pyCmd = [sys.executable, "-m"]
pipCmd = ["pip", "install", "--user", "--upgrade"]
for stepCmd in installQueue:
pkgCmd = stepCmd.split(" ")
try:
subprocess.call(pyCmd + pipCmd + pkgCmd)
except Exception as e:
print("Failed with error:")
print(str(e))
sys.exit(1)
return
# =============================================================================================== #
# Run PyInstaller on Package
# =============================================================================================== #
def freezePackage(buildWindowed, oneFile, makeSetup, hostOS):
"""Run PyInstaller to freeze the packages. This assumes all
dependencies are already in place.
"""
import PyInstaller.__main__ # noqa: E402
print("")
print("Running PyInstaller")
print("###################")
print("")
if hostOS == OS_WIN:
dotDot = ";"
else:
dotDot = ":"
sys.modules["FixTk"] = None
instOpt = [
"--name=novelWriter",
"--clean",
"--add-data=%s%s%s" % (os.path.join("nw", "assets"), dotDot, "assets"),
"--icon=%s" % os.path.join("nw", "assets", "icons", "novelwriter.ico"),
"--exclude-module=PyQt5.QtQml",
"--exclude-module=PyQt5.QtBluetooth",
"--exclude-module=PyQt5.QtDBus",
"--exclude-module=PyQt5.QtMultimedia",
"--exclude-module=PyQt5.QtMultimediaWidgets",
"--exclude-module=PyQt5.QtNetwork",
"--exclude-module=PyQt5.QtNetworkAuth",
"--exclude-module=PyQt5.QtNfc",
"--exclude-module=PyQt5.QtQuick",
"--exclude-module=PyQt5.QtQuickWidgets",
"--exclude-module=PyQt5.QtRemoteObjects",
"--exclude-module=PyQt5.QtSensors",
"--exclude-module=PyQt5.QtSerialPort",
"--exclude-module=PyQt5.QtSql",
"--exclude-module=FixTk",
"--exclude-module=tcl",
"--exclude-module=tk",
"--exclude-module=_tkinter",
"--exclude-module=tkinter",
"--exclude-module=Tkinter",
]
if buildWindowed:
instOpt.append("--windowed")
if oneFile and not makeSetup:
instOpt.append("--onefile")
else:
instOpt.append("--onedir")
instOpt.append("novelWriter.py")
# Make sample.zip first
try:
subprocess.call([sys.executable, "setup.py", "sample"])
except Exception as e:
print("Failed with error:")
print(str(e))
sys.exit(1)
PyInstaller.__main__.run(instOpt)
if not oneFile:
# These files are not needed, and take up a fair bit of space.
delFiles = []
if hostOS == OS_WIN:
delFiles = [
"Qt5DBus.dll",
"Qt5Network.dll",
"Qt5Qml.dll",
"Qt5QmlModels.dll",
"Qt5Quick.dll",
"Qt5Quick3D.dll",
"Qt5Quick3DAssetImport.dll",
"Qt5Quick3DRender.dll",
"Qt5Quick3DRuntimeRender.dll",
"Qt5Quick3DUtils.dll",
"Qt5Sql.dll"
]
elif hostOS == OS_LINUX:
delFiles = [
"libQt5DBus.so.5",
"libQt5Network.so.5",
"libQt5Qml.so.5",
"libQt5QmlModels.so.5",
"libQt5Quick.so.5",
"libQt5Quick3D.so.5",
"libQt5Quick3DAssetImport.so.5",
"libQt5Quick3DRender.so.5",
"libQt5Quick3DRuntimeRender.so.5",
"libQt5Quick3DUtils.so.5",
"libQt5Sql.so.5"
]
distDir = os.path.join(os.getcwd(), "dist", "novelWriter")
for delFile in delFiles:
delPath = os.path.join(distDir, delFile)
if os.path.isfile(delPath):
print("Deleting file: %s" % delPath)
os.unlink(delPath)
print("")
print("Build Finished")
print("")
print("The novelWriter executable should be in the folder named 'dist'")
print("")
return
# =============================================================================================== #
# Inno Setup Builder
# =============================================================================================== #
def innoSetup():
"""Run the Inno Setup tool to build a setup.exe file for Windows.
"""
print("")
print("Running Inno Setup")
print("##################")
print("")
# Read the iss template
issData = ""
with open(os.path.join("setup", "win_setup.iss"), mode="r") as inFile:
issData = inFile.read()
import nw # noqa: E402
issData = issData.replace(r"%%version%%", nw.__version__)
issData = issData.replace(r"%%dir%%", os.getcwd())
with open("setup.iss", mode="w+") as outFile:
outFile.write(issData)
try:
subprocess.call(["iscc", "setup.iss"])
except Exception as e:
print("Inno Setup failed with error:")
print(str(e))
sys.exit(1)
return
# =============================================================================================== #
# Clean Build and Dist Folders
# =============================================================================================== #
def cleanInstall():
"""Recursively delete the 'build' and 'dist' folders.
"""
print("")
print("Cleaning up build environment ...")
buildDir = os.path.join(os.getcwd(), "build")
if os.path.isdir(buildDir):
try:
shutil.rmtree(buildDir)
print("Deleted folder 'build'")
except Exception as e:
print("Error: Cannot delete 'build' folder.")
print(str(e))
sys.exit(1)
else:
print("Folder 'build' not found")
distDir = os.path.join(os.getcwd(), "dist")
if os.path.isdir(distDir):
try:
shutil.rmtree(distDir)
print("Deleted folder 'dist'")
except Exception as e:
print("Error: Cannot delete 'dist' folder.")
print(str(e))
sys.exit(1)
else:
print("Folder 'dist' not found")
print("")
return
# =============================================================================================== #
# Process Build Steps
# =============================================================================================== #
if __name__ == "__main__":
"""Parse command line options and run the commands.
"""
# Detect OS
if sys.platform.startswith("linux"):
hostOS = OS_LINUX
elif sys.platform.startswith("darwin"):
hostOS = OS_DARWIN
elif sys.platform.startswith("win32"):
hostOS = OS_WIN
elif sys.platform.startswith("cygwin"):
hostOS = OS_WIN
else:
hostOS = OS_NONE
# Flags and Variables
buildWindowed = True
oneFile = False
makeSetup = False
doFreeze = False
helpMsg = (
"\n"
"novelWriter Make Tool\n"
"=====================\n"
"This tool provides build commands for distibuting novelWriter as a\n"
"package. The available options are as follows:\n"
"\n"
"help Print the help message.\n"
"freeze Freeze the package and produces a folder of all\n"
" dependencies using pyinstaller.\n"
"onefile Build a standalone executable with all dependencies\n"
" bundled. Implies 'freeze', cannot be used with 'setup'.\n"
"pip Run pip to install all package dependencies for\n"
" novelWriter and this build tool.\n"
"setup Build a setup.exe installer for Windows. This option\n"
" automaticall disables the 'onefile' option.\n"
"clean This will attempt to delete the 'build' and 'dist'\n"
" folders in the current folder.\n"
)
if "help" in sys.argv or len(sys.argv) <= 1:
print(helpMsg)
sys.exit(0)
if not os.path.isfile(os.path.join(os.getcwd(), "novelWriter.py")):
print("Error: This script must be run in the root folder of novelWriter.")
sys.exit(1)
if not os.path.isdir(os.path.join(os.getcwd(), "nw")):
print("Error: This script must be run in the root folder of novelWriter.")
sys.exit(1)
if "clean" in sys.argv:
sys.argv.remove("clean")
cleanInstall()
if "pip" in sys.argv:
sys.argv.remove("pip")
installPackages(hostOS)
if "freeze" in sys.argv:
sys.argv.remove("freeze")
doFreeze = True
if "onefile" in sys.argv:
sys.argv.remove("onefile")
doFreeze = True
oneFile = True
if "setup" in sys.argv:
sys.argv.remove("setup")
if hostOS == OS_WIN:
oneFile = False
makeSetup = True
else:
print("Error: Argument 'setup' for Inno Setup is Windows only.")
sys.exit(1)
if doFreeze:
freezePackage(buildWindowed, oneFile, makeSetup, hostOS)
if makeSetup:
innoSetup()
# END Main

39
novelWriter.pro Normal file
View File

@@ -0,0 +1,39 @@
SOURCES += \
i18n/qtbase.py \
nw/core/project.py \
nw/core/tokenizer.py \
nw/dialogs/about.py \
nw/dialogs/docmerge.py \
nw/dialogs/docsplit.py \
nw/dialogs/itemeditor.py \
nw/dialogs/preferences.py \
nw/dialogs/projload.py \
nw/dialogs/projsettings.py \
nw/dialogs/wordlist.py \
nw/gui/custom.py \
nw/gui/doceditor.py \
nw/gui/docviewer.py \
nw/gui/itemdetails.py \
nw/gui/mainmenu.py \
nw/gui/noveltree.py \
nw/gui/outline.py \
nw/gui/outlinedetails.py \
nw/gui/projdetails.py \
nw/gui/projtree.py \
nw/gui/statusbar.py \
nw/gui/theme.py \
nw/tools/build.py \
nw/tools/projwizard.py \
nw/tools/writingstats.py \
nw/common.py \
nw/constants.py \
nw/error.py \
nw/guimain.py
TRANSLATIONS += \
i18n/nw_en_US.ts \
i18n/nw_fr.ts \
i18n/nw_nb_NO.ts \
i18n/nw_pt.ts \
i18n/nw_zh_CN.ts

View File

@@ -1,16 +1,21 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
novelWriter – Start Script
==========================
"""
import os
import sys
try:
import PyQt5.QtWidgets # noqa: F401
import PyQt5.QtGui # noqa: F401
import PyQt5.QtCore # noqa: F401
import PyQt5.QtWidgets # noqa: F401
import PyQt5.QtGui # noqa: F401
import PyQt5.QtCore # noqa: F401
except Exception:
print("ERROR: Failed to load dependency python3-pyqt5")
print("ERROR: Failed to load dependency PyQt5")
sys.exit(1)
os.curdir = os.path.abspath(os.path.dirname(__file__))
if __name__ == "__main__":
import nw
nw.main(sys.argv[1:])

View File

@@ -1,28 +1,26 @@
# -*- coding: utf-8 -*-
"""novelWriter Init
"""
novelWriter – Init File
=======================
Application initialisation
novelWriter – Init File
=========================
Application initialisation
File History:
Created: 2018-09-22 [0.0.1]
File History:
Created: 2018-09-22 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import sys
@@ -32,19 +30,19 @@ import logging
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QErrorMessage
from nw.error import exceptionHandler
from nw.error import exceptionHandler, logException
from nw.config import Config
#
##
# Version Scheme
# ================
# Generally follows PEP 440
# Hex Version:
# - Digit 1,2 : Major Version (01, 02, 03)
# = Digit 3,4 : Minor Version (01, 09, 10, 99)
# - Digit 5,6 : Patch Version (01, 09, 10, 99)
# = Digit 7 : Release Type (a: aplha, b: beta, c: candidate, f: final)
# - Digit 8 : Release Number (0-9)
# - Digit 1,2 : Major Version (01-ff)
# - Digit 3,4 : Minor Version (01-ff)
# - Digit 5,6 : Patch Version (01-ff)
# - Digit 7 : Release Type (a: aplha, b: beta, c: candidate, f: final)
# - Digit 8 : Release Number (0-f)
#
# Example : Full Short Description
# -------------------------------------------------------------------------
@@ -55,7 +53,7 @@ from nw.config import Config
# 0x010200f0 : 1.2 1.2 Final release
# 0x010200f1 : 1.2-post1 1.2.post1 Post release, but not a code patch!
# 0x010201f0 : 1.2.1 1.2.1 Patch release
#
##
__package__ = "nw"
__copyright__ = "Copyright 2018–2021, Veronica Berglyd Olsen"
@@ -63,9 +61,9 @@ __license__ = "GPLv3"
__author__ = "Veronica Berglyd Olsen"
__maintainer__ = "Veronica Berglyd Olsen"
__email__ = "code@vkbo.net"
__version__ = "1.0"
__hexversion__ = "0x010000f0"
__date__ = "2021-01-03"
__version__ = "1.4"
__hexversion__ = "0x010400f0"
__date__ = "2021-07-27"
__status__ = "Stable"
__domain__ = "novelwriter.io"
__url__ = "https://novelwriter.io"
@@ -74,12 +72,8 @@ __issuesurl__ = "https://github.com/vkbo/novelWriter/issues"
__helpurl__ = "https://github.com/vkbo/novelWriter/discussions"
__releaseurl__ = "https://github.com/vkbo/novelWriter/releases/latest"
__docurl__ = "https://novelwriter.readthedocs.io"
__credits__ = [
"Veronica Berglyd Olsen (developer)",
"Marian Lückhof (contributor, tester)"
]
#
##
# Logging
# =========
# Standard used for logging levels in novelWriter:
@@ -90,30 +84,34 @@ __credits__ = [
# ----------- SPAM Threshold : Output above should be minimal -----------------
# DEBUG Use for descriptions of main program flow
# VERBOSE Use for outputting values and program flow details
#
##
# Add verbose logging level
VERBOSE = 5
logging.addLevelName(VERBOSE, "VERBOSE")
def logVerbose(self, message, *args, **kws):
if self.isEnabledFor(VERBOSE):
self._log(VERBOSE, message, args, **kws)
logging.Logger.verbose = logVerbose
# Initiating logging
logger = logging.getLogger(__name__)
#
##
# Main Program
# ==============
#
##
# Load the main config as a global object
CONFIG = Config()
def main(sysArgs=None):
"""Parses command line, sets up logging, and launches main GUI.
"""Parse command line, set up logging, and launches main GUI.
"""
if sysArgs is None:
sysArgs = sys.argv[1:]
@@ -133,39 +131,37 @@ def main(sysArgs=None):
]
helpMsg = (
"novelWriter {version} ({status} {date})\n"
"novelWriter {version} ({date})\n"
"{copyright}\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"GNU General Public Licence for more details.\n"
"\n"
"Usage:\n"
" -h, --help Print this message.\n"
" -v, --version Print program version and exit.\n"
" --info Print additional runtime information.\n"
" --debug Print debug output. Includes --info.\n"
" --verbose Increase verbosity of debug output. Includes --debug.\n"
" --style= Sets Qt5 style flag. Defaults to 'Fusion'.\n"
" --config= Alternative config file.\n"
" --data= Alternative user data path.\n"
" --testmode Do not display GUI. Used by the test suite.\n"
" -h, --help Print this message.\n"
" -v, --version Print program version and exit.\n"
" --info Print additional runtime information.\n"
" --debug Print debug output. Includes --info.\n"
" --verbose Increase verbosity of debug output. Includes --debug.\n"
" --style= Sets Qt5 style flag. Defaults to 'Fusion'.\n"
" --config= Alternative config file.\n"
" --data= Alternative user data path.\n"
).format(
version = __version__,
status = __status__,
copyright = __copyright__,
date = __date__,
version=__version__,
copyright=__copyright__,
date=__date__,
)
# Defaults
debugLevel = logging.WARN
logFormat = "{levelname:8} {message:}"
confPath = None
dataPath = None
testMode = False
qtStyle = "Fusion"
cmdOpen = None
logLevel = logging.WARN
logFormat = "{levelname:8} {message:}"
confPath = None
dataPath = None
testMode = False
qtStyle = "Fusion"
cmdOpen = None
# Parse Options
try:
@@ -183,17 +179,15 @@ def main(sysArgs=None):
print(helpMsg)
sys.exit(0)
elif inOpt in ("-v", "--version"):
print("novelWriter %s Version %s [%s]" % (
__status__, __version__, __date__)
)
print("novelWriter Version %s [%s]" % (__version__, __date__))
sys.exit(0)
elif inOpt == "--info":
debugLevel = logging.INFO
logLevel = logging.INFO
elif inOpt == "--debug":
debugLevel = logging.DEBUG
logLevel = logging.DEBUG
logFormat = "[{asctime:}] {name:>22}:{lineno:<4d} {levelname:8} {message:}"
elif inOpt == "--verbose":
debugLevel = VERBOSE
logLevel = VERBOSE
logFormat = "[{asctime:}] {name:>22}:{lineno:<4d} {levelname:8} {message:}"
elif inOpt == "--style":
qtStyle = inArg
@@ -205,21 +199,17 @@ def main(sysArgs=None):
testMode = True
# Set Config Options
CONFIG.showGUI = not testMode
CONFIG.debugInfo = debugLevel < logging.INFO
CONFIG.cmdOpen = cmdOpen
CONFIG.cmdOpen = cmdOpen
# Set Logging
logFmt = logging.Formatter(fmt=logFormat, style="{")
cHandle = logging.StreamHandler()
cHandle.setLevel(debugLevel)
cHandle.setFormatter(logFmt)
logger.addHandler(cHandle)
cHandle.setFormatter(logging.Formatter(fmt=logFormat, style="{"))
logger.setLevel(debugLevel)
logger.info("Starting novelWriter %s (%s) %s" % (
__version__, __hexversion__, __date__
))
pkgLogger = logging.getLogger(__package__)
pkgLogger.addHandler(cHandle)
pkgLogger.setLevel(logLevel)
logger.info("Starting novelWriter %s (%s) %s", __version__, __hexversion__, __date__)
# Check Packages and Versions
errorData = []
@@ -229,19 +219,19 @@ def main(sysArgs=None):
"At least Python 3.6.0 is required, found %s." % CONFIG.verPyString
)
errorCode |= 4
if CONFIG.verQtValue < 50200:
if CONFIG.verQtValue < 50300:
errorData.append(
"At least Qt5 version 5.2 is required, found %s." % CONFIG.verQtString
"At least Qt5 version 5.3 is required, found %s." % CONFIG.verQtString
)
errorCode |= 8
if CONFIG.verPyQtValue < 50200:
if CONFIG.verPyQtValue < 50300:
errorData.append(
"At least PyQt5 version 5.2 is required, found %s." % CONFIG.verPyQtString
"At least PyQt5 version 5.3 is required, found %s." % CONFIG.verPyQtString
)
errorCode |= 16
try:
import lxml # noqa: F401
import lxml # noqa: F401
except ImportError:
errorData.append("Python module 'lxml' is missing.")
errorCode |= 32
@@ -272,9 +262,9 @@ def main(sysArgs=None):
bundle = NSBundle.mainBundle()
info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
info["CFBundleName"] = "novelWriter"
except ImportError as e:
except ImportError:
logger.error("Failed to set application name")
logger.error(str(e))
logException()
# Import GUI (after dependency checks), and launch
from nw.guimain import GuiMain
@@ -292,7 +282,13 @@ def main(sysArgs=None):
# Connect the exception handler before making the main GUI
sys.excepthook = exceptionHandler
# Launch main GUI
CONFIG.initLocalisation(nwApp)
nwGUI = GuiMain()
if not nwGUI.hasProject:
nwGUI.showProjectLoadDialog()
nwGUI.releaseNotes()
sys.exit(nwApp.exec_())
# END Function main

View File

@@ -0,0 +1,105 @@
{
"Synopsis": "Synopsis",
"Comment": "Kommentar",
"Notes": "Notizen",
"0": "Null",
"1": "Eins",
"2": "Zwei",
"3": "Drei",
"4": "Vier",
"5": "Fünf",
"6": "Sechs",
"7": "Sieben",
"8": "Acht",
"9": "Neun",
"10": "Zehn",
"11": "Elf",
"12": "Zwölf",
"13": "Dreizehen",
"14": "Vierzehn",
"15": "Fünfzehn",
"16": "Sechzehn",
"17": "Siebzehn",
"18": "Achtzehn",
"19": "Neunzehn",
"20": "Zwanzig",
"21": "Einundzwanzig",
"22": "Zweiundzwanzig",
"23": "Dreiundzwanzig",
"24": "Vierundzwanzig",
"25": "Fünfundzwanzig",
"26": "Sechsundzwanzig",
"27": "Siebenundzwanzig",
"28": "Achtundzwanzig",
"29": "Neunundzwanzig",
"30": "Dreißig",
"31": "Einunddreißig",
"32": "Zweiunddreißig",
"33": "Dreiunddreißig",
"34": "Vierunddreißig",
"35": "Fünfunddreißig",
"36": "Sechsunddreißig",
"37": "Siebenunddreißig",
"38": "Achtunddreißig",
"39": "Neununddreißig",
"40": "Vierzig",
"41": "Einundvierzig",
"42": "Zweiundvierzig",
"43": "Dreiundvierzig",
"44": "Vierundvierzig",
"45": "Fünfundvierzig",
"46": "Sechsundvierzig",
"47": "Siebenundvierzig",
"48": "Achtundvierzig",
"49": "Neunundvierzig",
"50": "Fünfzig",
"51": "Einundfünfzig",
"52": "Zweiundfünfzig",
"53": "Dreiundfünfzig",
"54": "Vierundfünfzig",
"55": "Fünfundfünfzig",
"56": "Sechsundfünfzig",
"57": "Siebenundfünfzig",
"58": "Achtundfünfzig",
"59": "Neunundfünfzig",
"60": "Sechzig",
"61": "Einundsechzig",
"62": "Zweiundsechzig",
"63": "Dreiundsechzig",
"64": "Vierundsechzig",
"65": "Fünfundsechzig",
"66": "Sechsundsechzig",
"67": "Siebenundsechzig",
"68": "Achtundsechzig",
"69": "Neunundsechzig",
"70": "Siebzig",
"71": "Einundsiebzig",
"72": "Zweiundsiebzig",
"73": "Dreiundsiebzig",
"74": "Vierundsiebzig",
"75": "Fünfundsiebzig",
"76": "Sechsundsiebzig",
"77": "Siebenundsiebzig",
"78": "Achtundsiebzig",
"79": "Neunundsiebzig",
"80": "Achtzig",
"81": "Einundachtzig",
"82": "Zweiundachtzig",
"83": "Dreiundachtzig",
"84": "Vierundachtzig",
"85": "Fünfundachtzig",
"86": "Sechsundachtzig",
"87": "Siebenundachtzig",
"88": "Achtundachtzig",
"89": "Neunundachtzig",
"90": "Neunzig",
"91": "Einundneunzig",
"92": "Zweiundneunzig",
"93": "Dreiundneunzig",
"94": "Vierundneunzig",
"95": "Fünfundneunzig",
"96": "Sechsundneunzig",
"97": "Siebenundneunzig",
"98": "Achtundneunzig",
"99": "Neunundneunzig"
}

View File

@@ -0,0 +1,105 @@
{
"Synopsis": "Synopsis",
"Comment": "Comment",
"Notes": "Notes",
"0": "Zero",
"1": "One",
"2": "Two",
"3": "Three",
"4": "Four",
"5": "Five",
"6": "Six",
"7": "Seven",
"8": "Eight",
"9": "Nine",
"10": "Ten",
"11": "Eleven",
"12": "Twelve",
"13": "Thirteen",
"14": "Fourteen",
"15": "Fifteen",
"16": "Sixteen",
"17": "Seventeen",
"18": "Eighteen",
"19": "Nineteen",
"20": "Twenty",
"21": "Twenty-One",
"22": "Twenty-Two",
"23": "Twenty-Three",
"24": "Twenty-Four",
"25": "Twenty-Five",
"26": "Twenty-Six",
"27": "Twenty-Seven",
"28": "Twenty-Eight",
"29": "Twenty-Nine",
"30": "Thirty",
"31": "Thirty-One",
"32": "Thirty-Two",
"33": "Thirty-Three",
"34": "Thirty-Four",
"35": "Thirty-Five",
"36": "Thirty-Six",
"37": "Thirty-Seven",
"38": "Thirty-Eight",
"39": "Thirty-Nine",
"40": "Forty",
"41": "Forty-One",
"42": "Forty-Two",
"43": "Forty-Three",
"44": "Forty-Four",
"45": "Forty-Five",
"46": "Forty-Six",
"47": "Forty-Seven",
"48": "Forty-Eight",
"49": "Forty-Nine",
"50": "Fifty",
"51": "Fifty-One",
"52": "Fifty-Two",
"53": "Fifty-Three",
"54": "Fifty-Four",
"55": "Fifty-Five",
"56": "Fifty-Six",
"57": "Fifty-Seven",
"58": "Fifty-Eight",
"59": "Fifty-Nine",
"60": "Sixty",
"61": "Sixty-One",
"62": "Sixty-Two",
"63": "Sixty-Three",
"64": "Sixty-Four",
"65": "Sixty-Five",
"66": "Sixty-Six",
"67": "Sixty-Seven",
"68": "Sixty-Eight",
"69": "Sixty-Nine",
"70": "Seventy",
"71": "Seventy-One",
"72": "Seventy-Two",
"73": "Seventy-Three",
"74": "Seventy-Four",
"75": "Seventy-Five",
"76": "Seventy-Six",
"77": "Seventy-Seven",
"78": "Seventy-Eight",
"79": "Seventy-Nine",
"80": "Eighty",
"81": "Eighty-One",
"82": "Eighty-Two",
"83": "Eighty-Three",
"84": "Eighty-Four",
"85": "Eighty-Five",
"86": "Eighty-Six",
"87": "Eighty-Seven",
"88": "Eighty-Eight",
"89": "Eighty-Nine",
"90": "Ninety",
"91": "Ninety-One",
"92": "Ninety-Two",
"93": "Ninety-Three",
"94": "Ninety-Four",
"95": "Ninety-Five",
"96": "Ninety-Six",
"97": "Ninety-Seven",
"98": "Ninety-Eight",
"99": "Ninety-Nine"
}

View File

@@ -0,0 +1,105 @@
{
"Synopsis": "Synopsis",
"Comment": "Commentaire",
"Notes": "Notes",
"0": "Zero",
"1": "Un",
"2": "Deux",
"3": "Trois",
"4": "Quatre",
"5": "Cinq",
"6": "Six",
"7": "Sept",
"8": "Huit",
"9": "Neuf",
"10": "Dix",
"11": "Onze",
"12": "Douze",
"13": "Treize",
"14": "Quatorze",
"15": "Quinze",
"16": "Seize",
"17": "Dix-sept",
"18": "Dix-huit",
"19": "Dix-neuf",
"20": "Vingt",
"21": "Vingt et un",
"22": "Vingt-deux",
"23": "Vingt-trois",
"24": "Vingt-quatre",
"25": "Vingt-cinq",
"26": "Vingt-six",
"27": "Vingt-sept",
"28": "Vingt-huit",
"29": "Vingt-neuf",
"30": "Trente",
"31": "Trente et un",
"32": "Trente-deux",
"33": "Trente-trois",
"34": "Trente-quatre",
"35": "Trente-cinq",
"36": "Trente-six",
"37": "Trente-sept",
"38": "Trente-huit",
"39": "Trente-neuf",
"40": "Quarante",
"41": "Quarante et un",
"42": "Quarante-deux",
"43": "Quarante-trois",
"44": "Quarante-quatre",
"45": "Quarante-cinq",
"46": "Quarante-six",
"47": "Quarante-sept",
"48": "Quarante-huit",
"49": "Quarante-neuf",
"50": "Cinquante",
"51": "Cinquante et un",
"52": "Cinquante-deux",
"53": "Cinquante-trois",
"54": "Cinquante-quatre",
"55": "Cinquante-cinq",
"56": "Cinquante-six",
"57": "Cinquante-sept",
"58": "Cinquante-huit",
"59": "Cinquante-neuf",
"60": "Soixante",
"61": "Soixante et un",
"62": "Soixante-deux",
"63": "Soixante-trois",
"64": "Soixante-quatre",
"65": "Soixante-cinq",
"66": "Soixante-six",
"67": "Soixante-sept",
"68": "Soixante-huit",
"69": "Soixante-neuf",
"70": "Soixante-dix",
"71": "Soixante et onze",
"72": "Soixante-douze",
"73": "Soixante-treize",
"74": "Soixante-quatorze",
"75": "Soixante-quinze",
"76": "Soixante-seize",
"77": "Soixante-dix-sept",
"78": "Soixante-dix-huit",
"79": "Soixante-dix-neuf",
"80": "Quatre-vingts",
"81": "Quatre-vingt-un",
"82": "Quatre-vingt-deux",
"83": "Quatre-vingt-trois",
"84": "Quatre-vingt-quatre",
"85": "Quatre-vingt-cinq",
"86": "Quatre-vingt-six",
"87": "Quatre-vingt-sept",
"88": "Quatre-vingt-huit",
"89": "Quatre-vingt-neuf",
"90": "Quatre-vingt-dix",
"91": "Quatre-vingt-onze",
"92": "Quatre-vingt-douze",
"93": "Quatre-vingt-treize",
"94": "Quatre-vingt-quatorze",
"95": "Quatre-vingt-quinze",
"96": "Quatre-vingt-seize",
"97": "Quatre-vingt-dix-sept",
"98": "Quatre-vingt-dix-huit",
"99": "Quatre-vingt-dix-neuf"
}

View File

@@ -0,0 +1,105 @@
{
"Synopsis": "Sammendrag",
"Comment": "Kommentar",
"Notes": "Notat",
"0": "null",
"1": "én",
"2": "to",
"3": "tre",
"4": "fire",
"5": "fem",
"6": "seks",
"7": "sju",
"8": "åtte",
"9": "ni",
"10": "ti",
"11": "elleve",
"12": "tolv",
"13": "tretten",
"14": "fjorten",
"15": "femten",
"16": "seksten",
"17": "sytten",
"18": "atten",
"19": "nitten",
"20": "tjue",
"21": "tjueén",
"22": "tjueto",
"23": "tjuetre",
"24": "tjuefire",
"25": "tjuefem",
"26": "tjueseks",
"27": "tjuesju",
"28": "tjueåtte",
"29": "tjueni",
"30": "tretti",
"31": "trettién",
"32": "trettito",
"33": "trettitre",
"34": "trettifire",
"35": "trettifem",
"36": "trettiseks",
"37": "trettisju",
"38": "trettiåtte",
"39": "trettini",
"40": "førti",
"41": "førtién",
"42": "førtito",
"43": "førtitre",
"44": "førtifire",
"45": "førtifem",
"46": "førtiseks",
"47": "førtisju",
"48": "førtiåtte",
"49": "førtini",
"50": "femti",
"51": "femtién",
"52": "femtito",
"53": "femtitre",
"54": "femtifire",
"55": "femtifem",
"56": "femtiseks",
"57": "femtisju",
"58": "femtiåtte",
"59": "femtini",
"60": "seksti",
"61": "sekstién",
"62": "sekstito",
"63": "sekstitre",
"64": "sekstifire",
"65": "sekstifem",
"66": "sekstiseks",
"67": "sekstisju",
"68": "sekstiåtte",
"69": "sekstini",
"70": "sytti",
"71": "syttién",
"72": "syttito",
"73": "syttitre",
"74": "syttifire",
"75": "syttifem",
"76": "syttiseks",
"77": "syttisju",
"78": "syttiåtte",
"79": "syttini",
"80": "åtti",
"81": "åttién",
"82": "åttito",
"83": "åttitre",
"84": "åttifire",
"85": "åttifem",
"86": "åttiseks",
"87": "åttisju",
"88": "åttiåtte",
"89": "åttini",
"90": "nitti",
"91": "nittién",
"92": "nittito",
"93": "nittitre",
"94": "nittifire",
"95": "nittifem",
"96": "nittiseks",
"97": "nittisju",
"98": "nittiåtte",
"99": "nittini"
}

View File

@@ -0,0 +1,105 @@
{
"Synopsis": "Samandrag",
"Comment": "Kommentar",
"Notes": "Notat",
"0": "null",
"1": "ein",
"2": "to",
"3": "tre",
"4": "fire",
"5": "fem",
"6": "seks",
"7": "sju",
"8": "åtte",
"9": "ni",
"10": "ti",
"11": "elleve",
"12": "tolv",
"13": "tretten",
"14": "fjorten",
"15": "femten",
"16": "seksten",
"17": "sytten",
"18": "atten",
"19": "nitten",
"20": "tjue",
"21": "tjueein",
"22": "tjueto",
"23": "tjuetre",
"24": "tjuefire",
"25": "tjuefem",
"26": "tjueseks",
"27": "tjuesju",
"28": "tjueåtte",
"29": "tjueni",
"30": "tretti",
"31": "trettiein",
"32": "trettito",
"33": "trettitre",
"34": "trettifire",
"35": "trettifem",
"36": "trettiseks",
"37": "trettisju",
"38": "trettiåtte",
"39": "trettini",
"40": "førti",
"41": "førtiein",
"42": "førtito",
"43": "førtitre",
"44": "førtifire",
"45": "førtifem",
"46": "førtiseks",
"47": "førtisju",
"48": "førtiåtte",
"49": "førtini",
"50": "femti",
"51": "femtiein",
"52": "femtito",
"53": "femtitre",
"54": "femtifire",
"55": "femtifem",
"56": "femtiseks",
"57": "femtisju",
"58": "femtiåtte",
"59": "femtini",
"60": "seksti",
"61": "sekstiein",
"62": "sekstito",
"63": "sekstitre",
"64": "sekstifire",
"65": "sekstifem",
"66": "sekstiseks",
"67": "sekstisju",
"68": "sekstiåtte",
"69": "sekstini",
"70": "sytti",
"71": "syttiein",
"72": "syttito",
"73": "syttitre",
"74": "syttifire",
"75": "syttifem",
"76": "syttiseks",
"77": "syttisju",
"78": "syttiåtte",
"79": "syttini",
"80": "åtti",
"81": "åttiein",
"82": "åttito",
"83": "åttitre",
"84": "åttifire",
"85": "åttifem",
"86": "åttiseks",
"87": "åttisju",
"88": "åttiåtte",
"89": "åttini",
"90": "nitti",
"91": "nittiein",
"92": "nittito",
"93": "nittitre",
"94": "nittifire",
"95": "nittifem",
"96": "nittiseks",
"97": "nittisju",
"98": "nittiåtte",
"99": "nittini"
}

View File

@@ -0,0 +1,105 @@
{
"Synopsis": "Sinopse",
"Comment": "Comentários",
"Notes": "Notas",
"0": "Zero",
"1": "Um",
"2": "Dois",
"3": "Três",
"4": "Quatro",
"5": "Cinco",
"6": "Seis",
"7": "Sete",
"8": "Oito",
"9": "Nove",
"10": "Dez",
"11": "Onze",
"12": "Doze",
"13": "Treze",
"14": "Quatorze",
"15": "Quinze",
"16": "Dezesseis",
"17": "Dezesete",
"18": "Dezoito",
"19": "Dezenove",
"20": "Vinte",
"21": "Vinte e Um",
"22": "Vinte e Dois",
"23": "Vinte e Três",
"24": "Vinte e Quatro",
"25": "Vinte e Cinco",
"26": "Vinte e Seis",
"27": "Vinte e Sete",
"28": "Vinte e Oito",
"29": "Vinte e Nove",
"30": "Trinta",
"31": "Trinta e Um",
"32": "Trinta e Dois",
"33": "Trinta e Três",
"34": "Trinta e Quatro",
"35": "Trinta e Cinco",
"36": "Trinta e Seis",
"37": "Trinta e Sete",
"38": "Trinta e Oito",
"39": "Trinta e Nove",
"40": "Quarenta",
"41": "Quarenta e Um",
"42": "Quarenta e Dois",
"43": "Quarenta e Três",
"44": "Quarenta e Quatro",
"45": "Quarenta e Cinco",
"46": "Quarenta e Seis",
"47": "Quarenta e Sete",
"48": "Quarenta e Oito",
"49": "Quarenta e Nove",
"50": "Cinquenta",
"51": "Cinquenta e Um",
"52": "Cinquenta e Dois",
"53": "Cinquenta e Três",
"54": "Cinquenta e Quatro",
"55": "Cinquenta e Cinco",
"56": "Cinquenta e Seis",
"57": "Cinquenta e Sete",
"58": "Cinquenta e Oito",
"59": "Cinquenta e Nove",
"60": "Sessenta",
"61": "Sessenta e Um",
"62": "Sessenta e Dois",
"63": "Sessenta e Três",
"64": "Sessenta e Quatro",
"65": "Sessenta e Cinco",
"66": "Sessenta e Seis",
"67": "Sessenta e Sete",
"68": "Sessenta e Oito",
"69": "Sessenta e Nove",
"70": "Setenta",
"71": "Setenta e Um",
"72": "Setenta e Dois",
"73": "Setenta e Três",
"74": "Setenta e Quatro",
"75": "Setenta e Cinco",
"76": "Setenta e Seis",
"77": "Setenta e Sete",
"78": "Setenta e Oito",
"79": "Setenta e Nove",
"80": "Oitenta",
"81": "Oitenta e Um",
"82": "Oitenta e Dois",
"83": "Oitenta e Três",
"84": "Oitenta e Quatro",
"85": "Oitenta e Cinco",
"86": "Oitenta e Seis",
"87": "Oitenta e Sete",
"88": "Oitenta e Oito",
"89": "Oitenta e Nove",
"90": "Noventa",
"91": "Noventa e Um",
"92": "Noventa e Dois",
"93": "Noventa e Três",
"94": "Noventa e Quatro",
"95": "Noventa e Cinco",
"96": "Noventa e Seis",
"97": "Noventa e Sete",
"98": "Noventa e Oito",
"99": "Noventa e Nove"
}

View File

@@ -0,0 +1,105 @@
{
"Synopsis": "概要",
"Comment": "注释",
"Notes": "笔记",
"0": "零",
"1": "一",
"2": "二",
"3": "三",
"4": "四",
"5": "五",
"6": "六",
"7": "七",
"8": "八",
"9": "九",
"10": "十",
"11": "十一",
"12": "十二",
"13": "十三",
"14": "十四",
"15": "十五",
"16": "十六",
"17": "十七",
"18": "十八",
"19": "十九",
"20": "二十",
"21": "二十一",
"22": "二十二",
"23": "二十三",
"24": "二十四",
"25": "二十五",
"26": "二十六",
"27": "二十七",
"28": "二十八",
"29": "二十九",
"30": "三十",
"31": "三十一",
"32": "三十二",
"33": "三十三",
"34": "三十四",
"35": "三十五",
"36": "三十六",
"37": "三十七",
"38": "三十八",
"39": "三十九",
"40": "四十",
"41": "四十一",
"42": "四十二",
"43": "四十三",
"44": "四十四",
"45": "四十五",
"46": "四十六",
"47": "四十七",
"48": "四十八",
"49": "四十九",
"50": "五十",
"51": "五十一",
"52": "五十二",
"53": "五十三",
"54": "五十四",
"55": "五十五",
"56": "五十六",
"57": "五十七",
"58": "五十八",
"59": "五十九",
"60": "六十",
"61": "六十一",
"62": "六十二",
"63": "六十三",
"64": "六十四",
"65": "六十五",
"66": "六十六",
"67": "六十七",
"68": "六十八",
"69": "六十九",
"70": "七十",
"71": "七十一",
"72": "七十二",
"73": "七十三",
"74": "七十四",
"75": "七十五",
"76": "七十六",
"77": "七十七",
"78": "七十八",
"79": "七十九",
"80": "八十",
"81": "八十一",
"82": "八十二",
"83": "八十三",
"84": "八十四",
"85": "八十五",
"86": "八十六",
"87": "八十七",
"88": "八十八",
"89": "八十九",
"90": "九十",
"91": "九十一",
"92": "九十二",
"93": "九十三",
"94": "九十四",
"95": "九十五",
"96": "九十六",
"97": "九十七",
"98": "九十八",
"99": "九十九",
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg1989">
<metadata
id="metadata1995">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1993" />
<path
d="M 8.3268645,20.0768 8.9719703,22.448 C 9.2032354,23.3008 10.175241,24 11.131598,24 h 1.738831 c 0.956356,0 1.928363,-0.6992 2.159627,-1.552 l 0.645108,-2.3712 c 0.231264,-0.8528 1.173709,-1.3536 2.091812,-1.1104 l 2.550866,0.672 c 0.91984,0.2416 2.06573,-0.1824 2.542169,-0.9456 l 0.869415,-1.3872 c 0.476441,-0.7632 0.307773,-1.8864 -0.380803,-2.4992 l -1.909236,-1.6976 c -0.688578,-0.6128 -0.688578,-1.6128 0.0017,-2.224 L 23.346891,9.1872 C 24.035507,8.5759996 24.205912,7.4527996 23.729472,6.6895996 L 22.858272,5.3024 C 22.380094,4.5392 21.235943,4.1152 20.317842,4.3568 l -2.550866,0.672 C 16.847134,5.2704 15.906428,4.7712 15.673424,3.9184 L 15.030056,1.5504 C 14.798792,0.69919996 13.826785,0 12.870429,0 H 11.131598 C 10.175241,0 9.2032354,0.69919996 8.9719703,1.552 L 8.3286034,3.92 C 8.0955994,4.7728 7.1548921,5.2736 6.2350507,5.032 L 3.684186,4.36 C 2.7643447,4.1168 1.6184552,4.5424 1.1420155,5.304 L 0.27260019,6.6912 c -0.47643954,0.7632 -0.307773,1.8864 0.38254277,2.4991996 L 2.5609015,10.8848 c 0.6868381,0.6128 0.6868381,1.6128 0,2.2256 L 0.65166536,14.808 c -0.68683817,0.6128 -0.85898242,1.736 -0.38080407,2.4992 l 0.87115421,1.3872 c 0.4764397,0.7632 1.6223292,1.1872 2.5421705,0.9456 l 2.5508647,-0.672 c 0.9181025,-0.2448 1.8605487,0.256 2.0918138,1.1088 z M 12.001014,8.8000004 c 1.919668,0 3.477662,1.4319996 3.477662,3.1999996 0,1.7664 -1.557994,3.2 -3.477662,3.2 -1.91967,0 -3.4776615,-1.4336 -3.4776615,-3.2 0,-1.768 1.5579915,-3.1999996 3.4776615,-3.1999996 z"
id="path1987"
style="fill:#aeaeae;fill-opacity:1;stroke-width:1.66797" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg1989">
<metadata
id="metadata1995">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1993" />
<path
d="M 8.3268645,20.0768 8.9719703,22.448 C 9.2032354,23.3008 10.175241,24 11.131598,24 h 1.738831 c 0.956356,0 1.928363,-0.6992 2.159627,-1.552 l 0.645108,-2.3712 c 0.231264,-0.8528 1.173709,-1.3536 2.091812,-1.1104 l 2.550866,0.672 c 0.91984,0.2416 2.06573,-0.1824 2.542169,-0.9456 l 0.869415,-1.3872 c 0.476441,-0.7632 0.307773,-1.8864 -0.380803,-2.4992 l -1.909236,-1.6976 c -0.688578,-0.6128 -0.688578,-1.6128 0.0017,-2.224 L 23.346891,9.1872 C 24.035507,8.5759996 24.205912,7.4527996 23.729472,6.6895996 L 22.858272,5.3024 C 22.380094,4.5392 21.235943,4.1152 20.317842,4.3568 l -2.550866,0.672 C 16.847134,5.2704 15.906428,4.7712 15.673424,3.9184 L 15.030056,1.5504 C 14.798792,0.69919996 13.826785,0 12.870429,0 H 11.131598 C 10.175241,0 9.2032354,0.69919996 8.9719703,1.552 L 8.3286034,3.92 C 8.0955994,4.7728 7.1548921,5.2736 6.2350507,5.032 L 3.684186,4.36 C 2.7643447,4.1168 1.6184552,4.5424 1.1420155,5.304 L 0.27260019,6.6912 c -0.47643954,0.7632 -0.307773,1.8864 0.38254277,2.4991996 L 2.5609015,10.8848 c 0.6868381,0.6128 0.6868381,1.6128 0,2.2256 L 0.65166536,14.808 c -0.68683817,0.6128 -0.85898242,1.736 -0.38080407,2.4992 l 0.87115421,1.3872 c 0.4764397,0.7632 1.6223292,1.1872 2.5421705,0.9456 l 2.5508647,-0.672 c 0.9181025,-0.2448 1.8605487,0.256 2.0918138,1.1088 z M 12.001014,8.8000004 c 1.919668,0 3.477662,1.4319996 3.477662,3.1999996 0,1.7664 -1.557994,3.2 -3.477662,3.2 -1.91967,0 -3.4776615,-1.4336 -3.4776615,-3.2 0,-1.768 1.5579915,-3.1999996 3.4776615,-3.1999996 z"
id="path1987"
style="fill:#000000;fill-opacity:0.721569;stroke-width:1.66797" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg5582">
<metadata
id="metadata5588">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs5586" />
<path
d="m 6.7499997,3 c -1.656,0 -3,1.3440001 -3,3.0000001 V 17.999999 c 0,1.656 1.344,3.000001 3,3.000001 1.6560002,0 2.9999998,-1.344001 2.9999998,-3.000001 V 6.0000001 C 9.7499995,4.3440001 8.4059999,3 6.7499997,3 Z M 17.249999,3 c -1.656,0 -3.000001,1.3440001 -3.000001,3.0000001 V 17.999999 c 0,1.656 1.344001,3.000001 3.000001,3.000001 1.656,0 3.000001,-1.344001 3.000001,-3.000001 V 6.0000001 C 20.25,4.3440001 18.905999,3 17.249999,3 Z"
id="path5580"
style="fill:#aeaeae;fill-opacity:1;stroke-width:1.49999" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg5582">
<metadata
id="metadata5588">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs5586" />
<path
d="m 6.7499997,3 c -1.656,0 -3,1.3440001 -3,3.0000001 V 17.999999 c 0,1.656 1.344,3.000001 3,3.000001 1.6560002,0 2.9999998,-1.344001 2.9999998,-3.000001 V 6.0000001 C 9.7499995,4.3440001 8.4059999,3 6.7499997,3 Z M 17.249999,3 c -1.656,0 -3.000001,1.3440001 -3.000001,3.0000001 V 17.999999 c 0,1.656 1.344001,3.000001 3.000001,3.000001 1.656,0 3.000001,-1.344001 3.000001,-3.000001 V 6.0000001 C 20.25,4.3440001 18.905999,3 17.249999,3 Z"
id="path5580"
style="fill:#000000;fill-opacity:0.780392;stroke-width:1.49999" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg1897"
viewBox="0 0 24 24"
height="24"
width="24"
version="1.2">
<metadata
id="metadata1903">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1901" />
<path
style="fill:#6699cc;fill-opacity:1;stroke-width:1.42859697"
id="path1895"
d="m 3.1443377,2.8368008 c -1.1157342,1.1157342 -1.1157342,2.9243378 0,4.040072 L 8.2658581,11.999821 3.1443377,17.12277 c -1.1157342,1.115734 -1.1157342,2.924338 0,4.040072 C 3.7014904,21.721423 4.4329321,22 5.1643736,22 5.8958159,22 6.627257,21.721423 7.1844103,21.162842 L 16.348859,11.999821 7.1844103,2.8368008 c -1.1143067,-1.1157343 -2.9257671,-1.1157343 -4.0400726,0 z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -29,6 +29,7 @@ cls_archive = delete.svg
cls_trash = trash.svg
proj_document = document-text.svg
proj_folder = folder.svg
doc_h0 = heading0.svg
doc_h1 = heading1.svg
doc_h2 = heading2.svg
doc_h3 = heading3.svg

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg1897"
viewBox="0 0 24 24"
height="24"
width="24"
version="1.2">
<metadata
id="metadata1903">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1901" />
<path
style="fill:#4271ae;fill-opacity:1;stroke-width:1.42859697"
id="path1895"
d="m 3.1443377,2.8368008 c -1.1157342,1.1157342 -1.1157342,2.9243378 0,4.040072 L 8.2658581,11.999821 3.1443377,17.12277 c -1.1157342,1.115734 -1.1157342,2.924338 0,4.040072 C 3.7014904,21.721423 4.4329321,22 5.1643736,22 5.8958159,22 6.627257,21.721423 7.1844103,21.162842 L 16.348859,11.999821 7.1844103,2.8368008 c -1.1143067,-1.1157343 -2.9257671,-1.1157343 -4.0400726,0 z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -29,6 +29,7 @@ cls_archive = delete.svg
cls_trash = trash.svg
proj_document = document-text.svg
proj_folder = folder.svg
doc_h0 = heading0.svg
doc_h1 = heading1.svg
doc_h2 = heading2.svg
doc_h3 = heading3.svg

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg1897"
viewBox="0 0 24 24"
height="24"
width="24"
version="1.2">
<metadata
id="metadata1903">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1901" />
<path
style="fill:#aeaeae;fill-opacity:1;stroke-width:1.42859697"
id="path1895"
d="m 3.1443377,2.8368008 c -1.1157342,1.1157342 -1.1157342,2.9243378 0,4.040072 L 8.2658581,11.999821 3.1443377,17.12277 c -1.1157342,1.115734 -1.1157342,2.924338 0,4.040072 C 3.7014904,21.721423 4.4329321,22 5.1643736,22 5.8958159,22 6.627257,21.721423 7.1844103,21.162842 L 16.348859,11.999821 7.1844103,2.8368008 c -1.1143067,-1.1157343 -2.9257671,-1.1157343 -4.0400726,0 z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -29,6 +29,7 @@ cls_archive = delete.svg
cls_trash = trash.svg
proj_document = document-text.svg
proj_folder = folder.svg
doc_h0 = heading0.svg
doc_h1 = heading1.svg
doc_h2 = heading2.svg
doc_h3 = heading3.svg

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg1897"
viewBox="0 0 24 24"
height="24"
width="24"
version="1.2">
<metadata
id="metadata1903">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1901" />
<path
style="fill:#000000;fill-opacity:0.78039217;stroke-width:1.42859697"
id="path1895"
d="m 3.1443377,2.8368008 c -1.1157342,1.1157342 -1.1157342,2.9243378 0,4.040072 L 8.2658581,11.999821 3.1443377,17.12277 c -1.1157342,1.115734 -1.1157342,2.924338 0,4.040072 C 3.7014904,21.721423 4.4329321,22 5.1643736,22 5.8958159,22 6.627257,21.721423 7.1844103,21.162842 L 16.348859,11.999821 7.1844103,2.8368008 c -1.1143067,-1.1157343 -2.9257671,-1.1157343 -4.0400726,0 z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -29,6 +29,7 @@ cls_archive = delete.svg
cls_trash = trash.svg
proj_document = document-text.svg
proj_folder = folder.svg
doc_h0 = heading0.svg
doc_h1 = heading1.svg
doc_h2 = heading2.svg
doc_h3 = heading3.svg

View File

@@ -2,90 +2,52 @@
<html>
<body>
<h2>Release Notes for 1.0</h2>
<p><i>Released on 3 January 2021</i></p>
<p>Based on my own testing and usage, and no serious bugs discovered in quite some time (aside from
a few corner case issues), it appears that novelWriter is stable enough for a 1.0 release. Thanks
to all the new users who keep providing feedback on bugs, cosmetic issues, or suggesting
improvements and new features. I'm glad to hear that others find my application useful, and I will
keep making improvements as I get new suggestions and have new ideas myself. At the same time, I
will continue to keep novelWriter simple and clean and avoid feature-bloat.</p>
<p>This release mainly fixes cosmetic and other minor issues to the user interface and makes a few
minor improvements to some less used features. Aside from this, nothing major has changed since the
last release candidate.</p>
<p>This release concludes over two years of tinkering with this project. The project grew out of
numerous lunch and coffee discussions with my colleague Marian Lückhof at my former job. We were
both looking for a tool for writing novels on Linux that suited our needs. We started assembling a
wish list of features that has become novelWriter. In addition, users on GitHub have continued to
test new features, provide very helpful feedback, and make new suggestions for improvements.
Especially the feedback from @johnblommers has been helpful during much of the initial development
time. Over the last months more users have started posting ideas and feedback. Thanks to all of you
for your contributions.</p>
<p>The 1.0 release is intended as a first release of the core features of novelWriter. That does
not mean that all planned features have been fully implemented. There is a long list of ideas and
suggestions to consider and implement. New ideas and suggestions are welcome. Either as feature
requests in the issue tracker, or if not fully formed, can be discussed on the
<a href="https://github.com/vkbo/novelWriter/discussions">discussions page</a>.
<h2>Release Notes for 1.4</h2>
<p><i>Released on 27 July 2021</i></p>
<p><i>The full changelog is available
<a href="https://github.com/vkbo/novelWriter/blob/main/CHANGELOG.md">here</a>.</i></p>
<p>This release contains some new features and a lot of code refactoring. Among the main new
features is paragraph alignment and indentation. Regular line breaks within paragraphs are now also
supported. The changes are described in more detail below.</p>
<hr/>
<h3>Internationalisation</h3>
<p>Translation files have been added for Simplified Chinese by Qianzhi Long.</p>
<h2>Release Notes for 1.0 RC2</h2>
<p><i>Released on 13 December 2020</i></p>
<p>This second release candidate for 1.0 comes with only minor changes and improvements, and a
handful of minor bugfixes.</p>
<p>Among the improvements is the addition of all the possible @-keywords for tags and references to
the "Insert" menu under the sub-menu "Tags and References". The "Help" menu has also received a few
improvements and additional links to useful webpages. This release also adds a "Release" notes tab
to the "About novelWriter" dialog. The release notes are displayed automatically the first time you
launch novelWriter after updating to a new version.</p>
<p>Among the fixes is better support for high resolution screens. A few elements on the GUI did not
scale properly, among them the document editor and viewer header and footer. These were clipped on
high res screens due to an underlying issue with the Qt widget underestimating how much space it
required to accommodate the text. Unfortunately, dragging the novelWriter app between screens of
different scaling factors is not currently supported. However, the GUI should scale properly to the
scaling factor on the screen it is opened on.</p>
<p>The work leading up to this release has mostly been focused on improving the test coverage of
the source code of novelWriter. This helps to ensure that the code does what it is intended to do,
and is able to handle corner cases and unexpected external errors and user actions that may occur.
While writing these tests, a number of minor potential issues have been uncovered and handled. Most
of these are corner cases that may not even be reachable by unexpected user actions.</p>
<p>Hopefully, these changes have resulted in an even more stable version of novelWriter. If no more
issues are discovered, the next release will be the final version 1.0 release.</p>
<h3>Line Breaks</h3>
<p>The way line breaks inside paragraphs work has been changed. A single line break is now treated
as a proper line break and will show up in the document viewer and exported documents. A single
line break does not start a new paragraph, but forces a break inside the paragraph like a Shift +
Enter does in most rich text editors. Two line breaks is still needed to start a new paragraph.</p>
<p>The old syntax of adding two spaces at the end of a line to force a line break within a
paragraph will still work as before, so there is no need to change your existing text if you've
used this feature. However, there is a new highlighting feature that will show you where in the
text you have redundant spaces. If you are used to having double spaces between sentences, you may
want to switch off this highlighting feature in Preferences as it will also detect those.</p>
<p>A helper function has been added to the Format menu that can look through a paragraph and remove
line breaks in case you've been using line breaks inside your existing text under the assumption
that the exporter and viewer will ignore them.</p>
<p>I hope this change will not be too inconvenient. I believe the new behaviour will make more
sense for most people. Especially considering some of the feedback I've gotten on how line breaks
work. The original implementation was following the Markdown standard, but since novelWriter is not
a proper Markdown editor and instead just borrows from Markdown, this behaviour always seemed a bit
unnecessary.</p>
<hr/>
<h3>Text Alignment and Indentation</h3>
<p>The default text alignment is left or justified based on your preferences. For documents with
the layout set to Title Page or Partitions, the default is centred. However, sometimes you may
want to override this default. A new set of codes have therefore been added to allow specifying
alignment as well as additional text margins on individual paragraphs.</p>
<p>The logic of the syntax is as follows:</p>
<p>A single angle bracket will push the text away from the edge it points away from. Therefore, a
single '&gt;' before the paragraph, or a single '&lt;' after the paragraph, will add indentation on
the respective side. It's perfectly valid to do this on both sides at the same time.</p>
<p>A double set of angle brackets will push the text all the way towards the opposite side.
Therefore, a double set of '&gt;&gt;' before the paragraph will indicate right alignment, and a
double set of '&lt;&lt;' after the paragraph will force left alignment. Also here both can be used
at the same time, which results in the paragraph being centred.</p>
<p>Format menu entries and keyboard shortcuts have been added so that you don't have to memorise
these codes.</p>
<h2>Release Notes for 1.0 RC1</h2>
<p><i>Released on 16 November 2020</i></p>
<p>This is the first release candidate for the upcoming release of novelWriter 1.0.</p>
<p>Since the fifth beta release about four weeks ago, not much has been changed in novelWriter. A
few minor tweaks have been made to the GUI.</p>
<p>A number of features and tools are now automatically switched off when there is no project or
document open for those features to act upon. Previously, this was a bit inconsistent, although no
serious bugs have been reported or encountered.</p>
<p>Most of the minor changes in this release should not be noticeable to most users. However, there
are a couple of noticeable changes.</p>
<h3>Typewriter Mode</h3>
<p>The "Typewriter Mode" of the editor has been improved. Essentially, this feature is a sort of
smart scroll. It tries to keep the cursor stationary in the vertical direction, and will try to
scroll the document up when the cursor skips to a new line while typing (or down in case of
backspaces). This is similar to the way a typewriter scrolls the paper when hitting the return key.
It improves the writing experience as the current active line will stay at the same eye height
level on the screen.</p>
<p>Previously, the feature would lock the cursor to a given vertical position defined by the user.
Now, instead, the cursor will remain stationary in the vertical direction at any position the user
sets it to by mouse click or keyboard navigation. The user can define a minimum distance from the
top where this feature is activated. These changes makes it more flexible in terms of where the
focus is in the editor. The feature can be controlled from the main Preferences.</p>
<h3>Switching Syntax Theme</h3>
<p>It is now possible to switch syntax highlighting theme without restarting novelWriter.
Previously, changing the theme would only half-way update the document, header and footer
background and text colours. The new settings would not be fully applied until the application was
shut down and started again, thus making it a bit tedious to look through syntax themes to find the
one you want.</p>
<p>Switching main GUI theme still requires a restart.</p>
<p><i>See also the <a href="https://github.com/vkbo/novelWriter/releases">Releases</a> page.</i></p>
</body>
</html>

View File

@@ -0,0 +1,137 @@
<!DOCTYPE html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
<h2>Release Notes for 1.0.4</h2>
<p><i>Released on 3 February 2021</i></p>
<p>This patch release fixes a couple of minor issues with the Preferences dialog and the behaviour
of one of the keyboard shortcuts.</p>
<p>Aside from these fixes, the main point of this patch is to add new setup features for
novelWriter on Windows. A Windows installer will no longer be provided for the foreseeable future,
and instead functionality has been added to the main setup script to create desktop and start menu
icons.</p>
<p><i>The full changelog is available
<a href="https://github.com/vkbo/novelWriter/blob/main/CHANGELOG.md">here</a>.</i></p>
<hr/>
<h2>Release Notes for 1.0.3</h2>
<p><i>Released on 24 January 2021</i></p>
<p>This patch release fixes a minor bug sometimes encountered when running novelWriter from command
line on Windows. In addition, the Solarized Dark and Solarized Light themes have been added to the
selection of GUI and syntax themes by a user contribution.</p>
<p>The main change in this release is to the install scripts and the documentation related to
installing and running novelWriter. The primary change is a different method of packaging the app
for Windows. Instead of building an <i>.exe</i> file, the new setup instead builds a runnable zip
file <i>.pyz</i>. The executable would often be mistakenly flagged by virus control software due to
the packaging tools. This is a known problem with pyinstaller and similar tools, but such warnings
are always concerning even if they are false positives.</p>
<hr/>
<h2>Release Notes for 1.0.2</h2>
<p><i>Released on 19 January 2021</i></p>
<p>This patch release fixes a few minor cosmetic issues, a minor issue with the indexer, and a bug
when adding words to the user's own spell check dictionary. Additionally, the documentation has
been updated based on user feedback, and some install issues resolved.</p>
<hr/>
<h2>Release Notes for 1.0.1</h2>
<p><i>Released on 10 January 2021</i></p>
<p>This release is mainly to bring the documentation up to date, as I forgot to update the install
instructions in the original 1.0 release. I also forgot to change the various settings and help
texts that describe novelWriter as under initial development (beta state).</p>
<p>Some minor improvements have been made to the "Edit Project Item" dialog and some restrictions
on the settings available for documents created in the "Outtakes" folder relaxed. A few minor
issues with the document and project changed icons on the status bar have also been resolved. The
indicators were previously set to changed status even if no actual change had been made to the
project.</p>
<hr/>
<h2>Release Notes for 1.0</h2>
<p><i>Released on 3 January 2021</i></p>
<p>Based on my own testing and usage, and no serious bugs discovered in quite some time (aside from
a few corner case issues), it appears that novelWriter is stable enough for a 1.0 release. Thanks
to all the new users who keep providing feedback on bugs, cosmetic issues, or suggesting
improvements and new features. I'm glad to hear that others find my application useful, and I will
keep making improvements as I get new suggestions and have new ideas myself. At the same time, I
will continue to keep novelWriter simple and clean and avoid feature-bloat.</p>
<p>This release mainly fixes cosmetic and other minor issues to the user interface and makes a few
minor improvements to some less used features. Aside from this, nothing major has changed since the
last release candidate.</p>
<p>This release concludes over two years of tinkering with this project. The project grew out of
numerous lunch and coffee discussions with my colleague Marian Lückhof at my former job. We were
both looking for a tool for writing novels on Linux that suited our needs. We started assembling a
wish list of features that has become novelWriter. In addition, users on GitHub have continued to
test new features, provide very helpful feedback, and make new suggestions for improvements.
Especially the feedback from @johnblommers has been helpful during much of the initial development
time. Over the last months more users have started posting ideas and feedback. Thanks to all of you
for your contributions.</p>
<p>The 1.0 release is intended as a first release of the core features of novelWriter. That does
not mean that all planned features have been fully implemented. There is a long list of ideas and
suggestions to consider and implement. New ideas and suggestions are welcome. Either as feature
requests in the issue tracker, or if not fully formed, can be discussed on the
<a href="https://github.com/vkbo/novelWriter/discussions">discussions page</a>.
<hr/>
<h2>Release Notes for 1.0 RC2</h2>
<p><i>Released on 13 December 2020</i></p>
<p>This second release candidate for 1.0 comes with only minor changes and improvements, and a
handful of minor bugfixes.</p>
<p>Among the improvements is the addition of all the possible @-keywords for tags and references to
the "Insert" menu under the sub-menu "Tags and References". The "Help" menu has also received a few
improvements and additional links to useful webpages. This release also adds a "Release" notes tab
to the "About novelWriter" dialog. The release notes are displayed automatically the first time you
launch novelWriter after updating to a new version.</p>
<p>Among the fixes is better support for high resolution screens. A few elements on the GUI did not
scale properly, among them the document editor and viewer header and footer. These were clipped on
high res screens due to an underlying issue with the Qt widget underestimating how much space it
required to accommodate the text. Unfortunately, dragging the novelWriter app between screens of
different scaling factors is not currently supported. However, the GUI should scale properly to the
scaling factor on the screen it is opened on.</p>
<p>The work leading up to this release has mostly been focused on improving the test coverage of
the source code of novelWriter. This helps to ensure that the code does what it is intended to do,
and is able to handle corner cases and unexpected external errors and user actions that may occur.
While writing these tests, a number of minor potential issues have been uncovered and handled. Most
of these are corner cases that may not even be reachable by unexpected user actions.</p>
<p>Hopefully, these changes have resulted in an even more stable version of novelWriter. If no more
issues are discovered, the next release will be the final version 1.0 release.</p>
<hr/>
<h2>Release Notes for 1.0 RC1</h2>
<p><i>Released on 16 November 2020</i></p>
<p>This is the first release candidate for the upcoming release of novelWriter 1.0.</p>
<p>Since the fifth beta release about four weeks ago, not much has been changed in novelWriter. A
few minor tweaks have been made to the GUI.</p>
<p>A number of features and tools are now automatically switched off when there is no project or
document open for those features to act upon. Previously, this was a bit inconsistent, although no
serious bugs have been reported or encountered.</p>
<p>Most of the minor changes in this release should not be noticeable to most users. However, there
are a couple of noticeable changes.</p>
<h3>Typewriter Mode</h3>
<p>The "Typewriter Mode" of the editor has been improved. Essentially, this feature is a sort of
smart scroll. It tries to keep the cursor stationary in the vertical direction, and will try to
scroll the document up when the cursor skips to a new line while typing (or down in case of
backspaces). This is similar to the way a typewriter scrolls the paper when hitting the return key.
It improves the writing experience as the current active line will stay at the same eye height
level on the screen.</p>
<p>Previously, the feature would lock the cursor to a given vertical position defined by the user.
Now, instead, the cursor will remain stationary in the vertical direction at any position the user
sets it to by mouse click or keyboard navigation. The user can define a minimum distance from the
top where this feature is activated. These changes makes it more flexible in terms of where the
focus is in the editor. The feature can be controlled from the main Preferences.</p>
<h3>Switching Syntax Theme</h3>
<p>It is now possible to switch syntax highlighting theme without restarting novelWriter.
Previously, changing the theme would only half-way update the document, header and footer
background and text colours. The new settings would not be fully applied until the application was
shut down and started again, thus making it a bit tedious to look through syntax themes to find the
one you want.</p>
<p>Switching main GUI theme still requires a restart.</p>
</body>
</html>

View File

@@ -0,0 +1,49 @@
<!DOCTYPE html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
<h2>Release Notes for 1.1.1</h2>
<p><i>Released on 21 February 2021</i></p>
<p>This patch makes a couple of minor improvements to the GUI. The keyboard shortcut for deleting
entries in the project tree has been changed from "Ctrl+Del" to "Ctrl+Shift+Del" to free up that
shortcut for the document editor. It is now possible to use the shortcut for deleting the word in
front of the cursor, a common and useful feature of many text editors.</p>
<p>The way the negative word count filter option works on the Writing Statistics tool has been
changed to be more intuitive. Enabling this filter now appears to remove all negative entries
without altering the other entries. Previously, the removed negative counts would be included in
the following entries to make it consistent with the total word count. In addition, writing
sessions shorter than five minutes, and with no change in the word count, are no longer recorded in
the session log file.</p>
<p>Other changes include improving the speed of the internal spell checker, used when the Enchant
spell check library isn't available. The internal spell checker is no longer significantly slower,
but is still lacking in functionality compared to Enchant.</p>
<p><i>See also the <a href="https://github.com/vkbo/novelWriter/releases">Releases</a> page.</i></p>
<hr/>
<h2>Release Notes for 1.1</h2>
<p><i>Released on 7 February 2021</i></p>
<p>The main change in this release is the addition of a new tab to the project tree on the left
side of the main window. The regular project tree is now on a tab named "Project", while a new tab
named "Novel" displays a simpler version of the information on the main "Outline" page. It lists
all the headers of the novel part of the project, as well as the word count and point-of-view
character of each section. This is an alternative way to navigate the novel part of the project.
The various tree views are now also kept better in sync when the user selects various documents and
headers.</p>
<p>In addition, a new information dialog named "Project Details" has been added. It replaces the
"Details" tab in "Project Settings", and adds more information about the novel part of the project.
In particular, a "Table of Contents" in the "Contents" tab displays a summary of the main parts
and chapters of the project, their total word counts, and an estimated page count. This was made in
response to users asking for ways to estimate the total page count of the project. The page count
is estimated based on a words per page setting, which can be changed on the dialog window.</p>
<p>Since the tabs below the project tree now add some extra room on the GUI, some convenient
buttons have been added in the same area, with direct access to "Project Details", "Writing
Statistics" and "Project Setting".</p>
<p>A few other minor changes have been made as well. The Preferences dialog has been improved with
clearer categories and hopefully better help text. Some new options have been added too. They allow
syntax highlighting of multi-paragraph quotes. The highlighter can now optionally accept quotes to
be left "hanging", that is, no closing quote in the same paragraph.</p>
</body>
</html>

View File

@@ -0,0 +1,104 @@
<!DOCTYPE html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
<h2>Release Notes for 1.2.2</h2>
<p><i>Released on 28 March 2021</i></p>
<p>This patch release is a bug fix release addressing some inconsistencies and issues with the
document header buttons when Focus Mode is active. The keyboard shortcuts for search and replace
should now also work in Focus Mode. In addition, the setup script for novelWriter has been improved
when installing on Windows.</p>
<p><i>See also the <a href="https://github.com/vkbo/novelWriter/releases">Releases</a> page.</i></p>
<hr/>
<h2>Release Notes for 1.2.1</h2>
<p><i>Released on 21 March 2021</i></p>
<p>This patch release is a bug fix release addressing issues with the document editor's search and
replace tool. Due to some recently added restrictions on when various tools are active, depending
on which part of the main window has the user's focus, the search tool keyboard shortcuts and
buttons were blocked when they shouldn't. This release resolves these issues.</p>
<hr/>
<h2>Release Notes for 1.2</h2>
<p><i>Released on 14 March 2021</i></p>
<p>This release is mainly focused on the Build Novel Project tool. Completely new export classes
have been written to support Open Document and Markdown exports. In addition, the way document
layouts are handled have been automated a little to assist the user in keeping header levels and
document layout flags in sync. The third new additoion is the ability to record and log idle time
during a writing session to improve the writing statistics information as requested by several
users. Finally, it is now possible to directly edit the project dictionary via a new, simple GUI
dialog.</p>
<h3>The Build Novel Project Tool</h3>
<p>The main changes for this release are to the Build Novel Project tool. The Open Document export,
as well as the Markdown export, is now handled entirely by code written for novelWriter.
Previously, these export features depended on the underlying Qt library's save routines connected
to the preview document shown in the build dialog. Using this method of export both meant that the
content of the document was dependent on the preview being generated first, and it also meant that
the exported document had limited support for novelWriter-specific features and custom formatting.
The new export class should generate a much better result, especially for the Open Document
formats. The Open Document standard is supported by Open Office, Libre Office, Google Docs,
Microsoft Word, and probably a number of other applications too. The Markdown export hasn't changed
a lot, but should be a slight improvement on the previous export feature.</p>
<p>These changes to the build tool also imply that the saving process is now independent of the
content of the preview window, meaning you don't have to rebuild the preview before saving, which
was previously the case. To make this more consistent, the PDF export option has been moved to the
print button as it is actually a print-to-file feature under the hood, not technically a proper PDF
export format. It is exactly the same as printing to file from the print preview dialog.</p>
<p>In addition to the changes to the export features, the Build Novel Project tool now also has
controls for line height, which applies to all rich text export formats, and the option to replace
unicode characters with appropriate html entities for html export.</p>
<h3>Document Layout Automation</h3>
<p>Among other changes in this release are a few improvements to the process of creating and
changing documents. When a new document is first created, the header is generated from the assigned
label and layout.</p>
<p>In addition, for some document layouts, when the user changes the header level of the first
header of the document, the document layout setting is updated accordingly. This should reduce the
need for the user to maintain two ways of assigning the role of a given document. This automation
only applies to combinations of header level and current document layouts where there is no
ambiguity. For instance, changing the header level in a "Scene" document from level 3 to 2 changes
the document layout automatically to "Chapter". But changing the first header of a "Book" layout
document from 1 to 2 does not change the document's layout as the "Book" layout is a generic
document layout and it's perfectly reasonable for its first header to be a chapter header.</p>
<p>Keep in mind that novelWriter treats documents with layout "Book", "Chapter" and "Scene" exactly
the same during exports. The distinction is only meant as a way to indicate the purpose of a
document in the project tree. This new automation is meant to assist in keeping this information up
to date. The other layouts do have an effect on formatting during export, and are generally left
alone.</p>
<h3>The Session Timer and Idle Time</h3>
<p>Another change that has been requested by a couple of users is to have the session timer in the
status bar stop counting when the user is inactive (idle). This feature is optional, and can be
controlled from Preferences. The definition of "idle" in this context is either that the user is
active in a different application than novelWriter (loss of focus) or that the user has not made
any changes to the current document for a given amount of time. The time threshold is by default
five minutes, but can be altered in Preferences.</p>
<p>In addition, the idle time is also recorded in the session log, and can be viewed in the Writing
Statistics dialog and exported with the rest of the information. The idle time is recorder in the
logs regardless of whether the status bar clock takes idle time into consideration or not. So even
if you turn off the idle time switch in Preferences, the other idle time setting still affects the
writing stats log entries.</p>
<h3>Other Changes</h3>
<p>The user dictionary of the project, where words added to the dictionary from the document editor
go, can now be viewed and edited with a new "Project Word List" tool in the "Tools" menu.</p>
<p>A small additional feature added is also the ability to undo the last move of an item in the
project tree. The keyboard shortcut for this is `Ctrl+Shift+Z`, or it can be accessed from the
menu. The feature can only undo the last move, but it includes both documents moved to trash, moves
by up/down keypress or menu entries, and drag and drop moves.</p>
<p>A new keyword has been added to mark characters in the story. The new keyword is intended to tag
a character as the focus character for a chapter or scene. This is useful for stories where the
point-of-view character and the focus character are different.</p>
<p>Lastly, two bugfixes have been made as well. The Empty Trash feature was no longer working due
to an earlier fix solving another issue. The feature has now been restored. In addition, the
indexer now checks that a keyword (tag or reference) is valid before saving it to the index.
Previously, an invalid keyword could be saved to the index and potentially crash the application.
</p>
</body>
</html>

View File

@@ -0,0 +1,60 @@
<!DOCTYPE html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
<h2>Release Notes for 1.3.3</h2>
<p><i>Released on 13 June 2021</i></p>
<p>This patch release fixes a potential file encoding issue when running setup on Windows, and a
minor issue with the project word count not being updated immediately when a file is deleted. In
addition, the keyboard shortcuts to change focus between the project tree, the editor, the viewer,
and the outline panel, have been changed for Windows users. They keyboard shortcuts were
interfering with the Alt codes used for special characters. The shortcuts are unchanged for Linux
and macOS.</p>
<p><i>See also the <a href="https://github.com/vkbo/novelWriter/releases">Releases</a> page.</i></p>
<hr/>
<h2>Release Notes for 1.3.2</h2>
<p><i>Released on 30 May 2021</i></p>
<p>This is a patch release that fixes some minor issues. One issue was with the split tool, which
would drop the last line from the source document during a split if it was missing a final line
break. A minor issue with the display of word counts on the details panel under the project tree
has also been fixed. In addition, the setup script commands for Linux have been improved a bit.</p>
<hr/>
<h2>Release Notes for 1.3.1</h2>
<p><i>Released on 6 May 2021</i></p>
<p>This is a patch release primarily to fix a problem with the Qt translation library used to make
novelWriter available in multiple languages. One of the function calls made to the library was
added recently, in Qt 5.15, which many users on Linux will not have installed on their system. The
issue could be resolved by updating the library, but it's an unnecessary and inconvenient
restriction.</p>
<hr/>
<h2>Release Notes for 1.3</h2>
<p><i>Released on 2 May 2021</i></p>
<p>The main feature of the 1.3 release is internationalisation. The release introduces support for
Portuguese, French, and Norwegian for the main GUI, in addition to the default English. The
settings for choosing the GUI language can be found in the main Preferences.</p>
<p>The implementation is such that the projects themselves can use a different language than the
one selected for the GUI. To allow for better support for multiple language projects, the Build
Novel Project tool has the added option to select the language of the injected text into exported
documents. In particularly for the number words that can be added for chapter headers. Available
languages here are the same as mentioned above for the main GUI, plus German.</p>
<p>Settings have also been added in Preferences to allow for automatic injection of spaces or
non-breaking spaces in front of, or behind, certain characters. These are features generally
available in text editors for French, but the implementation in novelWriter simply makes them a
free text box where you can list all characters or symbols where you want a space added
automatically.</p>
<p>The translation files for this release have been provided by Bruno Meneguello for the Portuguese
translation, by Jan Lüdke (jyhelle) for the French translation, by Veronica Berglyd Olsen for the
Norwegian translation as well as the minor modifications for US English, and Marian Lückhof
provided the translation file for chapter numbers in German.</p>
<p>The work to rewrite novelWriter to allow for internationalisation was done by Bruno Meneguello
and Veronica Berglyd Olsen.</p>
</body>
</html>

View File

@@ -23,7 +23,6 @@ link = 44, 152, 247
linkvisited = 44, 152, 247
[GUI]
treewordcount = 197, 200, 198
statusnone = 150, 152, 150
statussaved = 39, 135, 78
statusunsaved = 138, 32, 32

View File

@@ -0,0 +1,28 @@
[Main]
name = Solarized Dark
author = nullbasis
credit = Ethan Schoonover
url = https://ethanschoonover.com/solarized/
license = MIT
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
[Palette]
window = 0, 43, 54
windowtext = 253, 246, 227
base = 7, 54, 66
alternatebase = 67, 67, 67
text = 253, 246, 227
tooltipbase = 133, 153, 0
tooltiptext = 0, 43, 54
button = 7, 54, 66
buttontext = 253, 246, 227
brighttext = 253, 246, 227
highlight = 42, 161, 152
highlightedtext = 0, 43, 54
link = 38, 139, 210
linkvisited = 38, 139, 210
[GUI]
statusnone = 88, 110, 117
statussaved = 42, 161, 152
statusunsaved = 203, 75, 22

View File

@@ -0,0 +1,28 @@
[Main]
name = Solarized Light
author = nullbasis
credit = Ethan Schoonover
url = https://ethanschoonover.com/solarized/
license = MIT
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
[Palette]
window = 238, 232, 213
windowtext = 0, 43, 54
base = 253, 246, 227
alternatebase = 238, 232, 213
text = 0, 43, 54
tooltipbase = 133, 153, 0
tooltiptext = 0, 43, 54
button = 238, 232, 213
buttontext = 0, 43, 54
brighttext = 0, 43, 54
highlight = 42, 161, 152
highlightedtext = 253, 246, 227
link = 38, 139, 210
linkvisited = 38, 139, 210
[GUI]
statusnone = 88, 110, 117
statussaved = 42, 161, 152
statusunsaved = 203, 75, 22

View File

@@ -20,6 +20,6 @@ hidden = 150, 150, 150
keyword = 200, 46, 0
value = 184, 200, 0
spellcheckline = 200, 46, 0
tagerror = 46, 200, 0
errorline = 46, 200, 0
replacetag = 0, 184, 46
modifier = 200, 120, 0

View File

@@ -20,6 +20,6 @@ hidden = 100, 100, 100
keyword = 200, 50, 50
value = 50, 150, 50
spellcheckline = 200, 0, 0
tagerror = 0, 150, 0
errorline = 0, 150, 0
replacetag = 0, 150, 0
modifier = 150, 110, 30

View File

@@ -20,6 +20,6 @@ hidden = 150, 150, 150
keyword = 225, 225, 225
value = 200, 200, 200
spellcheckline = 200, 46, 0
tagerror = 46, 200, 0
errorline = 46, 200, 0
replacetag = 225, 225, 225
modifier = 225, 225, 225

View File

@@ -20,6 +20,6 @@ hidden = 100, 100, 100
keyword = 0, 0, 0
value = 20, 20, 20
spellcheckline = 200, 0, 0
tagerror = 0, 150, 0
errorline = 0, 150, 0
replacetag = 0, 0, 0
modifier = 0, 0, 0

View File

@@ -40,6 +40,6 @@ hidden = 152, 159, 177
keyword = 222, 61, 58
value = 150, 74, 193
spellcheckline = 222, 61, 58
tagerror = 8, 145, 106
errorline = 8, 145, 106
replacetag = 42, 162, 152
modifier = 224, 175, 5

View File

@@ -40,6 +40,6 @@ hidden = 99, 119, 119
keyword = 247, 140, 108
value = 199, 146, 234
spellcheckline = 247, 140, 108
tagerror = 173, 219, 103
errorline = 173, 219, 103
replacetag = 127, 219, 202
modifier = 236, 196, 141

View File

@@ -0,0 +1,25 @@
[Main]
name = Solarized Dark
author = nullbasis
credit = Ethan Schoonover
url = https://ethanschoonover.com/solarized/
license = MIT
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
[Syntax]
background = 7, 54, 66
text = 253, 246, 227
link = 38, 139, 210
headertext = 147, 161, 161
headertag = 42, 161, 152
emphasis = 38, 139, 210
straightquotes = 211, 54, 130
doublequotes = 42, 161, 152
singlequotes = 42, 161, 152
hidden = 147, 161, 161
keyword = 133, 153, 0
value = 203, 75, 22
spellcheckline = 203, 75, 22
errorline = 220, 50, 47
replacetag = 133, 153, 0
modifier = 181, 137, 0

View File

@@ -0,0 +1,25 @@
[Main]
name = Solarized Light
author = nullbasis
credit = Ethan Schoonover
url = https://ethanschoonover.com/solarized/
license = MIT
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
[Syntax]
background = 253, 246, 227
text = 0, 43, 54
link = 38, 139, 210
headertext = 88, 110, 117
headertag = 42, 161, 152
emphasis = 38, 139, 210
straightquotes = 211, 54, 130
doublequotes = 42, 161, 152
singlequotes = 42, 161, 152
hidden = 88, 110, 117
keyword = 133, 153, 0
value = 203, 75, 22
spellcheckline = 203, 75, 22
errorline = 220, 50, 47
replacetag = 133, 153, 0
modifier = 181, 137, 0

View File

@@ -40,6 +40,6 @@ hidden = 142, 144, 140
keyword = 240, 40, 41
value = 137, 89, 168
spellcheckline = 240, 40, 41
tagerror = 113, 140, 0
errorline = 113, 140, 0
replacetag = 62, 153, 159
modifier = 245, 135, 31

View File

@@ -40,6 +40,6 @@ hidden = 150, 152, 150
keyword = 204, 102, 102
value = 178, 148, 187
spellcheckline = 204, 102, 102
tagerror = 181, 189, 104
errorline = 181, 189, 104
replacetag = 138, 190, 183
modifier = 222, 147, 95

View File

@@ -40,6 +40,6 @@ hidden = 114, 133, 183
keyword = 255, 157, 164
value = 235, 187, 255
spellcheckline = 255, 157, 164
tagerror = 209, 241, 169
errorline = 209, 241, 169
replacetag = 153, 255, 255
modifier = 255, 197, 143

View File

@@ -40,6 +40,6 @@ hidden = 150, 152, 150
keyword = 213, 78, 83
value = 195, 151, 216
spellcheckline = 213, 78, 83
tagerror = 185, 202, 74
errorline = 185, 202, 74
replacetag = 112, 192, 177
modifier = 231, 140, 69

View File

@@ -40,6 +40,6 @@ hidden = 153, 153, 153
keyword = 242, 119, 122
value = 204, 153, 204
spellcheckline = 242, 119, 122
tagerror = 153, 204, 153
errorline = 153, 204, 153
replacetag = 102, 204, 204
modifier = 249, 145, 57

View File

@@ -1,28 +1,26 @@
# -*- coding: utf-8 -*-
"""novelWriter Common Functions
"""
novelWriter – Common Functions
==============================
Various common functions
novelWriter – Common Functions
================================
Various functions used multiple places
File History:
Created: 2019-05-12 [0.1.0]
File History:
Created: 2019-05-12 [0.1.0]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
@@ -30,71 +28,78 @@ import logging
from datetime import datetime
from PyQt5.QtWidgets import qApp
from PyQt5.QtCore import QCoreApplication
from nw.enum import nwItemClass, nwItemType, nwItemLayout
from nw.constants import nwConst, nwUnicode
logger = logging.getLogger(__name__)
def checkString(checkValue, defaultValue, allowNone=False):
def checkString(value, default, allowNone=False):
"""Check if a variable is a string or a none.
"""
if allowNone:
if checkValue is None:
if value is None:
return None
if checkValue == "None":
if value == "None":
return None
if isinstance(checkValue, str):
return str(checkValue)
return defaultValue
if isinstance(value, str):
return str(value)
return default
def checkInt(checkValue, defaultValue, allowNone=False):
def checkInt(value, default, allowNone=False):
"""Check if a variable is an integer or a none.
"""
if allowNone:
if checkValue is None:
if value is None:
return None
if checkValue == "None":
if value == "None":
return None
try:
return int(checkValue)
return int(value)
except Exception:
return defaultValue
return default
def checkBool(checkValue, defaultValue, allowNone=False):
def checkBool(value, default, allowNone=False):
"""Check if a variable is a boolean or a none.
"""
if allowNone:
if checkValue is None:
if value is None:
return None
if checkValue == "None":
if value == "None":
return None
if isinstance(checkValue, str):
if checkValue == "True":
if isinstance(value, str):
if value == "True":
return True
elif checkValue == "False":
elif value == "False":
return False
else:
return defaultValue
elif isinstance(checkValue, int):
if checkValue == 1:
return default
elif isinstance(value, int):
if value == 1:
return True
elif checkValue == 0:
elif value == 0:
return False
else:
return defaultValue
return defaultValue
return default
return default
def checkHandle(checkValue, defaultValue, allowNone=False):
def checkHandle(value, default, allowNone=False):
"""Check if a value is a handle.
"""
if allowNone:
if checkValue is None:
if value is None:
return None
if checkValue == "None":
if value == "None":
return None
if isHandle(checkValue):
return str(checkValue)
return defaultValue
if isHandle(value):
return str(value)
return default
def isHandle(theString):
"""Check if a string is a valid novelWriter handle.
@@ -104,42 +109,55 @@ def isHandle(theString):
return False
if len(theString) != 13:
return False
invalidChar = False
for c in theString:
if c not in "0123456789abcdef":
invalidChar = True
return not invalidChar
return False
return True
def colRange(rgbStart, rgbEnd, nStep):
"""Generate a range of colours from one RGB value to another.
def isTitleTag(theString):
"""Check if a string is a valid title string.
"""
if len(rgbStart) != 3 and len(rgbEnd) != 3 and nStep < 1:
logger.error("Cannot create colour range from given parameters")
return None
if not isinstance(theString, str):
return False
if len(theString) != 7:
return False
if not theString.startswith("T"):
return False
for c in theString[1:]:
if c not in "0123456789":
return False
return True
if nStep == 1:
return rgbStart
elif nStep == 2:
return [rgbStart, rgbEnd]
dC = [0, 0, 0]
for c in range(3):
cA = rgbStart[c]
cB = rgbEnd[c]
dC[c] = (cB-cA)/(nStep-1)
print(dC)
retCol = [rgbStart]
for n in range(nStep):
if n > 0 and n < nStep:
retCol.append([
int(retCol[n-1][0] + dC[0]),
int(retCol[n-1][1] + dC[1]),
int(retCol[n-1][2] + dC[2]),
])
retCol[-1] = rgbEnd
print(retCol)
def isItemClass(theString):
"""Check if an item is a calid nwItemClass identifier.
"""
return theString in nwItemClass.__members__
def isItemType(theString):
"""Check if an item is a calid nwItemType identifier.
"""
return theString in nwItemType.__members__
def isItemLayout(theString):
"""Check if an item is a calid nwItemLayout identifier.
"""
return theString in nwItemLayout.__members__
def hexToInt(value, default=0):
"""Convert a hex string to an integer.
"""
if isinstance(value, str):
try:
return int(value, 16)
except Exception:
return default
return default
return retCol
def formatInt(theInt):
"""Formats an integer with k, M, G etc.
@@ -152,14 +170,15 @@ def formatInt(theInt):
theVal /= 1000.0
if theVal < 1000.0:
if theVal < 10.0:
return f"{theVal:4.2f}{nwUnicode.U_THNSP}{pF}"
return f"{theVal:4.2f}{nwUnicode.U_THSP}{pF}"
elif theVal < 100.0:
return f"{theVal:4.1f}{nwUnicode.U_THNSP}{pF}"
return f"{theVal:4.1f}{nwUnicode.U_THSP}{pF}"
else:
return f"{theVal:3.0f}{nwUnicode.U_THNSP}{pF}"
return f"{theVal:3.0f}{nwUnicode.U_THSP}{pF}"
return str(theInt)
def formatTimeStamp(theTime, fileSafe=False):
"""Take a number (on the format returned by time.time()) and convert
it to a timestamp string.
@@ -169,6 +188,7 @@ def formatTimeStamp(theTime, fileSafe=False):
else:
return datetime.fromtimestamp(theTime).strftime(nwConst.FMT_TSTAMP)
def formatTime(tS):
"""Format a time in seconds in HH:MM:SS format or d-HH:MM:SS format
if a full day or longer.
@@ -180,6 +200,7 @@ def formatTime(tS):
return f"{tS//3600:02d}:{tS%3600//60:02d}:{tS%60:02d}"
return "ERROR"
def splitVersionNumber(vString):
""" Splits a version string on the form aa.bb.cc into major, minor
and patch, and computes an integer value aabbcc.
@@ -187,7 +208,7 @@ def splitVersionNumber(vString):
vMajor = 0
vMinor = 0
vPatch = 0
vInt = 0
vInt = 0
vBits = vString.split(".")
nBits = len(vBits)
@@ -203,6 +224,7 @@ def splitVersionNumber(vString):
return [vMajor, vMinor, vPatch, vInt]
def transferCase(theSource, theTarget):
"""Transfers the case of the source word to the target word. This
will consider all upper or lower, and first char capitalisation.
@@ -224,37 +246,67 @@ def transferCase(theSource, theTarget):
return theResult
def fuzzyTime(secDiff):
"""Converts a time difference in seconds into a fuzzy time string.
"""
if secDiff < 0:
return "in the future"
return QCoreApplication.translate(
"Common", "in the future"
)
elif secDiff < 30:
return "just now"
return QCoreApplication.translate(
"Common", "just now"
)
elif secDiff < 90:
return "a minute ago"
elif secDiff < 3300: # 55 minutes
return "%d minutes ago" % int(round(secDiff/60))
elif secDiff < 5400: # 90 minutes
return "an hour ago"
elif secDiff < 84600: # 23.5 hours
return "%d hours ago" % int(round(secDiff/3600))
elif secDiff < 129600: # 1.5 days
return "a day ago"
elif secDiff < 561600: # 6.5 days
return "%d days ago" % int(round(secDiff/86400))
elif secDiff < 907200: # 10.5 days
return "a week ago"
elif secDiff < 2419200: # 28 days
return "%d weeks ago" % int(round(secDiff/604800))
elif secDiff < 3888000: # 45 days
return "a month ago"
elif secDiff < 29808000: # 345 days
return "%d months ago" % int(round(secDiff/2592000))
elif secDiff < 47336400: # 1.5 years
return "a year ago"
return QCoreApplication.translate(
"Common", "a minute ago"
)
elif secDiff < 3300: # 55 minutes
return QCoreApplication.translate(
"Common", "{0} minutes ago"
).format(int(round(secDiff/60)))
elif secDiff < 5400: # 90 minutes
return QCoreApplication.translate(
"Common", "an hour ago"
)
elif secDiff < 84600: # 23.5 hours
return QCoreApplication.translate(
"Common", "{0} hours ago"
).format(int(round(secDiff/3600)))
elif secDiff < 129600: # 1.5 days
return QCoreApplication.translate(
"Common", "a day ago"
)
elif secDiff < 561600: # 6.5 days
return QCoreApplication.translate(
"Common", "{0} days ago"
).format(int(round(secDiff/86400)))
elif secDiff < 907200: # 10.5 days
return QCoreApplication.translate(
"Common", "a week ago"
)
elif secDiff < 2419200: # 28 days
return QCoreApplication.translate(
"Common", "{0} weeks ago"
).format(int(round(secDiff/604800)))
elif secDiff < 3888000: # 45 days
return QCoreApplication.translate(
"Common", "a month ago"
)
elif secDiff < 29808000: # 345 days
return QCoreApplication.translate(
"Common", "{0} months ago"
).format(int(round(secDiff/2592000)))
elif secDiff < 47336400: # 1.5 years
return QCoreApplication.translate(
"Common", "a year ago"
)
else:
return "%d years ago" % int(round(secDiff/31557600))
return QCoreApplication.translate(
"Common", "{0} years ago"
).format(int(round(secDiff/31557600)))
def makeFileNameSafe(theText):
"""Returns a filename safe version of the text.
@@ -265,6 +317,7 @@ def makeFileNameSafe(theText):
cleanName += c
return cleanName
def getGuiItem(theName):
"""Returns a QtWidget based on its objectName.
"""
@@ -272,3 +325,27 @@ def getGuiItem(theName):
if qWidget.objectName() == theName:
return qWidget
return None
def numberToRoman(numVal, isLower=False):
"""Convert an integer to a roman number.
"""
if not isinstance(numVal, int):
return "NAN"
if numVal < 1 or numVal > 4999:
return "OOR"
theValues = [
(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"),
(50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I"),
]
romNum = ""
for theDiv, theSym in theValues:
n = numVal//theDiv
romNum += n*theSym
numVal -= n*theDiv
if numVal <= 0:
break
return romNum.lower() if isLower else romNum

View File

@@ -1,47 +1,50 @@
# -*- coding: utf-8 -*-
"""novelWriter Config Class
"""
novelWriter – Config Class
==========================
Class holding the user preferences and handling the config file
novelWriter – Config Class
============================
Class reading and holding the preferences of the application
File History:
Created: 2018-09-22 [0.0.1]
File History:
Created: 2018-09-22 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import os
import sys
import json
import shutil
import logging
import configparser
import shutil
import json
import sys
import os
from time import time
from PyQt5.Qt import PYQT_VERSION_STR
from PyQt5.QtCore import QT_VERSION_STR, QStandardPaths, QSysInfo
from PyQt5.QtCore import (
QT_VERSION_STR, QStandardPaths, QSysInfo, QLocale, QLibraryInfo,
QTranslator
)
from nw.constants import nwConst, nwFiles, nwUnicode
from nw.error import logException
from nw.common import splitVersionNumber, formatTimeStamp
from nw.constants import nwConst, nwFiles, nwUnicode
logger = logging.getLogger(__name__)
class Config:
CNF_STR = 0
@@ -50,16 +53,15 @@ class Config:
CNF_S_LST = 3
CNF_I_LST = 4
LANG_NW = 1
LANG_PROJ = 2
def __init__(self):
# Set Application Variables
self.appName = "novelWriter"
self.appHandle = self.appName.lower()
# Debug Settings
self.showGUI = True # Allow blocking the GUI (disabled for testing)
self.debugInfo = False # True if log level is DEBUG or VERBOSE
# Config Error Handling
self.hasError = False # True if the config class encountered an error
self.errData = [] # List of error messages
@@ -80,81 +82,98 @@ class Config:
self.helpPath = None # The full path to the novelwriter .qhc help file
# Runtime Settings and Variables
self.confChanged = False # True whenever the config has chenged, false after save
self.hasHelp = False # True if the Qt help files are present in the assets folder
self.confChanged = False # True whenever the config has chenged, false after save
self.hasHelp = False # True if the Qt help files are present in the assets folder
## General
# General
self.guiTheme = "default"
self.guiSyntax = "default_light"
self.guiIcons = "typicons_colour_light"
self.guiDark = False # Load icons for dark backgrounds, if available
self.guiLang = "en" # Hardcoded for now since the GUI is only in English
self.guiFont = "" # Defaults to system default font
self.guiFontSize = 11
self.guiScale = 1.0 # Set automatically by Theme class
self.lastNotes = "" # The latest release notes that have been shown
self.guiDark = False # Load icons for dark backgrounds, if available
self.guiFont = "" # Defaults to system default font
self.guiFontSize = 11 # Is overridden if system default is loaded
self.guiScale = 1.0 # Set automatically by Theme class
self.lastNotes = "0x0" # The latest release notes that have been shown
## Sizes
self.winGeometry = [1200, 650]
self.treeColWidth = [200, 50, 30]
self.projColWidth = [200, 60, 140]
self.mainPanePos = [300, 800]
self.docPanePos = [400, 400]
self.viewPanePos = [500, 150]
self.outlnPanePos = [500, 150]
self.isFullScreen = False
# Localisation
self.qLocal = QLocale.system()
self.guiLang = self.qLocal.name()
self.qtLangPath = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
self.nwLangPath = None
self.qtTrans = {}
## Features
self.hideVScroll = False # Hide vertical scroll bars on main widgets
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
# Sizes
self.winGeometry = [1200, 650]
self.prefGeometry = [700, 615]
self.treeColWidth = [200, 50, 30]
self.novelColWidth = [200, 50]
self.projColWidth = [200, 60, 140]
self.mainPanePos = [300, 800]
self.docPanePos = [400, 400]
self.viewPanePos = [500, 150]
self.outlnPanePos = [500, 150]
self.isFullScreen = False
## Project
self.autoSaveProj = 60 # Interval for auto-saving project in seconds
self.autoSaveDoc = 30 # Interval for auto-saving document in seconds
# Features
self.hideVScroll = False # Hide vertical scroll bars on main widgets
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
## Text Editor
self.textFont = None # Editor font
self.textSize = 12 # Editor font size
self.textFixedW = True # Keep editor text fixed width
self.textWidth = 600 # Editor text width
self.textMargin = 40 # Editor/viewer text margin
self.tabWidth = 40 # Editor tabulator width
# Project
self.autoSaveProj = 60 # Interval for auto-saving project in seconds
self.autoSaveDoc = 30 # Interval for auto-saving document in seconds
self.focusWidth = 800 # Focus Mode text width
self.hideFocusFooter = False # Hide document footer in Focus Mode
self.showFullPath = True # Show full document path in editor header
self.autoSelect = True # Auto-select word when applying format with no selection
# Text Editor
self.textFont = None # Editor font
self.textSize = 12 # Editor font size
self.textFixedW = True # Keep editor text fixed width
self.textWidth = 600 # Editor text width
self.textMargin = 40 # Editor/viewer text margin
self.tabWidth = 40 # Editor tabulator width
self.doJustify = False # Justify text
self.showTabsNSpaces = False # Show tabs and spaces in edior
self.showLineEndings = False # Show line endings in editor
self.focusWidth = 800 # Focus Mode text width
self.hideFocusFooter = False # Hide document footer in Focus Mode
self.showFullPath = True # Show full document path in editor header
self.autoSelect = True # Auto-select word when applying format with no selection
self.doReplace = True # Enable auto-replace as you type
self.doReplaceSQuote = True # Smart single quotes
self.doReplaceDQuote = True # Smart double quotes
self.doReplaceDash = True # Replace multiple hyphens with dashes
self.doReplaceDots = True # Replace three dots with ellipsis
self.doJustify = False # Justify text
self.showTabsNSpaces = False # Show tabs and spaces in edior
self.showLineEndings = False # Show line endings in editor
self.showMultiSpaces = True # Highlight multiple spaces in the text
self.scrollPastEnd = True # Allow scrolling past end of document
self.autoScroll = False # Typewriter-like scrolling
self.autoScrollPos = 30 # Start point for typewriter-like scrolling
self.doReplace = True # Enable auto-replace as you type
self.doReplaceSQuote = True # Smart single quotes
self.doReplaceDQuote = True # Smart double quotes
self.doReplaceDash = True # Replace multiple hyphens with dashes
self.doReplaceDots = True # Replace three dots with ellipsis
self.wordCountTimer = 5.0 # Interval for word count update in seconds
self.bigDocLimit = 800 # Size threshold for heavy editor features in kilobytes
self.scrollPastEnd = True # Allow scrolling past end of document
self.autoScroll = False # Typewriter-like scrolling
self.autoScrollPos = 30 # Start point for typewriter-like scrolling
self.highlightQuotes = True # Highlight text in quotes
self.highlightEmph = True # Add colour to text emphasis
self.wordCountTimer = 5.0 # Interval for word count update in seconds
self.bigDocLimit = 800 # Size threshold for heavy editor features in kilobytes
## User-Selected Symbols
self.highlightQuotes = True # Highlight text in quotes
self.allowOpenSQuote = False # Allow open-ended single quotes
self.allowOpenDQuote = True # Allow open-ended double quotes
self.highlightEmph = True # Add colour to text emphasis
self.stopWhenIdle = True # Stop the status bar clock when the user is idle
self.userIdleTime = 300 # Time of inactivity to consider user idle
# User-Selected Symbols
self.fmtApostrophe = nwUnicode.U_RSQUO
self.fmtSingleQuotes = [nwUnicode.U_LSQUO, nwUnicode.U_RSQUO]
self.fmtDoubleQuotes = [nwUnicode.U_LDQUO, nwUnicode.U_RDQUO]
self.fmtPadBefore = ""
self.fmtPadAfter = ""
self.fmtPadThin = False
## Spell Checking
# Spell Checking
self.spellTool = None
self.spellLanguage = None
## Search Bar Switches
# Search Bar Switches
self.searchCase = False
self.searchWord = False
self.searchRegEx = False
@@ -162,12 +181,12 @@ class Config:
self.searchNextFile = False
self.searchMatchCap = False
## Backup
# Backup
self.backupPath = ""
self.backupOnClose = False
self.askBeforeBackup = True
## State
# State
self.showRefPanel = True
self.viewComments = True
self.viewSynopsis = True
@@ -216,8 +235,8 @@ class Config:
self.kernelVer = "Unknown"
# Packages
self.hasEnchant = False # The pyenchant package
self.hasAssistant = False # The Qt Assistant executable
self.hasEnchant = False # The pyenchant package
self.hasAssistant = False # The Qt Assistant executable
# Recent Cache
self.recentProj = {}
@@ -253,7 +272,7 @@ class Config:
confRoot = QStandardPaths.writableLocation(QStandardPaths.ConfigLocation)
self.confPath = os.path.join(os.path.abspath(confRoot), self.appHandle)
else:
logger.info("Setting config from alternative path: %s" % confPath)
logger.info("Setting config from alternative path: %s", confPath)
self.confPath = confPath
if dataPath is None:
@@ -263,24 +282,36 @@ class Config:
dataRoot = QStandardPaths.writableLocation(QStandardPaths.DataLocation)
self.dataPath = os.path.join(os.path.abspath(dataRoot), self.appHandle)
else:
logger.info("Setting data path from alternative path: %s" % dataPath)
logger.info("Setting data path from alternative path: %s", dataPath)
self.dataPath = dataPath
logger.verbose("Config path: %s" % self.confPath)
logger.verbose("Data path: %s" % self.dataPath)
logger.verbose("Config path: %s", self.confPath)
logger.verbose("Data path: %s", self.dataPath)
self.confFile = self.appHandle+".conf"
self.lastPath = os.path.expanduser("~")
self.appPath = getattr(sys, "_MEIPASS", os.path.abspath(os.path.dirname(__file__)))
self.appRoot = os.path.join(self.appPath, os.path.pardir)
self.confFile = self.appHandle+".conf"
self.lastPath = os.path.expanduser("~")
self.appPath = getattr(sys, "_MEIPASS", os.path.abspath(os.path.dirname(__file__)))
self.appRoot = os.path.abspath(os.path.join(self.appPath, os.path.pardir))
if os.path.isfile(self.appRoot):
# novelWriter is packaged as a single file, so the app and
# root paths are the same, and equal to the folder that
# contains the single executable.
self.appRoot = os.path.dirname(self.appRoot)
self.appPath = self.appRoot
# Assets
self.assetPath = os.path.join(self.appPath, "assets")
self.themeRoot = os.path.join(self.assetPath, "themes")
self.dictPath = os.path.join(self.assetPath, "dict")
self.iconPath = os.path.join(self.assetPath, "icons")
self.appIcon = os.path.join(self.iconPath, "novelwriter.svg")
logger.verbose("App path: %s" % self.appPath)
logger.verbose("Last path: %s" % self.lastPath)
# Internationalisation
self.nwLangPath = os.path.join(self.assetPath, "i18n")
logger.verbose("App path: %s", self.appPath)
logger.verbose("Last path: %s", self.lastPath)
# If config folder does not exist, create it.
# This assumes that the os config folder itself exists.
@@ -288,8 +319,8 @@ class Config:
try:
os.mkdir(self.confPath)
except Exception as e:
logger.error("Could not create folder: %s" % self.confPath)
logger.error(str(e))
logger.error("Could not create folder: %s", self.confPath)
logException()
self.hasError = True
self.errData.append("Could not create folder: %s" % self.confPath)
self.errData.append(str(e))
@@ -311,8 +342,8 @@ class Config:
try:
os.mkdir(self.dataPath)
except Exception as e:
logger.error("Could not create folder: %s" % self.dataPath)
logger.error(str(e))
logger.error("Could not create folder: %s", self.dataPath)
logException()
self.hasError = True
self.errData.append("Could not create folder: %s" % self.dataPath)
self.errData.append(str(e))
@@ -343,6 +374,57 @@ class Config:
return True
def initLocalisation(self, nwApp):
"""Initialise the localisation of the GUI.
"""
self.qLocal = QLocale(self.guiLang)
QLocale.setDefault(self.qLocal)
self.qtTrans = {}
langList = [
(self.qtLangPath, "qtbase"), # Qt 5.x
(self.nwLangPath, "qtbase"), # Alternative Qt 5.x
(self.nwLangPath, "nw"), # novelWriter
]
for lngPath, lngBase in langList:
for lngCode in self.qLocal.uiLanguages():
qTrans = QTranslator()
lngFile = "%s_%s" % (lngBase, lngCode.replace("-", "_"))
if lngFile not in self.qtTrans:
if qTrans.load(lngFile, lngPath):
logger.debug("Loaded: %s", os.path.join(lngPath, lngFile))
nwApp.installTranslator(qTrans)
self.qtTrans[lngFile] = qTrans
return
def listLanguages(self, lngSet):
"""List localisation files in the i18n folder. The default GUI
language 'en_GB' is British English.
"""
if lngSet == self.LANG_NW:
fPre = "nw_"
fExt = ".qm"
langList = {"en_GB": QLocale("en_GB").nativeLanguageName().title()}
elif lngSet == self.LANG_PROJ:
fPre = "project_"
fExt = ".json"
langList = {"en": "English"}
else:
return []
for qmFile in os.listdir(self.nwLangPath):
if not os.path.isfile(os.path.join(self.nwLangPath, qmFile)):
continue
if not qmFile.startswith(fPre) or not qmFile.endswith(fExt):
continue
qmLang = qmFile[len(fPre):-len(fExt)]
qmName = QLocale(qmLang).nativeLanguageName().title()
if qmLang and qmName and qmLang != "en":
langList[qmLang] = qmName
return sorted(langList.items(), key=lambda x: x[0])
def loadConfig(self):
"""Load preferences from file and replace default settings.
"""
@@ -351,19 +433,19 @@ class Config:
return False
cnfParse = configparser.ConfigParser()
cnfPath = os.path.join(self.confPath, self.confFile)
cnfPath = os.path.join(self.confPath, self.confFile)
try:
with open(cnfPath, mode="r", encoding="utf8") as inFile:
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
cnfParse.read_file(inFile)
except Exception as e:
logger.error("Could not load config file")
logger.error(str(e))
logException()
self.hasError = True
self.errData.append("Could not load config file")
self.errData.append(str(e))
return False
## Main
# Main
cnfSec = "Main"
self.guiTheme = self._parseLine(
cnfParse, cnfSec, "theme", self.CNF_STR, self.guiTheme
@@ -386,15 +468,24 @@ class Config:
self.lastNotes = self._parseLine(
cnfParse, cnfSec, "lastnotes", self.CNF_STR, self.lastNotes
)
self.guiLang = self._parseLine(
cnfParse, cnfSec, "guilang", self.CNF_STR, self.guiLang
)
## Sizes
# Sizes
cnfSec = "Sizes"
self.winGeometry = self._parseLine(
cnfParse, cnfSec, "geometry", self.CNF_I_LST, self.winGeometry
)
self.prefGeometry = self._parseLine(
cnfParse, cnfSec, "preferences", self.CNF_I_LST, self.prefGeometry
)
self.treeColWidth = self._parseLine(
cnfParse, cnfSec, "treecols", self.CNF_I_LST, self.treeColWidth
)
self.novelColWidth = self._parseLine(
cnfParse, cnfSec, "novelcols", self.CNF_I_LST, self.novelColWidth
)
self.projColWidth = self._parseLine(
cnfParse, cnfSec, "projcols", self.CNF_I_LST, self.projColWidth
)
@@ -420,7 +511,7 @@ class Config:
cnfParse, cnfSec, "hidehscroll", self.CNF_BOOL, self.hideHScroll
)
## Project
# Project
cnfSec = "Project"
self.autoSaveProj = self._parseLine(
cnfParse, cnfSec, "autosaveproject", self.CNF_INT, self.autoSaveProj
@@ -429,7 +520,7 @@ class Config:
cnfParse, cnfSec, "autosavedoc", self.CNF_INT, self.autoSaveDoc
)
## Editor
# Editor
cnfSec = "Editor"
self.textFont = self._parseLine(
cnfParse, cnfSec, "textfont", self.CNF_STR, self.textFont
@@ -491,6 +582,15 @@ class Config:
self.fmtDoubleQuotes = self._parseLine(
cnfParse, cnfSec, "fmtdoublequote", self.CNF_S_LST, self.fmtDoubleQuotes
)
self.fmtPadBefore = self._parseLine(
cnfParse, cnfSec, "fmtpadbefore", self.CNF_STR, self.fmtPadBefore
)
self.fmtPadAfter = self._parseLine(
cnfParse, cnfSec, "fmtpadafter", self.CNF_STR, self.fmtPadAfter
)
self.fmtPadThin = self._parseLine(
cnfParse, cnfSec, "fmtpadthin", self.CNF_BOOL, self.fmtPadThin
)
self.spellTool = self._parseLine(
cnfParse, cnfSec, "spelltool", self.CNF_STR, self.spellTool
)
@@ -503,6 +603,9 @@ class Config:
self.showLineEndings = self._parseLine(
cnfParse, cnfSec, "showlineendings", self.CNF_BOOL, self.showLineEndings
)
self.showMultiSpaces = self._parseLine(
cnfParse, cnfSec, "showmultispaces", self.CNF_BOOL, self.showMultiSpaces
)
self.bigDocLimit = self._parseLine(
cnfParse, cnfSec, "bigdoclimit", self.CNF_INT, self.bigDocLimit
)
@@ -512,11 +615,23 @@ class Config:
self.highlightQuotes = self._parseLine(
cnfParse, cnfSec, "highlightquotes", self.CNF_BOOL, self.highlightQuotes
)
self.allowOpenSQuote = self._parseLine(
cnfParse, cnfSec, "allowopensquote", self.CNF_BOOL, self.allowOpenSQuote
)
self.allowOpenDQuote = self._parseLine(
cnfParse, cnfSec, "allowopendquote", self.CNF_BOOL, self.allowOpenDQuote
)
self.highlightEmph = self._parseLine(
cnfParse, cnfSec, "highlightemph", self.CNF_BOOL, self.highlightEmph
)
self.stopWhenIdle = self._parseLine(
cnfParse, cnfSec, "stopwhenidle", self.CNF_BOOL, self.stopWhenIdle
)
self.userIdleTime = self._parseLine(
cnfParse, cnfSec, "useridletime", self.CNF_INT, self.userIdleTime
)
## Backup
# Backup
cnfSec = "Backup"
self.backupPath = self._parseLine(
cnfParse, cnfSec, "backuppath", self.CNF_STR, self.backupPath
@@ -528,7 +643,7 @@ class Config:
cnfParse, cnfSec, "askbeforebackup", self.CNF_BOOL, self.askBeforeBackup
)
## State
# State
cnfSec = "State"
self.showRefPanel = self._parseLine(
cnfParse, cnfSec, "showrefpanel", self.CNF_BOOL, self.showRefPanel
@@ -558,7 +673,7 @@ class Config:
cnfParse, cnfSec, "searchmatchcap", self.CNF_BOOL, self.searchMatchCap
)
## Path
# Path
cnfSec = "Path"
self.lastPath = self._parseLine(
cnfParse, cnfSec, "lastpath", self.CNF_STR, self.lastPath
@@ -567,6 +682,15 @@ class Config:
# Check Certain Values for None
self.spellLanguage = self._checkNone(self.spellLanguage)
# If we're using straight quotes, disable auto-replace
if self.fmtSingleQuotes == ["'", "'"] and self.doReplaceSQuote:
logger.info("Using straight single quotes, so disabling auto-replace")
self.doReplaceSQuote = False
if self.fmtDoubleQuotes == ["\"", "\""] and self.doReplaceDQuote:
logger.info("Using straight double quotes, so disabling auto-replace")
self.doReplaceDQuote = False
return True
def saveConfig(self):
@@ -580,7 +704,7 @@ class Config:
# Set options
## Main
# Main
cnfSec = "Main"
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec, "timestamp", formatTimeStamp(time()))
@@ -591,12 +715,15 @@ class Config:
cnfParse.set(cnfSec, "guifont", str(self.guiFont))
cnfParse.set(cnfSec, "guifontsize", str(self.guiFontSize))
cnfParse.set(cnfSec, "lastnotes", str(self.lastNotes))
cnfParse.set(cnfSec, "guilang", str(self.guiLang))
## Sizes
# Sizes
cnfSec = "Sizes"
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec, "geometry", self._packList(self.winGeometry))
cnfParse.set(cnfSec, "preferences", self._packList(self.prefGeometry))
cnfParse.set(cnfSec, "treecols", self._packList(self.treeColWidth))
cnfParse.set(cnfSec, "novelcols", self._packList(self.novelColWidth))
cnfParse.set(cnfSec, "projcols", self._packList(self.projColWidth))
cnfParse.set(cnfSec, "mainpane", self._packList(self.mainPanePos))
cnfParse.set(cnfSec, "docpane", self._packList(self.docPanePos))
@@ -606,13 +733,13 @@ class Config:
cnfParse.set(cnfSec, "hidevscroll", str(self.hideVScroll))
cnfParse.set(cnfSec, "hidehscroll", str(self.hideHScroll))
## Project
# Project
cnfSec = "Project"
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec, "autosaveproject", str(self.autoSaveProj))
cnfParse.set(cnfSec, "autosavedoc", str(self.autoSaveDoc))
## Editor
# Editor
cnfSec = "Editor"
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec, "textfont", str(self.textFont))
@@ -635,23 +762,31 @@ class Config:
cnfParse.set(cnfSec, "autoscrollpos", str(self.autoScrollPos))
cnfParse.set(cnfSec, "fmtsinglequote", self._packList(self.fmtSingleQuotes))
cnfParse.set(cnfSec, "fmtdoublequote", self._packList(self.fmtDoubleQuotes))
cnfParse.set(cnfSec, "fmtpadbefore", str(self.fmtPadBefore))
cnfParse.set(cnfSec, "fmtpadafter", str(self.fmtPadAfter))
cnfParse.set(cnfSec, "fmtpadthin", str(self.fmtPadThin))
cnfParse.set(cnfSec, "spelltool", str(self.spellTool))
cnfParse.set(cnfSec, "spellcheck", str(self.spellLanguage))
cnfParse.set(cnfSec, "showtabsnspaces", str(self.showTabsNSpaces))
cnfParse.set(cnfSec, "showlineendings", str(self.showLineEndings))
cnfParse.set(cnfSec, "showmultispaces", str(self.showMultiSpaces))
cnfParse.set(cnfSec, "bigdoclimit", str(self.bigDocLimit))
cnfParse.set(cnfSec, "showfullpath", str(self.showFullPath))
cnfParse.set(cnfSec, "highlightquotes", str(self.highlightQuotes))
cnfParse.set(cnfSec, "allowopensquote", str(self.allowOpenSQuote))
cnfParse.set(cnfSec, "allowopendquote", str(self.allowOpenDQuote))
cnfParse.set(cnfSec, "highlightemph", str(self.highlightEmph))
cnfParse.set(cnfSec, "stopwhenidle", str(self.stopWhenIdle))
cnfParse.set(cnfSec, "useridletime", str(self.userIdleTime))
## Backup
# Backup
cnfSec = "Backup"
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec, "backuppath", str(self.backupPath))
cnfParse.set(cnfSec, "backuponclose", str(self.backupOnClose))
cnfParse.set(cnfSec, "askbeforebackup", str(self.askBeforeBackup))
## State
# State
cnfSec = "State"
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec, "showrefpanel", str(self.showRefPanel))
@@ -664,7 +799,7 @@ class Config:
cnfParse.set(cnfSec, "searchnextfile", str(self.searchNextFile))
cnfParse.set(cnfSec, "searchmatchcap", str(self.searchMatchCap))
## Path
# Path
cnfSec = "Path"
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec, "lastpath", str(self.lastPath))
@@ -672,12 +807,12 @@ class Config:
# Write config file
cnfPath = os.path.join(self.confPath, self.confFile)
try:
with open(cnfPath, mode="w", encoding="utf8") as outFile:
with open(cnfPath, mode="w", encoding="utf-8") as outFile:
cnfParse.write(outFile)
self.confChanged = False
except Exception as e:
logger.error("Could not save config file")
logger.error(str(e))
logException()
self.hasError = True
self.errData.append("Could not save config file")
self.errData.append(str(e))
@@ -696,13 +831,13 @@ class Config:
if os.path.isfile(cacheFile):
try:
with open(cacheFile, mode="r", encoding="utf8") as inFile:
with open(cacheFile, mode="r", encoding="utf-8") as inFile:
theData = json.load(inFile)
for projPath in theData.keys():
theEntry = theData[projPath]
theTitle = ""
lastTime = 0
theEntry = theData[projPath]
theTitle = ""
lastTime = 0
wordCount = 0
if "title" in theEntry.keys():
theTitle = theEntry["title"]
@@ -711,9 +846,9 @@ class Config:
if "words" in theEntry.keys():
wordCount = int(theEntry["words"])
self.recentProj[projPath] = {
"title" : theTitle,
"time" : lastTime,
"words" : wordCount,
"title": theTitle,
"time": lastTime,
"words": wordCount,
}
except Exception as e:
@@ -734,7 +869,7 @@ class Config:
cacheTemp = os.path.join(self.dataPath, nwFiles.RECENT_FILE+"~")
try:
with open(cacheTemp, mode="w+", encoding="utf8") as outFile:
with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
json.dump(self.recentProj, outFile, indent=2)
except Exception as e:
self.hasError = True
@@ -752,9 +887,9 @@ class Config:
"""Add or update recent cache information o9n a given project.
"""
self.recentProj[os.path.abspath(projPath)] = {
"title" : projTitle,
"time" : int(saveTime),
"words" : int(wordCount),
"title": projTitle,
"time": int(saveTime),
"words": int(wordCount),
}
return True
@@ -763,10 +898,10 @@ class Config:
"""
if thePath in self.recentProj:
del self.recentProj[thePath]
logger.verbose("Removed recent: %s" % thePath)
logger.verbose("Removed recent: %s", thePath)
self.saveRecentCache()
else:
logger.error("Unknown recent: %s" % thePath)
logger.error("Unknown recent: %s", thePath)
return False
return True
@@ -811,11 +946,22 @@ class Config:
self.confChanged = True
return True
def setPreferencesSize(self, newWidth, newHeight):
self.prefGeometry[0] = int(newWidth/self.guiScale)
self.prefGeometry[1] = int(newHeight/self.guiScale)
self.confChanged = True
return True
def setTreeColWidths(self, colWidths):
self.treeColWidth = [int(x/self.guiScale) for x in colWidths]
self.confChanged = True
return True
def setNovelColWidths(self, colWidths):
self.novelColWidth = [int(x/self.guiScale) for x in colWidths]
self.confChanged = True
return True
def setProjColWidths(self, colWidths):
self.projColWidth = [int(x/self.guiScale) for x in colWidths]
self.confChanged = True
@@ -869,9 +1015,15 @@ class Config:
def getWinSize(self):
return [int(x*self.guiScale) for x in self.winGeometry]
def getPreferencesSize(self):
return [int(x*self.guiScale) for x in self.prefGeometry]
def getTreeColWidths(self):
return [int(x*self.guiScale) for x in self.treeColWidth]
def getNovelColWidths(self):
return [int(x*self.guiScale) for x in self.novelColWidth]
def getProjColWidths(self):
return [int(x*self.guiScale) for x in self.projColWidth]
@@ -945,9 +1097,9 @@ class Config:
return self._unpackList(
cnfParse.get(cnfSec, cnfName), cnfDefault, self.CNF_S_LST
)
except ValueError as e:
except ValueError:
logger.error("Failed to load value from config file.")
logger.error(str(e))
logException()
return cnfDefault
return cnfDefault
@@ -967,9 +1119,9 @@ class Config:
"""Cheks if we have the optional packages used by some features.
"""
try:
import enchant # noqa: F401
import enchant # noqa: F401
self.hasEnchant = True
logger.debug("Checking package 'pyenchant': Ok")
logger.debug("Checking package 'pyenchant': OK")
except Exception:
self.hasEnchant = False
logger.debug("Checking package 'pyenchant': Missing")
@@ -977,7 +1129,7 @@ class Config:
assistPath = shutil.which("assistant")
self.hasAssistant = assistPath is not None
if self.hasAssistant:
logger.debug("Checking executable 'assistant': Ok")
logger.debug("Checking executable 'assistant': OK")
else:
logger.debug("Checking executable 'assistant': Missing")

451
nw/constants.py Normal file
View File

@@ -0,0 +1,451 @@
"""
novelWriter – Constants
=======================
Constants and maps for translating flags and enums to text
File History:
Created: 2019-04-28 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
from nw.enum import nwItemClass, nwItemLayout, nwItemType, nwOutline
def trConst(tString):
"""Wrapper function for locally translating constants.
"""
return QCoreApplication.translate("Constant", tString)
class nwConst():
# Date and Time Formats
FMT_TSTAMP = "%Y-%m-%d %H:%M:%S" # Default format
FMT_FSTAMP = "%Y-%m-%d %H.%M.%S" # FileName safe format
FMT_DSTAMP = "%Y-%m-%d" # Date only format
# Various Hard Limits
MAX_DEPTH = 30 # Maximum folder depth of a project
MAX_DOCSIZE = 5000000 # Maxium size of a single document
MAX_BUILDSIZE = 10000000 # Maxium size of a project build
# Spell Check Providers
SP_INTERNAL = "internal"
SP_ENCHANT = "enchant"
# END Class nwConst
class nwLists():
"""Lists used for grouping various other constants.
"""
# Regular user-accessible item types
REG_TYPES = {nwItemType.ROOT, nwItemType.FOLDER, nwItemType.FILE}
# Item classes where the full list of novel layouts are allowed
CLS_NOVEL = {nwItemClass.NOVEL, nwItemClass.ARCHIVE}
# Item classes which do not require items to have same class
FREE_CLASS = {nwItemClass.ARCHIVE, nwItemClass.TRASH}
# END Class nwLists
class nwRegEx():
FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
# END Class nwRegEx
class nwFiles():
PROJ_FILE = "nwProject.nwx"
PROJ_DICT = "wordlist.txt"
PROJ_LOCK = "nwProject.lock"
TOC_TXT = "ToC.txt"
SESS_STATS = "sessionStats.log"
INDEX_FILE = "tagsIndex.json"
OPTS_FILE = "guiOptions.json"
RECENT_FILE = "recentProjects.json"
BUILD_CACHE = "prevBuild.json"
# END Class nwFiles
class nwKeyWords:
TAG_KEY = "@tag"
POV_KEY = "@pov"
FOCUS_KEY = "@focus"
CHAR_KEY = "@char"
PLOT_KEY = "@plot"
TIME_KEY = "@time"
WORLD_KEY = "@location"
OBJECT_KEY = "@object"
ENTITY_KEY = "@entity"
CUSTOM_KEY = "@custom"
# Set of Valid Keys
VALID_KEYS = {
TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY,
WORLD_KEY, OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY
}
# Map from Keys to Item Class
KEY_CLASS = {
POV_KEY: nwItemClass.CHARACTER,
FOCUS_KEY: nwItemClass.CHARACTER,
CHAR_KEY: nwItemClass.CHARACTER,
PLOT_KEY: nwItemClass.PLOT,
TIME_KEY: nwItemClass.TIMELINE,
WORLD_KEY: nwItemClass.WORLD,
OBJECT_KEY: nwItemClass.OBJECT,
ENTITY_KEY: nwItemClass.ENTITY,
CUSTOM_KEY: nwItemClass.CUSTOM,
}
# END Class nwKeyWords
class nwLabels():
CLASS_NAME = {
nwItemClass.NO_CLASS: QT_TRANSLATE_NOOP("Constant", "None"),
nwItemClass.NOVEL: QT_TRANSLATE_NOOP("Constant", "Novel"),
nwItemClass.PLOT: QT_TRANSLATE_NOOP("Constant", "Plot"),
nwItemClass.CHARACTER: QT_TRANSLATE_NOOP("Constant", "Characters"),
nwItemClass.WORLD: QT_TRANSLATE_NOOP("Constant", "Locations"),
nwItemClass.TIMELINE: QT_TRANSLATE_NOOP("Constant", "Timeline"),
nwItemClass.OBJECT: QT_TRANSLATE_NOOP("Constant", "Objects"),
nwItemClass.ENTITY: QT_TRANSLATE_NOOP("Constant", "Entity"),
nwItemClass.CUSTOM: QT_TRANSLATE_NOOP("Constant", "Custom"),
nwItemClass.ARCHIVE: QT_TRANSLATE_NOOP("Constant", "Outtakes"),
nwItemClass.TRASH: QT_TRANSLATE_NOOP("Constant", "Trash"),
}
CLASS_FLAG = {
nwItemClass.NO_CLASS: "0",
nwItemClass.NOVEL: "N",
nwItemClass.PLOT: "P",
nwItemClass.CHARACTER: "C",
nwItemClass.WORLD: "L",
nwItemClass.TIMELINE: "T",
nwItemClass.OBJECT: "O",
nwItemClass.ENTITY: "E",
nwItemClass.CUSTOM: "X",
nwItemClass.ARCHIVE: "U",
nwItemClass.TRASH: "R",
}
CLASS_ICON = {
nwItemClass.NO_CLASS: "cls_none",
nwItemClass.NOVEL: "cls_novel",
nwItemClass.PLOT: "cls_plot",
nwItemClass.CHARACTER: "cls_character",
nwItemClass.WORLD: "cls_world",
nwItemClass.TIMELINE: "cls_timeline",
nwItemClass.OBJECT: "cls_object",
nwItemClass.ENTITY: "cls_entity",
nwItemClass.CUSTOM: "cls_custom",
nwItemClass.ARCHIVE: "cls_archive",
nwItemClass.TRASH: "cls_trash",
}
LAYOUT_NAME = {
nwItemLayout.NO_LAYOUT: QT_TRANSLATE_NOOP("Constant", "None"),
nwItemLayout.TITLE: QT_TRANSLATE_NOOP("Constant", "Title Page"),
nwItemLayout.BOOK: QT_TRANSLATE_NOOP("Constant", "Book"),
nwItemLayout.PAGE: QT_TRANSLATE_NOOP("Constant", "Plain Page"),
nwItemLayout.PARTITION: QT_TRANSLATE_NOOP("Constant", "Partition"),
nwItemLayout.UNNUMBERED: QT_TRANSLATE_NOOP("Constant", "Unnumbered"),
nwItemLayout.CHAPTER: QT_TRANSLATE_NOOP("Constant", "Chapter"),
nwItemLayout.SCENE: QT_TRANSLATE_NOOP("Constant", "Scene"),
nwItemLayout.NOTE: QT_TRANSLATE_NOOP("Constant", "Note"),
}
LAYOUT_FLAG = {
nwItemLayout.NO_LAYOUT: "Xo",
nwItemLayout.TITLE: "Tt",
nwItemLayout.BOOK: "Bk",
nwItemLayout.PAGE: "Pg",
nwItemLayout.PARTITION: "Pt",
nwItemLayout.UNNUMBERED: "Un",
nwItemLayout.CHAPTER: "Ch",
nwItemLayout.SCENE: "Sc",
nwItemLayout.NOTE: "Nt",
}
KEY_NAME = {
nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
nwKeyWords.CHAR_KEY: QT_TRANSLATE_NOOP("Constant", "Characters"),
nwKeyWords.PLOT_KEY: QT_TRANSLATE_NOOP("Constant", "Plot"),
nwKeyWords.TIME_KEY: QT_TRANSLATE_NOOP("Constant", "Timeline"),
nwKeyWords.WORLD_KEY: QT_TRANSLATE_NOOP("Constant", "Locations"),
nwKeyWords.OBJECT_KEY: QT_TRANSLATE_NOOP("Constant", "Objects"),
nwKeyWords.ENTITY_KEY: QT_TRANSLATE_NOOP("Constant", "Entities"),
nwKeyWords.CUSTOM_KEY: QT_TRANSLATE_NOOP("Constant", "Custom"),
}
OUTLINE_COLS = {
nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"),
nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"),
nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"),
nwOutline.LINE: QT_TRANSLATE_NOOP("Constant", "Line"),
nwOutline.CCOUNT: QT_TRANSLATE_NOOP("Constant", "Chars"),
nwOutline.WCOUNT: QT_TRANSLATE_NOOP("Constant", "Words"),
nwOutline.PCOUNT: QT_TRANSLATE_NOOP("Constant", "Pars"),
nwOutline.POV: QT_TRANSLATE_NOOP("Constant", "POV"),
nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"),
nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY],
nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY],
nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY],
nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY],
nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY],
nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY],
nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY],
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
}
# END Class nwLabels
class nwQuotes():
"""Allowed quotation marks.
Source: https://en.wikipedia.org/wiki/Quotation_mark
"""
SYMBOLS = {
"\u0027": QT_TRANSLATE_NOOP("Constant", "Straight single quotation mark"),
"\u0022": QT_TRANSLATE_NOOP("Constant", "Straight double quotation mark"),
"\u2018": QT_TRANSLATE_NOOP("Constant", "Left single quotation mark"),
"\u2019": QT_TRANSLATE_NOOP("Constant", "Right single quotation mark"),
"\u201a": QT_TRANSLATE_NOOP("Constant", "Single low-9 quotation mark"),
"\u201b": QT_TRANSLATE_NOOP("Constant", "Single high-reversed-9 quotation mark"),
"\u201c": QT_TRANSLATE_NOOP("Constant", "Left double quotation mark"),
"\u201d": QT_TRANSLATE_NOOP("Constant", "Right double quotation mark"),
"\u201e": QT_TRANSLATE_NOOP("Constant", "Double low-9 quotation mark"),
"\u201f": QT_TRANSLATE_NOOP("Constant", "Double high-reversed-9 quotation mark"),
"\u2e42": QT_TRANSLATE_NOOP("Constant", "Double low-reversed-9 quotation mark"),
"\u2039": QT_TRANSLATE_NOOP("Constant", "Single left-pointing angle quotation mark"),
"\u203a": QT_TRANSLATE_NOOP("Constant", "Single right-pointing angle quotation mark"),
"\u00ab": QT_TRANSLATE_NOOP("Constant", "Double left-pointing angle quotation mark"),
"\u00bb": QT_TRANSLATE_NOOP("Constant", "Double right-pointing angle quotation mark"),
"\u300c": QT_TRANSLATE_NOOP("Constant", "Left corner bracket"),
"\u300d": QT_TRANSLATE_NOOP("Constant", "Right corner bracket"),
"\u300e": QT_TRANSLATE_NOOP("Constant", "Left white corner bracket"),
"\u300f": QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"),
}
# END Class nwQuotes
class nwUnicode:
"""Supported unicode character constants and their HTML equivalents.
"""
# Unicode Constants
# =================
# Quotation Marks
U_QUOT = "\u0022" # Quotation mark
U_APOS = "\u0027" # Apostrophe
U_LAQUO = "\u00ab" # Left-pointing double angle quotation mark
U_RAQUO = "\u00bb" # Right-pointing double angle quotation mark
U_LSQUO = "\u2018" # Left single quotation mark
U_RSQUO = "\u2019" # Right single quotation mark
U_SBQUO = "\u201a" # Single low-9 quotation mark
U_SUQUO = "\u201b" # Single high-reversed-9 quotation mark
U_LDQUO = "\u201c" # Left double quotation mark
U_RDQUO = "\u201d" # Right double quotation mark
U_BDQUO = "\u201e" # Double low-9 quotation mark
U_UDQUO = "\u201f" # Double high-reversed-9 quotation mark
U_LSAQUO = "\u2039" # Single left-pointing angle quotation mark
U_RSAQUO = "\u203a" # Single right-pointing angle quotation mark
U_BDRQUO = "\u2e42" # Double low-reversed-9 quotation mark
U_LCQUO = "\u300c" # Left corner bracket
U_RCQUO = "\u300d" # Right corner bracket
U_LWCQUO = "\u300e" # Left white corner bracket
U_RWCQUO = "\u300f" # Right white corner bracket
# Punctuation
U_FGDASH = "\u2012" # Figure dash
U_ENDASH = "\u2013" # Short dash
U_EMDASH = "\u2014" # Long dash
U_HBAR = "\u2015" # Horizontal bar
U_HELLIP = "\u2026" # Ellipsis
U_MAPOSS = "\u02bc" # Modifier letter single apostrophe
U_PRIME = "\u2032" # Prime
U_DPRIME = "\u2033" # Double prime
# Spaces and Lines
U_NBSP = "\u00a0" # Non-breaking space
U_THSP = "\u2009" # Thin space
U_THNBSP = "\u202f" # Thin non-breaking space
U_ENSP = "\u2002" # Short (en) space
U_EMSP = "\u2003" # Long (em) space
U_LSEP = "\u2028" # Line separator
U_PSEP = "\u2029" # Paragraph separator
# Symbols
U_CHECK = "\u2714" # Heavy check mark
U_CROSS = "\u2715" # Heavy cross mark
U_BULL = "\u2022" # List bullet
U_TRBULL = "\u2023" # Triangle bullet
U_HYBULL = "\u2043" # Hyphen bullet
U_FLOWER = "\u2055" # Flower punctuation mark
U_PERMIL = "\u2030" # Per mille sign
U_DEGREE = "\u00b0" # Degree symbol
U_MINUS = "\u2212" # Minus sign
U_TIMES = "\u00d7" # Multiplaction sign
U_DIVIDE = "\u00f7" # Division sign
# Arrows
U_UTRI = "\u25b2" # Up-pointing triangle
U_UTRIS = "\u25b4" # Up-pointing triangle, small
U_RTRI = "\u25b6" # Right-pointing triangle
U_RTRIS = "\u25b8" # Right-pointing triangle, small
U_DTRI = "\u25bc" # Down-pointing triangle
U_DTRIS = "\u25be" # Down-pointing triangle, small
U_LTRI = "\u25c0" # Left-pointing triangle
U_LTRIS = "\u25c2" # Left-pointing triangle, small
# HTML Equivalents
# ================
# Quotes
H_QUOT = "&quot;"
H_APOS = "&#39;"
H_LAQUO = "&laquo;"
H_RAQUO = "&raquo;"
H_LSQUO = "&lsquo;"
H_RSQUO = "&rsquo;"
H_SBQUO = "&sbquo;"
H_SUQUO = "&#8219;"
H_LDQUO = "&ldquo;"
H_RDQUO = "&rdquo;"
H_BDQUO = "&bdquo;"
H_UDQUO = "&#8223;"
H_LSAQUO = "&lsaquo;"
H_RSAQUO = "&rsaquo;"
H_BDRQUO = "&#11842;"
H_LCQUO = "&#12300;"
H_RCQUO = "&#12301;"
H_LWCQUO = "&#12302;"
H_RWCQUO = "&#12303;"
# Punctuation
H_FGDASH = "&#8210;"
H_ENDASH = "&ndash;"
H_EMDASH = "&mdash;"
H_HBAR = "&#8213;"
H_HELLIP = "&hellip;"
H_MAPOSS = "&#700;"
H_PRIME = "&prime;"
H_DPRIME = "&#8243;"
# Spaces
H_NBSP = "&nbsp;"
H_THSP = "&thinsp;"
H_THNBSP = "&#8239;"
H_ENSP = "&ensp;"
H_EMSP = "&emsp;"
# Symbols
H_CHECK = "&#10004;"
H_CROSS = "&#10005;"
H_BULL = "&bull;"
H_TRBULL = "&#8227;"
H_HYBULL = "&hybull;"
H_FLOWER = "&#8277;"
H_PERMIL = "&#8240;"
H_DEGREE = "&deg;"
H_MINUS = "&minus;"
H_TIMES = "&times;"
H_DIVIDE = "&divide;"
# Arrows
H_UTRI = "&#9650;"
H_UTRIS = "&#9652;"
H_RTRI = "&#9654;"
H_RTRIS = "&#9656;"
H_DTRI = "&#9660;"
H_DTRIS = "&#9662;"
H_LTRI = "&#9664;"
H_LTRIS = "&#9666;"
# END Class nwUnicode
class nwHtmlUnicode():
U_TO_H = {
# Quotes
nwUnicode.U_QUOT: nwUnicode.H_QUOT,
nwUnicode.U_APOS: nwUnicode.H_APOS,
nwUnicode.U_LAQUO: nwUnicode.H_LAQUO,
nwUnicode.U_RAQUO: nwUnicode.H_RAQUO,
nwUnicode.U_LSQUO: nwUnicode.H_LSQUO,
nwUnicode.U_RSQUO: nwUnicode.H_RSQUO,
nwUnicode.U_SBQUO: nwUnicode.H_SBQUO,
nwUnicode.U_SUQUO: nwUnicode.H_SUQUO,
nwUnicode.U_LDQUO: nwUnicode.H_LDQUO,
nwUnicode.U_RDQUO: nwUnicode.H_RDQUO,
nwUnicode.U_BDQUO: nwUnicode.H_BDQUO,
nwUnicode.U_UDQUO: nwUnicode.H_UDQUO,
nwUnicode.U_LSAQUO: nwUnicode.H_LSAQUO,
nwUnicode.U_RSAQUO: nwUnicode.H_RSAQUO,
nwUnicode.U_BDRQUO: nwUnicode.H_BDRQUO,
nwUnicode.U_LCQUO: nwUnicode.H_LCQUO,
nwUnicode.U_RCQUO: nwUnicode.H_RCQUO,
nwUnicode.U_LWCQUO: nwUnicode.H_LWCQUO,
nwUnicode.U_RWCQUO: nwUnicode.H_RWCQUO,
# Punctuation
nwUnicode.U_FGDASH: nwUnicode.H_FGDASH,
nwUnicode.U_ENDASH: nwUnicode.H_ENDASH,
nwUnicode.U_EMDASH: nwUnicode.H_EMDASH,
nwUnicode.U_HBAR: nwUnicode.H_HBAR,
nwUnicode.U_HELLIP: nwUnicode.H_HELLIP,
nwUnicode.U_MAPOSS: nwUnicode.H_MAPOSS,
nwUnicode.U_PRIME: nwUnicode.H_PRIME,
nwUnicode.U_DPRIME: nwUnicode.H_DPRIME,
# Spaces
nwUnicode.U_NBSP: nwUnicode.H_NBSP,
nwUnicode.U_THSP: nwUnicode.H_THSP,
nwUnicode.U_THNBSP: nwUnicode.H_THNBSP,
nwUnicode.U_ENSP: nwUnicode.H_ENSP,
nwUnicode.U_EMSP: nwUnicode.H_EMSP,
# Symbols
nwUnicode.U_CHECK: nwUnicode.H_CHECK,
nwUnicode.U_CROSS: nwUnicode.H_CROSS,
nwUnicode.U_BULL: nwUnicode.H_BULL,
nwUnicode.U_TRBULL: nwUnicode.H_TRBULL,
nwUnicode.U_HYBULL: nwUnicode.H_HYBULL,
nwUnicode.U_FLOWER: nwUnicode.H_FLOWER,
nwUnicode.U_PERMIL: nwUnicode.H_PERMIL,
nwUnicode.U_DEGREE: nwUnicode.H_DEGREE,
nwUnicode.U_MINUS: nwUnicode.H_MINUS,
nwUnicode.U_TIMES: nwUnicode.H_TIMES,
nwUnicode.U_DIVIDE: nwUnicode.H_DIVIDE,
}
# END Class nwHtmlUnicode

View File

@@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
from nw.constants.iso import isoLanguage, isoCountry
from nw.constants.constants import (
nwConst, nwRegEx, nwFiles, nwKeyWords, nwLabels, nwQuotes, nwUnicode
)
from nw.constants.enum import (
nwAlert, nwDocAction, nwItemClass, nwItemLayout, nwItemType, nwOutline,
nwDocInsert
)
__all__ = [
"isoCountry",
"isoLanguage",
"nwAlert",
"nwConst",
"nwDocAction",
"nwDocInsert",
"nwFiles",
"nwItemClass",
"nwItemLayout",
"nwItemType",
"nwKeyWords",
"nwLabels",
"nwOutline",
"nwQuotes",
"nwRegEx",
"nwUnicode",
]

View File

@@ -1,340 +0,0 @@
# -*- coding: utf-8 -*-
"""novelWriter Constants
novelWriter – Constants
=========================
Constants for translating flags and enums to text
File History:
Created: 2019-04-28 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from nw.constants.enum import (
nwItemClass, nwItemLayout, nwItemType, nwOutline
)
class nwConst():
# Date and Time Formats
FMT_TSTAMP = "%Y-%m-%d %H:%M:%S" # Default format
FMT_FSTAMP = "%Y-%m-%d %H.%M.%S" # FileName safe format
FMT_DSTAMP = "%Y-%m-%d" # Date only format
# Various Hard Limits
MAX_DEPTH = 30 # Maximum folder depth of a project
MAX_DOCSIZE = 5000000 # Maxium size of a single document
MAX_BUILDSIZE = 10000000 # Maxium size of a project build
# Spell Check Providers
SP_INTERNAL = "internal"
SP_ENCHANT = "enchant"
# Check Lists
REG_TYPES = {nwItemType.ROOT, nwItemType.FOLDER, nwItemType.FILE}
# END Class nwConst
class nwRegEx():
FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
# END Class nwRegEx
class nwFiles():
PROJ_FILE = "nwProject.nwx"
PROJ_DICT = "wordlist.txt"
PROJ_LOCK = "nwProject.lock"
TOC_TXT = "ToC.txt"
SESS_STATS = "sessionStats.log"
INDEX_FILE = "tagsIndex.json"
OPTS_FILE = "guiOptions.json"
RECENT_FILE = "recentProjects.json"
BUILD_CACHE = "prevBuild.json"
# END Class nwFiles
class nwKeyWords:
TAG_KEY = "@tag"
POV_KEY = "@pov"
CHAR_KEY = "@char"
PLOT_KEY = "@plot"
TIME_KEY = "@time"
WORLD_KEY = "@location"
OBJECT_KEY = "@object"
ENTITY_KEY = "@entity"
CUSTOM_KEY = "@custom"
# Set of Valid Keys
VALID_KEYS = {
TAG_KEY, POV_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY,
WORLD_KEY, OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY
}
# Map from Keys to Item Class
KEY_CLASS = {
CHAR_KEY : nwItemClass.CHARACTER,
POV_KEY : nwItemClass.CHARACTER,
PLOT_KEY : nwItemClass.PLOT,
TIME_KEY : nwItemClass.TIMELINE,
WORLD_KEY : nwItemClass.WORLD,
OBJECT_KEY : nwItemClass.OBJECT,
ENTITY_KEY : nwItemClass.ENTITY,
CUSTOM_KEY : nwItemClass.CUSTOM,
}
# END Class nwKeyWords
class nwLabels():
CLASS_NAME = {
nwItemClass.NO_CLASS : "None",
nwItemClass.NOVEL : "Novel",
nwItemClass.PLOT : "Plot",
nwItemClass.CHARACTER : "Characters",
nwItemClass.WORLD : "Locations",
nwItemClass.TIMELINE : "Timeline",
nwItemClass.OBJECT : "Objects",
nwItemClass.ENTITY : "Entity",
nwItemClass.CUSTOM : "Custom",
nwItemClass.ARCHIVE : "Outtakes",
nwItemClass.TRASH : "Trash",
}
CLASS_FLAG = {
nwItemClass.NO_CLASS : "0",
nwItemClass.NOVEL : "N",
nwItemClass.PLOT : "P",
nwItemClass.CHARACTER : "C",
nwItemClass.WORLD : "L",
nwItemClass.TIMELINE : "T",
nwItemClass.OBJECT : "O",
nwItemClass.ENTITY : "E",
nwItemClass.CUSTOM : "X",
nwItemClass.ARCHIVE : "U",
nwItemClass.TRASH : "R",
}
CLASS_ICON = {
nwItemClass.NO_CLASS : "cls_none",
nwItemClass.NOVEL : "cls_novel",
nwItemClass.PLOT : "cls_plot",
nwItemClass.CHARACTER : "cls_character",
nwItemClass.WORLD : "cls_world",
nwItemClass.TIMELINE : "cls_timeline",
nwItemClass.OBJECT : "cls_object",
nwItemClass.ENTITY : "cls_entity",
nwItemClass.CUSTOM : "cls_custom",
nwItemClass.ARCHIVE : "cls_archive",
nwItemClass.TRASH : "cls_trash",
}
LAYOUT_NAME = {
nwItemLayout.NO_LAYOUT : "None",
nwItemLayout.TITLE : "Title Page",
nwItemLayout.BOOK : "Book",
nwItemLayout.PAGE : "Plain Page",
nwItemLayout.PARTITION : "Partition",
nwItemLayout.UNNUMBERED : "Unnumbered",
nwItemLayout.CHAPTER : "Chapter",
nwItemLayout.SCENE : "Scene",
nwItemLayout.NOTE : "Note",
}
LAYOUT_FLAG = {
nwItemLayout.NO_LAYOUT : "Xo",
nwItemLayout.TITLE : "Tt",
nwItemLayout.BOOK : "Bk",
nwItemLayout.PAGE : "Pg",
nwItemLayout.PARTITION : "Pt",
nwItemLayout.UNNUMBERED : "Un",
nwItemLayout.CHAPTER : "Ch",
nwItemLayout.SCENE : "Sc",
nwItemLayout.NOTE : "Nt",
}
KEY_NAME = {
nwKeyWords.TAG_KEY : "Tag",
nwKeyWords.POV_KEY : "Point of View",
nwKeyWords.CHAR_KEY : "Characters",
nwKeyWords.PLOT_KEY : "Plot",
nwKeyWords.TIME_KEY : "Timeline",
nwKeyWords.WORLD_KEY : "Locations",
nwKeyWords.OBJECT_KEY : "Objects",
nwKeyWords.ENTITY_KEY : "Entities",
nwKeyWords.CUSTOM_KEY : "Custom",
}
OUTLINE_COLS = {
nwOutline.TITLE : "Title",
nwOutline.LEVEL : "Level",
nwOutline.LABEL : "Document",
nwOutline.LINE : "Line",
nwOutline.CCOUNT : "Chars",
nwOutline.WCOUNT : "Words",
nwOutline.PCOUNT : "Pars",
nwOutline.POV : "POV",
nwOutline.CHAR : KEY_NAME[nwKeyWords.CHAR_KEY],
nwOutline.PLOT : KEY_NAME[nwKeyWords.PLOT_KEY],
nwOutline.TIME : KEY_NAME[nwKeyWords.TIME_KEY],
nwOutline.WORLD : KEY_NAME[nwKeyWords.WORLD_KEY],
nwOutline.OBJECT : KEY_NAME[nwKeyWords.OBJECT_KEY],
nwOutline.ENTITY : KEY_NAME[nwKeyWords.ENTITY_KEY],
nwOutline.CUSTOM : KEY_NAME[nwKeyWords.CUSTOM_KEY],
nwOutline.SYNOP : "Synopsis",
}
# END Class nwLabels
class nwQuotes():
"""Allowed quotation marks.
Source: https://en.wikipedia.org/wiki/Quotation_mark
"""
SYMBOLS = {
"\u0027" : "Straight single quotation mark",
"\u0022" : "Straight double quotation mark",
"\u2018" : "Left single quotation mark",
"\u2019" : "Right single quotation mark",
"\u201a" : "Single low-9 quotation mark",
"\u201b" : "Single high-reversed-9 quotation mark",
"\u201c" : "Left double quotation mark",
"\u201d" : "Right double quotation mark",
"\u201e" : "Double low-9 quotation mark",
"\u201f" : "Double high-reversed-9 quotation mark",
"\u2e42" : "Double low-reversed-9 quotation mark",
"\u2039" : "Single left-pointing angle quotation mark",
"\u203a" : "Single right-pointing angle quotation mark",
"\u00ab" : "Left-pointing double angle quotation mark",
"\u00bb" : "Right-pointing double angle quotation mark",
"\u300c" : "Left corner bracket",
"\u300d" : "Right corner bracket",
"\u300e" : "Left white corner bracket",
"\u300f" : "Right white corner bracket",
}
# END Class nwQuotes
class nwUnicode:
"""Supported unicode character constants and translation maps for HTML.
"""
# Unicode Constants
# =================
## Quotation Marks
U_QUOT = "\u0022" # Quotation mark
U_APOS = "\u0027" # Apostrophe
U_LAQUO = "\u00ab" # Left-pointing double angle quotation mark
U_RAQUO = "\u00bb" # Right-pointing double angle quotation mark
U_LSQUO = "\u2018" # Left single quotation mark
U_RSQUO = "\u2019" # Right single quotation mark
U_SBQUO = "\u201a" # Single low-9 quotation mark
U_SUQUO = "\u201b" # Single high-reversed-9 quotation mark
U_LDQUO = "\u201c" # Left double quotation mark
U_RDQUO = "\u201d" # Right double quotation mark
U_BDQUO = "\u201e" # Double low-9 quotation mark
U_UDQUO = "\u201f" # Double high-reversed-9 quotation mark
U_LSAQUO = "\u2039" # Single left-pointing angle quotation mark
U_RSAQUO = "\u203a" # Single right-pointing angle quotation mark
U_BDRQUO = "\u2e42" # Double low-reversed-9 quotation mark
U_LCQUO = "\u300c" # Left corner bracket
U_RCQUO = "\u300d" # Right corner bracket
U_LWCQUO = "\u300e" # Left white corner bracket
U_RECQUO = "\u300f" # Right white corner bracket
## Punctuation
U_ENDASH = "\u2013" # Short dash
U_EMDASH = "\u2014" # Long dash
U_HELLIP = "\u2026" # Ellipsis
U_MAPOSS = "\u02bc" # Modifier letter single apostrophe
## Spaces and Lines
U_NBSP = "\u00a0" # Non-breaking space
U_THNSP = "\u2009" # Thin space
U_THNBSP = "\u202f" # Thin non-breaking space
U_LSEP = "\u2028" # Line separator
U_PSEP = "\u2029" # Paragraph separator
## Symbols
U_CHECK = "\u2714" # Heavy check mark
U_MULT = "\u2715" # Multiplication x
U_BULL = "\u2022" # List bullet
## Arrows
U_UTRI = "\u25b2" # Up-pointing triangle
U_UTRIS = "\u25b4" # Up-pointing triangle, small
U_RTRI = "\u25b6" # Right-pointing triangle
U_RTRIS = "\u25b8" # Right-pointing triangle, small
U_DTRI = "\u25bc" # Down-pointing triangle
U_DTRIS = "\u25be" # Down-pointing triangle, small
U_LTRI = "\u25c0" # Left-pointing triangle
U_LTRIS = "\u25c2" # Left-pointing triangle, small
# HTML Equivalents
# ================
## Quotes
H_QUOT = "&quot;"
H_APOS = "&#39;"
H_LAQUO = "&laquo;"
H_RAQUO = "&raquo;"
H_LSQUO = "&lsquo;"
H_RSQUO = "&rsquo;"
H_SBQUO = "&sbquo;"
H_SUQUO = "&#8219;"
H_LDQUO = "&ldquo;"
H_RDQUO = "&rdquo;"
H_BDQUO = "&bdquo;"
H_UDQUO = "&#8223;"
H_LSAQUO = "&lsaquo;"
H_RSAQUO = "&rsaquo;"
H_BDRQUO = "&#11842;"
H_LCQUO = "&#12300;"
H_RCQUO = "&#12301;"
H_LWCQUO = "&#12302;"
H_LWCQUO = "&#12302;"
## Punctuation
H_ENDASH = "&ndash;"
H_EMDASH = "&mdash;"
H_HELLIP = "&hellip;"
H_MAPOSS = "&#700;"
## Spaces
H_NBSP = "&nbsp;"
H_THNSP = "&thinsp;"
H_THNBSP = "&#8239;"
## Symbols
H_CHECK = "&#10004;"
H_MULT = "&#10005;"
H_BULL = "&bull;"
## Arrows
H_UTRI = "&#9650;"
H_UTRIS = "&#9652;"
H_RTRI = "&#9654;"
H_RTRIS = "&#9656;"
H_DTRI = "&#9660;"
H_DTRIS = "&#9662;"
H_LTRI = "&#9664;"
H_LTRIS = "&#9666;"
# END Class nwUnicode

View File

@@ -1,147 +0,0 @@
# -*- coding: utf-8 -*-
"""novelWriter Enums
novelWriter – Enums
=====================
All enum values
File History:
Created: 2018-11-02 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from enum import Enum
class nwItemType(Enum):
NO_TYPE = 0
ROOT = 1
FOLDER = 2
FILE = 3
TRASH = 4
# END Enum nwItemType
class nwItemClass(Enum):
NO_CLASS = 0
NOVEL = 1
PLOT = 2
CHARACTER = 3
WORLD = 4
TIMELINE = 5
OBJECT = 6
ENTITY = 7
CUSTOM = 8
ARCHIVE = 9
TRASH = 10
# END Enum nwItemClass
class nwItemLayout(Enum):
NO_LAYOUT = 0
TITLE = 1
BOOK = 2
PAGE = 3
PARTITION = 4
UNNUMBERED = 5
CHAPTER = 6
SCENE = 7
NOTE = 8
# END Enum nwItemLayout
class nwDocAction(Enum):
NO_ACTION = 0
UNDO = 1
REDO = 2
CUT = 3
COPY = 4
PASTE = 5
EMPH = 6
STRONG = 7
STRIKE = 8
S_QUOTE = 9
D_QUOTE = 10
SEL_ALL = 11
SEL_PARA = 12
FIND = 13
REPLACE = 14
GO_NEXT = 15
GO_PREV = 16
REPL_NEXT = 17
BLOCK_H1 = 18
BLOCK_H2 = 19
BLOCK_H3 = 20
BLOCK_H4 = 21
BLOCK_COM = 22
BLOCK_TXT = 23
REPL_SNG = 24
REPL_DBL = 25
# END Enum nwDocAction
class nwDocInsert(Enum):
NO_INSERT = 0
HARD_BREAK = 1
NB_SPACE = 2
THIN_SPACE = 3
THIN_NB_SPACE = 4
SHORT_DASH = 5
LONG_DASH = 6
ELLIPSIS = 7
QUOTE_LS = 8
QUOTE_RS = 9
QUOTE_LD = 10
QUOTE_RD = 11
MODAPOS_S = 12
# END Enum nwDocInsert
class nwAlert(Enum):
INFO = 0
WARN = 1
ERROR = 2
BUG = 3
# END Enum nwAlert
class nwOutline(Enum):
TITLE = 0
LEVEL = 1
LABEL = 2
LINE = 3
CCOUNT = 4
WCOUNT = 5
PCOUNT = 6
POV = 7
CHAR = 8
PLOT = 9
TIME = 10
WORLD = 11
OBJECT = 12
ENTITY = 13
CUSTOM = 14
SYNOP = 15
# END Enum nwOutline

View File

@@ -1,473 +0,0 @@
# -*- coding: utf-8 -*-
"""novelWriter ISO Codes
novelWriter – ISO Codes
=========================
Handles translating language codes to language names
File History:
Created: 2019-11-05 [0.4.0]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
class isoLanguage():
ISO_639_1 = {
"aa" : "Afar",
"ab" : "Abkhazian",
"ae" : "Avestan",
"af" : "Afrikaans",
"ak" : "Akan",
"am" : "Amharic",
"an" : "Aragonese",
"ar" : "Arabic",
"as" : "Assamese",
"av" : "Avaric",
"ay" : "Aymara",
"az" : "Azerbaijani",
"ba" : "Bashkir",
"be" : "Belarusian",
"bg" : "Bulgarian",
"bh" : "Bihari languages",
"bi" : "Bislama",
"bm" : "Bambara",
"bn" : "Bengali",
"bo" : "Tibetan",
"br" : "Breton",
"bs" : "Bosnian",
"ca" : "Catalan",
"ce" : "Chechen",
"ch" : "Chamorro",
"co" : "Corsican",
"cr" : "Cree",
"cs" : "Czech",
"cu" : "Church Slavic",
"cv" : "Chuvash",
"cy" : "Welsh",
"da" : "Danish",
"de" : "German",
"dv" : "Divehi",
"dz" : "Dzongkha",
"ee" : "Ewe",
"el" : "Modern Greek",
"en" : "English",
"eo" : "Esperanto",
"es" : "Spanish",
"et" : "Estonian",
"eu" : "Basque",
"fa" : "Persian",
"ff" : "Fulah",
"fi" : "Finnish",
"fj" : "Fijian",
"fo" : "Faroese",
"fr" : "French",
"fy" : "Western Frisian",
"ga" : "Irish",
"gd" : "Gaelic",
"gl" : "Galician",
"gn" : "Guarani",
"gu" : "Gujarati",
"gv" : "Manx",
"ha" : "Hausa",
"he" : "Hebrew",
"hi" : "Hindi",
"ho" : "Hiri Motu",
"hr" : "Croatian",
"ht" : "Haitian",
"hu" : "Hungarian",
"hy" : "Armenian",
"hz" : "Herero",
"ia" : "Interlingua",
"id" : "Indonesian",
"ie" : "Interlingue",
"ig" : "Igbo",
"ii" : "Sichuan Yi",
"ik" : "Inupiaq",
"io" : "Ido",
"is" : "Icelandic",
"it" : "Italian",
"iu" : "Inuktitut",
"ja" : "Japanese",
"jv" : "Javanese",
"ka" : "Georgian",
"kg" : "Kongo",
"ki" : "Kikuyu",
"kj" : "Kuanyama",
"kk" : "Kazakh",
"kl" : "Kalaallisut",
"km" : "Central Khmer",
"kn" : "Kannada",
"ko" : "Korean",
"kr" : "Kanuri",
"ks" : "Kashmiri",
"ku" : "Kurdish",
"kv" : "Komi",
"kw" : "Cornish",
"ky" : "Kirghiz",
"la" : "Latin",
"lb" : "Luxembourgish",
"lg" : "Ganda",
"li" : "Limburgan",
"ln" : "Lingala",
"lo" : "Lao",
"lt" : "Lithuanian",
"lu" : "Luba-Katanga",
"lv" : "Latvian",
"mg" : "Malagasy",
"mh" : "Marshallese",
"mi" : "Maori",
"mk" : "Macedonian",
"ml" : "Malayalam",
"mn" : "Mongolian",
"mr" : "Marathi",
"ms" : "Malay",
"mt" : "Maltese",
"my" : "Burmese",
"na" : "Nauru",
"nb" : "Norwegian Bokmål",
"nd" : "North Ndebele",
"ne" : "Nepali",
"ng" : "Ndonga",
"nl" : "Dutch",
"nn" : "Norwegian Nynorsk",
"no" : "Norwegian",
"nr" : "South Ndebele",
"nv" : "Navajo",
"ny" : "Chichewa",
"oc" : "Occitan",
"oj" : "Ojibwa",
"om" : "Oromo",
"or" : "Oriya",
"os" : "Ossetian",
"pa" : "Panjabi",
"pi" : "Pali",
"pl" : "Polish",
"ps" : "Pushto",
"pt" : "Portuguese",
"qu" : "Quechua",
"rm" : "Romansh",
"rn" : "Rundi",
"ro" : "Romanian",
"ru" : "Russian",
"rw" : "Kinyarwanda",
"sa" : "Sanskrit",
"sc" : "Sardinian",
"sd" : "Sindhi",
"se" : "Northern Sami",
"sg" : "Sango",
"si" : "Sinhala",
"sk" : "Slovak",
"sl" : "Slovenian",
"sm" : "Samoan",
"sn" : "Shona",
"so" : "Somali",
"sq" : "Albanian",
"sr" : "Serbian",
"ss" : "Swati",
"st" : "Southern Sotho",
"su" : "Sundanese",
"sv" : "Swedish",
"sw" : "Swahili",
"ta" : "Tamil",
"te" : "Telugu",
"tg" : "Tajik",
"th" : "Thai",
"ti" : "Tigrinya",
"tk" : "Turkmen",
"tl" : "Tagalog",
"tn" : "Tswana",
"to" : "Tonga",
"tr" : "Turkish",
"ts" : "Tsonga",
"tt" : "Tatar",
"tw" : "Twi",
"ty" : "Tahitian",
"ug" : "Uighur",
"uk" : "Ukrainian",
"ur" : "Urdu",
"uz" : "Uzbek",
"ve" : "Venda",
"vi" : "Vietnamese",
"vo" : "Volapük",
"wa" : "Walloon",
"wo" : "Wolof",
"xh" : "Xhosa",
"yi" : "Yiddish",
"yo" : "Yoruba",
"za" : "Zhuang",
"zh" : "Chinese",
"zu" : "Zulu",
}
# END Class isoLanguage
class isoCountry():
ISO_3166_1_alpha_2 = {
"AD" : "Andorra",
"AE" : "United Arab Emirates",
"AF" : "Afghanistan",
"AG" : "Antigua and Barbuda",
"AI" : "Anguilla",
"AL" : "Albania",
"AM" : "Armenia",
"AO" : "Angola",
"AQ" : "Antarctica",
"AR" : "Argentina",
"AS" : "American Samoa",
"AT" : "Austria",
"AU" : "Australia",
"AW" : "Aruba",
"AX" : "Åland Islands",
"AZ" : "Azerbaijan",
"BA" : "Bosnia and Herzegovina",
"BB" : "Barbados",
"BD" : "Bangladesh",
"BE" : "Belgium",
"BF" : "Burkina Faso",
"BG" : "Bulgaria",
"BH" : "Bahrain",
"BI" : "Burundi",
"BJ" : "Benin",
"BL" : "Saint Barthélemy",
"BM" : "Bermuda",
"BN" : "Brunei Darussalam",
"BO" : "Plurinational State of Bolivia",
"BQ" : "Sint Eustatius and Saba Bonaire",
"BR" : "Brazil",
"BS" : "Bahamas",
"BT" : "Bhutan",
"BV" : "Bouvet Island",
"BW" : "Botswana",
"BY" : "Belarus",
"BZ" : "Belize",
"CA" : "Canada",
"CC" : "Cocos (Keeling) Islands",
"CD" : "The Democratic Republic of the Congo",
"CF" : "Central African Republic",
"CG" : "Congo",
"CH" : "Switzerland",
"CI" : "Côte d'Ivoire",
"CK" : "Cook Islands",
"CL" : "Chile",
"CM" : "Cameroon",
"CN" : "China",
"CO" : "Colombia",
"CR" : "Costa Rica",
"CU" : "Cuba",
"CV" : "Cape Verde",
"CW" : "Curaçao",
"CX" : "Christmas Island",
"CY" : "Cyprus",
"CZ" : "Czech Republic",
"DE" : "Germany",
"DJ" : "Djibouti",
"DK" : "Denmark",
"DM" : "Dominica",
"DO" : "Dominican Republic",
"DZ" : "Algeria",
"EC" : "Ecuador",
"EE" : "Estonia",
"EG" : "Egypt",
"EH" : "Western Sahara",
"ER" : "Eritrea",
"ES" : "Spain",
"ET" : "Ethiopia",
"FI" : "Finland",
"FJ" : "Fiji",
"FK" : "Falkland Islands (Malvinas)",
"FM" : "Federated States of Micronesia",
"FO" : "Faroe Islands",
"FR" : "France",
"GA" : "Gabon",
"GB" : "United Kingdom",
"GD" : "Grenada",
"GE" : "Georgia",
"GF" : "French Guiana",
"GG" : "Guernsey",
"GH" : "Ghana",
"GI" : "Gibraltar",
"GL" : "Greenland",
"GM" : "Gambia",
"GN" : "Guinea",
"GP" : "Guadeloupe",
"GQ" : "Equatorial Guinea",
"GR" : "Greece",
"GS" : "South Georgia and the South Sandwich Islands",
"GT" : "Guatemala",
"GU" : "Guam",
"GW" : "Guinea-Bissau",
"GY" : "Guyana",
"HK" : "Hong Kong",
"HM" : "Heard Island and McDonald Islands",
"HN" : "Honduras",
"HR" : "Croatia",
"HT" : "Haiti",
"HU" : "Hungary",
"ID" : "Indonesia",
"IE" : "Ireland",
"IL" : "Israel",
"IM" : "Isle of Man",
"IN" : "India",
"IO" : "British Indian Ocean Territory",
"IQ" : "Iraq",
"IR" : "Islamic Republic of Iran",
"IS" : "Iceland",
"IT" : "Italy",
"JE" : "Jersey",
"JM" : "Jamaica",
"JO" : "Jordan",
"JP" : "Japan",
"KE" : "Kenya",
"KG" : "Kyrgyzstan",
"KH" : "Cambodia",
"KI" : "Kiribati",
"KM" : "Comoros",
"KN" : "Saint Kitts and Nevis",
"KP" : "Democratic People's Republic of Korea",
"KR" : "Republic of Korea",
"KW" : "Kuwait",
"KY" : "Cayman Islands",
"KZ" : "Kazakhstan",
"LA" : "Lao People's Democratic Republic",
"LB" : "Lebanon",
"LC" : "Saint Lucia",
"LI" : "Liechtenstein",
"LK" : "Sri Lanka",
"LR" : "Liberia",
"LS" : "Lesotho",
"LT" : "Lithuania",
"LU" : "Luxembourg",
"LV" : "Latvia",
"LY" : "Libya",
"MA" : "Morocco",
"MC" : "Monaco",
"MD" : "Republic of Moldova",
"ME" : "Montenegro",
"MF" : "Saint Martin (French part)",
"MG" : "Madagascar",
"MH" : "Marshall Islands",
"MK" : "The Former Yugoslav Republic of Macedonia",
"ML" : "Mali",
"MM" : "Myanmar",
"MN" : "Mongolia",
"MO" : "Macao",
"MP" : "Northern Mariana Islands",
"MQ" : "Martinique",
"MR" : "Mauritania",
"MS" : "Montserrat",
"MT" : "Malta",
"MU" : "Mauritius",
"MV" : "Maldives",
"MW" : "Malawi",
"MX" : "Mexico",
"MY" : "Malaysia",
"MZ" : "Mozambique",
"NA" : "Namibia",
"NC" : "New Caledonia",
"NE" : "Niger",
"NF" : "Norfolk Island",
"NG" : "Nigeria",
"NI" : "Nicaragua",
"NL" : "Netherlands",
"NO" : "Norway",
"NP" : "Nepal",
"NR" : "Nauru",
"NU" : "Niue",
"NZ" : "New Zealand",
"OM" : "Oman",
"PA" : "Panama",
"PE" : "Peru",
"PF" : "French Polynesia",
"PG" : "Papua New Guinea",
"PH" : "Philippines",
"PK" : "Pakistan",
"PL" : "Poland",
"PM" : "Saint Pierre and Miquelon",
"PN" : "Pitcairn",
"PR" : "Puerto Rico",
"PS" : "State of Palestine",
"PT" : "Portugal",
"PW" : "Palau",
"PY" : "Paraguay",
"QA" : "Qatar",
"RE" : "Réunion",
"RO" : "Romania",
"RS" : "Serbia",
"RU" : "Russian Federation",
"RW" : "Rwanda",
"SA" : "Saudi Arabia",
"SB" : "Solomon Islands",
"SC" : "Seychelles",
"SD" : "Sudan",
"SE" : "Sweden",
"SG" : "Singapore",
"SH" : "Saint Helena, Ascension and Tristan da Cunha",
"SI" : "Slovenia",
"SJ" : "Svalbard and Jan Mayen",
"SK" : "Slovakia",
"SL" : "Sierra Leone",
"SM" : "San Marino",
"SN" : "Senegal",
"SO" : "Somalia",
"SR" : "Suriname",
"SS" : "South Sudan",
"ST" : "Sao Tome and Principe",
"SV" : "El Salvador",
"SX" : "Sint Maarten",
"SY" : "Syrian Arab Republic",
"SZ" : "Swaziland",
"TC" : "Turks and Caicos Islands",
"TD" : "Chad",
"TF" : "French Southern Territories",
"TG" : "Togo",
"TH" : "Thailand",
"TJ" : "Tajikistan",
"TK" : "Tokelau",
"TL" : "Timor-Leste",
"TM" : "Turkmenistan",
"TN" : "Tunisia",
"TO" : "Tonga",
"TR" : "Turkey",
"TT" : "Trinidad and Tobago",
"TV" : "Tuvalu",
"TW" : "Taiwan, Province of China",
"TZ" : "United Republic of Tanzania",
"UA" : "Ukraine",
"UG" : "Uganda",
"UM" : "United States Minor Outlying Islands",
"US" : "United States",
"UY" : "Uruguay",
"UZ" : "Uzbekistan",
"VA" : "Holy See (Vatican City State)",
"VC" : "Saint Vincent and the Grenadines",
"VE" : "Bolivarian Republic of Venezuela",
"VG" : "British Virgin Islands",
"VI" : "U.S. Virgin Islands",
"VN" : "Viet Nam",
"VU" : "Vanuatu",
"WF" : "Wallis and Futuna",
"WS" : "Samoa",
"YE" : "Yemen",
"YT" : "Mayotte",
"ZA" : "South Africa",
"ZM" : "Zambia",
"ZW" : "Zimbabwe",
}
# END Class isoCountry

View File

@@ -1,16 +1,34 @@
# -*- coding: utf-8 -*-
"""
novelWriter – Core Init
=======================
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from nw.core.document import NWDoc
from nw.core.index import NWIndex
from nw.core.index import NWIndex, countWords
from nw.core.project import NWProject
from nw.core.spellcheck import NWSpellCheck, NWSpellEnchant, NWSpellSimple
from nw.core.tohtml import ToHtml
from nw.core.tools import countWords, numberToRoman, numberToWord
from nw.core.toodt import ToOdt
from nw.core.tomd import ToMarkdown
__all__ = [
"countWords",
"numberToRoman",
"numberToWord",
"NWDoc",
"NWIndex",
"NWProject",
@@ -18,4 +36,6 @@ __all__ = [
"NWSpellEnchant",
"NWSpellSimple",
"ToHtml",
"ToOdt",
"ToMarkdown",
]

View File

@@ -1,54 +1,55 @@
# -*- coding: utf-8 -*-
"""novelWriter Project Document
"""
novelWriter – Project Document
==============================
Data class for a single novelWriter document
novelWriter – Project Document
================================
Class holding a single novelWriter document
File History:
Created: 2018-09-29 [0.0.1]
File History:
Created: 2018-09-29 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
import os
from nw.constants import nwAlert
from nw.enum import nwItemLayout, nwItemClass
from nw.common import isHandle
from nw.constants import nwItemLayout, nwItemClass
logger = logging.getLogger(__name__)
class NWDoc():
def __init__(self, theProject, theParent):
def __init__(self, theProject, theHandle):
self.theProject = theProject
self.theParent = theParent
# Internal Variables
self._theItem = None # The currently open item
self._docHandle = None # The handle of the currently open item
self._fileLoc = None # The file location of the currently open item
self._docMeta = {} # The meta data of the currently open item
self._theItem = None # The currently open item
self._docHandle = None # The handle of the currently open item
self._fileLoc = None # The file location of the currently open item
self._docMeta = {} # The meta data of the currently open item
self._docError = "" # The latest encountered IO error
# Internal Mapping
self.makeAlert = self.theParent.makeAlert
if isHandle(theHandle):
self._docHandle = theHandle
if self._docHandle is not None:
self._theItem = self.theProject.projTree[theHandle]
return
@@ -56,39 +57,23 @@ class NWDoc():
# Class Methods
##
def clearDocument(self):
"""Clear the document contents.
"""
self._theItem = None
self._docHandle = None
self._fileLoc = None
self._docMeta = {}
return
def openDocument(self, tHandle, showStatus=True, isOrphan=False):
"""Open a document from handle, capturing potential file system
errors and parse meta data. If the document doesn't exist on
disk, return an empty string. If something went wrong, return
def readDocument(self, isOrphan=False):
"""Read a document from set handle, capturing potential file
system errors and parse meta data. If the document doesn't exist
on disk, return an empty string. If something went wrong, return
None.
"""
if not isHandle(tHandle):
self._docError = ""
if self._docHandle is None:
logger.error("No document handle set")
return None
# Always clear first, since the object will often be reused.
self.clearDocument()
self._docHandle = tHandle
if not isOrphan:
self._theItem = self.theProject.projTree[tHandle]
else:
self._theItem = None
if self._theItem is None and not isOrphan:
self.clearDocument()
logger.error("Unknown novelWriter document")
return None
docFile = self._docHandle+".nwd"
logger.debug("Opening document %s" % docFile)
logger.debug("Opening document: %s", docFile)
docPath = os.path.join(self.theProject.projContent, docFile)
self._fileLoc = docPath
@@ -97,7 +82,7 @@ class NWDoc():
self._docMeta = {}
if os.path.isfile(docPath):
try:
with open(docPath, mode="r", encoding="utf8") as inFile:
with open(docPath, mode="r", encoding="utf-8") as inFile:
# Check the first <= 10 lines for metadata
for i in range(10):
@@ -112,34 +97,30 @@ class NWDoc():
theText += inFile.read()
except Exception as e:
self.makeAlert(["Failed to open document file.", str(e)], nwAlert.ERROR)
# Note: Document must be cleared in case of an io error,
# or else the auto-save or save will try to overwrite it
# with an empty file. Return None to alert the caller.
self.clearDocument()
self._docError = str(e)
return None
else:
# The document file does not exist, so we assume it's a new
# document and initialise an empty text string.
logger.debug("The requested document does not exist.")
return ""
if showStatus and not isOrphan:
self.theParent.setStatus("Opened Document: %s" % self._theItem.itemName)
return theText
def saveDocument(self, docText):
"""Save the document. The file is saved via a temp file in case
def writeDocument(self, docText):
"""Write the document. The file is saved via a temp file in case
of save failure. Returns True if successful, False if not.
"""
self._docError = ""
if self._docHandle is None:
logger.error("No document handle set")
return False
self.theProject.ensureFolderStructure()
docFile = self._docHandle+".nwd"
logger.debug("Saving document %s" % docFile)
logger.debug("Saving document: %s", docFile)
docPath = os.path.join(self.theProject.projContent, docFile)
docTemp = os.path.join(self.theProject.projContent, docFile+"~")
@@ -155,11 +136,11 @@ class NWDoc():
)
try:
with open(docTemp, mode="w", encoding="utf8") as outFile:
with open(docTemp, mode="w", encoding="utf-8") as outFile:
outFile.write(docMeta)
outFile.write(docText)
except Exception as e:
self.makeAlert(["Could not save document.", str(e)], nwAlert.ERROR)
self._docError = str(e)
return False
# If we're here, the file was successfully saved, so we can
@@ -168,19 +149,18 @@ class NWDoc():
os.unlink(docPath)
os.rename(docTemp, docPath)
if self._theItem is not None:
self.theParent.setStatus("Saved Document: %s" % self._theItem.itemName)
return True
def deleteDocument(self, tHandle):
def deleteDocument(self):
"""Permanently delete a document source file and related files
from the project data folder.
"""
if not isHandle(tHandle):
self._docError = ""
if self._docHandle is None:
logger.error("No document handle set")
return False
docFile = tHandle+".nwd"
docFile = self._docHandle+".nwd"
chkList = []
chkList.append(os.path.join(self.theProject.projContent, docFile))
@@ -190,9 +170,9 @@ class NWDoc():
if os.path.isfile(chkFile):
try:
os.unlink(chkFile)
logger.debug("Deleted: %s" % chkFile)
logger.debug("Deleted: %s", chkFile)
except Exception as e:
self.makeAlert(["Could not delete document file.", str(e)], nwAlert.ERROR)
self._docError = str(e)
return False
return True
@@ -222,6 +202,11 @@ class NWDoc():
return theName, theParent, theClass, theLayout
def getError(self):
"""Return the last recorded exception.
"""
return self._docError
##
# Internal Functions
##
@@ -252,7 +237,7 @@ class NWDoc():
self._docMeta["layout"] = nwItemLayout[metaBits[1]]
else:
logger.debug("Ignoring meta data: '%s'" % metaLine.strip())
logger.debug("Ignoring meta data: '%s'", metaLine.strip())
return

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +1,38 @@
# -*- coding: utf-8 -*-
"""novelWriter Project Item Class
"""
novelWriter – Project Item Class
================================
Data class for a project tree item
novelWriter – Project Item Class
==================================
Class holding the data of a project tree item
File History:
Created: 2018-10-27 [0.0.1]
File History:
Created: 2018-10-27 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
from lxml import etree
from nw.common import checkInt, isHandle
from nw.constants import nwItemType, nwItemClass, nwItemLayout
from nw.enum import nwItemType, nwItemClass, nwItemLayout
from nw.common import checkInt, isHandle, isItemClass, isItemLayout, isItemType
logger = logging.getLogger(__name__)
class NWItem():
def __init__(self, theProject):
@@ -52,11 +51,11 @@ class NWItem():
self.isExported = True
# Document Meta Data
self.charCount = 0 # Current character count
self.wordCount = 0 # Current word count
self.paraCount = 0 # Current paragraph count
self.initCount = 0 # Initial word count
self.cursorPos = 0 # Last cursor position
self.charCount = 0 # Current character count
self.wordCount = 0 # Current word count
self.paraCount = 0 # Current paragraph count
self.initCount = 0 # Initial word count
self.cursorPos = 0 # Last cursor position
return
@@ -68,9 +67,9 @@ class NWItem():
"""Packs all the data in the class instance into an XML object.
"""
xPack = etree.SubElement(xParent, "item", attrib={
"handle" : str(self.itemHandle),
"order" : str(self.itemOrder),
"parent" : str(self.itemParent),
"handle": str(self.itemHandle),
"order": str(self.itemOrder),
"parent": str(self.itemParent),
})
self._subPack(xPack, "name", text=str(self.itemName))
self._subPack(xPack, "type", text=str(self.itemType.name))
@@ -107,7 +106,6 @@ class NWItem():
if "order" in xItem.attrib:
self.setOrder(xItem.attrib["order"])
retStatus = True
for xValue in xItem:
if xValue.tag == "name":
self.setName(xValue.text)
@@ -132,10 +130,12 @@ class NWItem():
elif xValue.tag == "cursorPos":
self.setCursorPos(xValue.text)
else:
logger.error("Unknown tag '%s'" % xValue.tag)
retStatus = False
# Sliently skip as we may otherwise cause orphaned
# items if an otherwise valid file is opened by a
# version of novelWriter that doesn't know the tag.
logger.error("Unknown tag '%s'", xValue.tag)
return retStatus
return True
@staticmethod
def _subPack(xParent, name, attrib=None, text=None, none=True):
@@ -202,10 +202,10 @@ class NWItem():
"""
if isinstance(theType, nwItemType):
self.itemType = theType
elif theType in nwItemType.__members__:
elif isItemType(theType):
self.itemType = nwItemType[theType]
else:
logger.error("Unrecognised item type '%s'" % theType)
logger.error("Unrecognised item type '%s'", theType)
self.itemType = nwItemType.NO_TYPE
return
@@ -215,10 +215,10 @@ class NWItem():
"""
if isinstance(theClass, nwItemClass):
self.itemClass = theClass
elif theClass in nwItemClass.__members__:
elif isItemClass(theClass):
self.itemClass = nwItemClass[theClass]
else:
logger.error("Unrecognised item class '%s'" % theClass)
logger.error("Unrecognised item class '%s'", theClass)
self.itemClass = nwItemClass.NO_CLASS
return
@@ -228,10 +228,10 @@ class NWItem():
"""
if isinstance(theLayout, nwItemLayout):
self.itemLayout = theLayout
elif theLayout in nwItemLayout.__members__:
elif isItemLayout(theLayout):
self.itemLayout = nwItemLayout[theLayout]
else:
logger.error("Unrecognised item layout '%s'" % theLayout)
logger.error("Unrecognised item layout '%s'", theLayout)
self.itemLayout = nwItemLayout.NO_LAYOUT
return
@@ -251,7 +251,7 @@ class NWItem():
if isinstance(expState, str):
self.isExpanded = (expState == str(True))
else:
self.isExpanded = (expState == True) # noqa: E712
self.isExpanded = (expState == True) # noqa: E712
return
def setExported(self, expState):
@@ -260,7 +260,7 @@ class NWItem():
if isinstance(expState, str):
self.isExported = (expState == str(True))
else:
self.isExported = (expState == True) # noqa: E712
self.isExported = (expState == True) # noqa: E712
return
##

View File

@@ -1,31 +1,30 @@
# -*- coding: utf-8 -*-
"""novelWriter Project Options Cache
"""
novelWriter – Project Options Cache
===================================
Data class for user-defined GUI project options
novelWriter – Project Options Cache
=====================================
Class wrapping the project options state
File History:
Created: 2019-10-21 [0.3.1]
Rewritten: 2020-02-19 [0.4.5]
File History:
Created: 2019-10-21 [0.3.1]
Rewritten: 2020-02-19 [0.4.5]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import nw
import logging
import json
import os
@@ -34,6 +33,7 @@ from nw.constants import nwFiles
logger = logging.getLogger(__name__)
class OptionState():
def __init__(self, theProject):
@@ -47,6 +47,7 @@ class OptionState():
"widthCol0",
"widthCol1",
"widthCol2",
"widthCol3",
"sortCol",
"sortOrder",
"incNovel",
@@ -54,6 +55,7 @@ class OptionState():
"hideZeros",
"hideNegative",
"groupByDay",
"showIdleTime",
"histMax",
},
"GuiDocSplit": {
@@ -71,12 +73,14 @@ class OptionState():
"excludeBody",
"textFont",
"textSize",
"lineHeight",
"noStyling",
"incSynopsis",
"incComments",
"incKeywords",
"incBodyText",
"replaceTabs",
"replaceUCode",
},
"GuiOutline": {
"headerOrder",
@@ -87,6 +91,24 @@ class OptionState():
"winWidth",
"winHeight",
"replaceColW",
"statusColW",
"importColW",
},
"GuiProjectDetails": {
"winWidth",
"winHeight",
"widthCol0",
"widthCol1",
"widthCol2",
"widthCol3",
"widthCol4",
"wordsPerPage",
"countFrom",
"clearDouble",
},
"GuiWordList": {
"winWidth",
"winHeight",
}
}
@@ -103,16 +125,16 @@ class OptionState():
return False
stateFile = os.path.join(self.theProject.projMeta, nwFiles.OPTS_FILE)
theState = {}
theState = {}
if os.path.isfile(stateFile):
logger.debug("Loading GUI options file")
try:
with open(stateFile, mode="r", encoding="utf8") as inFile:
with open(stateFile, mode="r", encoding="utf-8") as inFile:
theState = json.load(inFile)
except Exception as e:
except Exception:
logger.error("Failed to load GUI options file")
logger.error(str(e))
nw.logException()
return False
# Filter out unused variables
@@ -135,11 +157,11 @@ class OptionState():
logger.debug("Saving GUI options file")
try:
with open(stateFile, mode="w+", encoding="utf8") as outFile:
with open(stateFile, mode="w+", encoding="utf-8") as outFile:
json.dump(self.theState, outFile, indent=2)
except Exception as e:
except Exception:
logger.error("Failed to save GUI options file")
logger.error(str(e))
nw.logException()
return False
return True
@@ -152,11 +174,11 @@ class OptionState():
"""Saves a value, with a given group and name.
"""
if setGroup not in self.validMap:
logger.error("Unknown option group '%s'" % setGroup)
logger.error("Unknown option group '%s'", setGroup)
return False
if setName not in self.validMap[setGroup]:
logger.error("Unknown option name '%s'" % setName)
logger.error("Unknown option name '%s'", setName)
return False
if setGroup not in self.theState:

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,26 @@
# -*- coding: utf-8 -*-
"""novelWriter Spell Check Classes
"""
novelWriter – Spell Check Classes
=================================
Wrapper classes for spell checking tools
novelWriter – Spell Check Classes
===================================
Wrapper class for spell checking tools
File History:
Created: 2019-06-11 [0.1.5]
File History:
Created: 2019-06-11 [0.1.5]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import nw
@@ -30,10 +28,9 @@ import logging
import os
import difflib
from nw.constants import nwConst, isoLanguage
logger = logging.getLogger(__name__)
# =============================================================================================== #
# SpellChecking SuperClass
# =============================================================================================== #
@@ -50,17 +47,17 @@ class NWSpellCheck():
return
def setLanguage(self, theLang, projectDict=None):
"""Dummy function.
"""Default function.
"""
return
def checkWord(self, theWord):
"""Dummy function.
"""Default function.
"""
return True
def suggestWords(self, theWord):
"""Dummy function.
"""Default function.
"""
return []
@@ -73,33 +70,23 @@ class NWSpellCheck():
with open(self.projectDict, mode="a+", encoding="utf-8") as outFile:
outFile.write("%s\n" % newWord)
self.projDict.append(newWord)
except Exception as e:
logger.error("Failed to add word to project word list %s" % str(self.projectDict))
logger.error(str(e))
except Exception:
logger.error("Failed to add word to project word list %s", str(self.projectDict))
nw.logException()
return False
return True
return False
def listDictionaries(self):
"""Dummy function.
"""Default function.
"""
return []
def describeDict(self):
"""Dummy function.
"""Default function.
"""
return "", ""
@staticmethod
def expandLanguage(spTag):
"""Translate a language tag to something more user friendly.
"""
spBits = spTag.split("_")
spLang = isoLanguage.ISO_639_1.get(spBits[0], spBits[0])
if len(spBits) > 1:
spLang += " (%s)" % spBits[1]
return spLang
##
# Internal Functions
##
@@ -109,30 +96,33 @@ class NWSpellCheck():
lookup lists.
"""
self.projDict = []
if projectDict is not None:
if not os.path.isfile(projectDict):
self.projectDict = None
return False
else:
self.projectDict = projectDict
self.projectDict = projectDict
try:
logger.debug("Loading project word list")
with open(projectDict, mode="r", encoding="utf-8") as wordsFile:
for theLine in wordsFile:
theLine = theLine.strip()
if len(theLine) > 0 and theLine not in self.projDict:
self.projDict.append(theLine)
logger.debug("Project word list contains %d words" % len(self.projDict))
except Exception as e:
logger.error("Failed to load project word list")
logger.error(str(e))
return False
if projectDict is None:
return False
if not os.path.isfile(projectDict):
return False
try:
logger.debug("Loading project word list")
with open(projectDict, mode="r", encoding="utf-8") as wordsFile:
for theLine in wordsFile:
theLine = theLine.strip()
if len(theLine) > 0 and theLine not in self.projDict:
self.projDict.append(theLine)
logger.debug("Project word list contains %d words", len(self.projDict))
except Exception:
logger.error("Failed to load project word list")
nw.logException()
return False
return True
# END Class NWSpellCheck
# =============================================================================================== #
# Enchant Based SpellChecking
# =============================================================================================== #
@@ -142,21 +132,28 @@ class NWSpellEnchant(NWSpellCheck):
def __init__(self):
NWSpellCheck.__init__(self)
logger.debug("Enchant spell checking activated")
self.theBroker = None
return
def setLanguage(self, theLang, projectDict=None):
"""Load a dictionary for the language specified in the config.
If that fails, we load a dummy dictionary so that lookups don't
If that fails, we load a mock dictionary so that lookups don't
crash.
"""
try:
import enchant
self.theDict = enchant.Dict(theLang)
if self.theBroker is not None:
logger.verbose("Deleting old pyenchant broker")
del self.theBroker
self.theBroker = enchant.Broker()
self.theDict = self.theBroker.request_dict(theLang)
self.spellLanguage = theLang
logger.debug("Enchant spell checking for language %s loaded" % theLang)
logger.debug("Enchant spell checking for language '%s' loaded", theLang)
except Exception:
logger.error("Failed to load enchant spell checking for language %s" % theLang)
self.theDict = NWSpellEnchantDummy()
logger.error("Failed to load enchant spell checking for language '%s'", theLang)
self.theDict = FakeEnchant()
self.spellLanguage = None
self._readProjectDictionary(projectDict)
@@ -189,10 +186,10 @@ class NWSpellEnchant(NWSpellCheck):
try:
import enchant
for spTag, spProvider in enchant.list_dicts():
spName = "%s [%s]" % (self.expandLanguage(spTag), spProvider.name)
retList.append((spTag, spName))
retList.append((spTag, spProvider.name))
except Exception:
logger.error("Failed to list languages for enchant spell checking")
return retList
def describeDict(self):
@@ -202,9 +199,9 @@ class NWSpellEnchant(NWSpellCheck):
try:
spTag = self.theDict.tag
spName = self.theDict.provider.name
except Exception as e:
except Exception:
logger.error("Failed to extract information about the dictionary")
logger.error(str(e))
nw.logException()
spTag = ""
spName = ""
@@ -212,7 +209,8 @@ class NWSpellEnchant(NWSpellCheck):
# END Class NWSpellEnchant
class NWSpellEnchantDummy:
class FakeEnchant:
"""Fallback for when Enchant is selected, but not installed.
"""
def __init__(self):
@@ -227,7 +225,8 @@ class NWSpellEnchantDummy:
def add_to_session(self, theWord):
return
# END Class NWSpellEnchantDummy
# END Class FakeEnchant
# =============================================================================================== #
# Fallback SpellChecking Using difflib
@@ -236,10 +235,9 @@ class NWSpellEnchantDummy:
class NWSpellSimple(NWSpellCheck):
"""Internal spell check tool that uses standard Python packages with
no other external dependencies. This is the fallback spell checker
when no other is available. This method is fairly slow compared to
other implementations.
when no other is available. This method is slower than enchant.
"""
WORDS = []
theWords = set()
def __init__(self):
NWSpellCheck.__init__(self)
@@ -251,26 +249,27 @@ class NWSpellSimple(NWSpellCheck):
"""Load a dictionary as a list from the app assets folder.
"""
self.theLang = theLang
self.WORDS = []
self.theWords = set()
dictFile = os.path.join(self.mainConf.dictPath, theLang+".dict")
try:
with open(dictFile, mode="r", encoding="utf-8") as wordsFile:
for theLine in wordsFile:
if len(theLine) == 0 or theLine.startswith("#"):
continue
self.WORDS.append(theLine.strip().lower())
logger.debug("Spell check word list for language %s loaded" % theLang)
logger.debug("Word list contains %d words" % len(self.WORDS))
self.theWords.add(theLine.strip().lower())
logger.debug("Spell check dictionary for language '%s' loaded", theLang)
logger.debug("Dictionary contains %d words", len(self.theWords))
self.spellLanguage = theLang
except Exception as e:
logger.error("Failed to load spell check word list for language %s" % theLang)
logger.error(str(e))
except Exception:
logger.error("Failed to load spell check word list for language '%s'", theLang)
nw.logException()
self.spellLanguage = None
self._readProjectDictionary(projectDict)
for pWord in self.projDict:
if pWord not in self.WORDS:
self.WORDS.append(pWord)
self.theWords.add(pWord)
return
@@ -280,7 +279,7 @@ class NWSpellSimple(NWSpellCheck):
word by the syntax highlighter.
"""
theWord = theWord.replace(self.mainConf.fmtApostrophe, "'").lower()
return theWord in self.WORDS
return theWord in self.theWords
def suggestWords(self, theWord):
"""Get suggestions for correct word from difflib, and make sure
@@ -293,7 +292,7 @@ class NWSpellSimple(NWSpellCheck):
if len(theWord) == 0:
return []
theMatches = difflib.get_close_matches(theWord.lower(), self.WORDS, n=10, cutoff=0.75)
theMatches = difflib.get_close_matches(theWord.lower(), self.theWords, n=10, cutoff=0.75)
theOptions = []
for aWord in theMatches:
if len(aWord) == 0:
@@ -309,8 +308,8 @@ class NWSpellSimple(NWSpellCheck):
"""Wrapper for the internal project dictionary feature.
"""
newWord = newWord.strip().lower()
if newWord not in self.WORDS:
self.WORDS.append(newWord)
if newWord not in self.theWords:
self.theWords.add(newWord)
NWSpellCheck.addWord(self, newWord)
return
@@ -324,8 +323,7 @@ class NWSpellSimple(NWSpellCheck):
if fExt != ".dict":
continue
spName = "%s [%s]" % (self.expandLanguage(fRoot), nwConst.SP_INTERNAL)
retList.append((fRoot, spName))
retList.append((fRoot, "difflib"))
return retList
@@ -333,6 +331,6 @@ class NWSpellSimple(NWSpellCheck):
"""Return the tag and provider of the currently loaded
dictionary.
"""
return self.theLang, nwConst.SP_INTERNAL
return self.theLang, ""
# END Class NWSpellSimple

View File

@@ -1,28 +1,26 @@
# -*- coding: utf-8 -*-
"""novelWriter Project Item Status Class
"""
novelWriter – Project Item Status Class
=======================================
Data class for the status/importance settings of a project item
novelWriter – Project Item Status Class
=========================================
Class holding the status/importance elements of a project item
File History:
Created: 2019-05-19 [0.1.3]
File History:
Created: 2019-05-19 [0.1.3]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
@@ -33,15 +31,18 @@ from nw.common import checkInt
logger = logging.getLogger(__name__)
class NWStatus():
def __init__(self):
self._theLabels = []
self._theLabels = []
self._theColours = []
self._theCounts = []
self._theMap = {}
self._theLength = 0
self._theIndex = 0
self._theCounts = []
self._theMap = {}
self._theLength = 0
self._theIndex = 0
return
def addEntry(self, theLabel, theColours):
@@ -88,12 +89,12 @@ class NWStatus():
replaceMap = {}
if newList is not None:
self._theLabels = []
self._theLabels = []
self._theColours = []
self._theCounts = []
self._theMap = {}
self._theLength = 0
self._theIndex = 0
self._theCounts = []
self._theMap = {}
self._theLength = 0
self._theIndex = 0
for nName, nR, nG, nB, oName in newList:
self.addEntry(nName, (nR, nG, nB))
@@ -123,9 +124,9 @@ class NWStatus():
"""
for n in range(self._theLength):
xSub = etree.SubElement(xParent, "entry", attrib={
"blue" : str(self._theColours[n][2]),
"green" : str(self._theColours[n][1]),
"red" : str(self._theColours[n][0]),
"blue": str(self._theColours[n][2]),
"green": str(self._theColours[n][1]),
"red": str(self._theColours[n][0]),
})
xSub.text = self._theLabels[n]
return True

View File

@@ -1,66 +1,52 @@
# -*- coding: utf-8 -*-
"""novelWriter HTML Text Converter
"""
novelWriter – HTML Text Converter
=================================
Extends the Tokenizer class to generate HTML output
novelWriter – HTML Text Converter
===================================
Extends the Tokenizer class to write HTML
File History:
Created: 2019-05-07 [0.0.1]
File History:
Created: 2019-05-07 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
import re
from nw.core.tokenizer import Tokenizer
from nw.constants import nwUnicode, nwLabels, nwKeyWords
from nw.constants import nwKeyWords, nwLabels, nwHtmlUnicode
logger = logging.getLogger(__name__)
class ToHtml(Tokenizer):
M_PREVIEW = 0 # Tweak output for the DocViewer
M_EXPORT = 1 # Tweak output for saving to HTML or printing
M_EBOOK = 2 # Tweak output for converting to epub
M_PREVIEW = 0 # Tweak output for the DocViewer
M_EXPORT = 1 # Tweak output for saving to HTML or printing
M_EBOOK = 2 # Tweak output for converting to epub
def __init__(self, theProject, theParent):
Tokenizer.__init__(self, theProject, theParent)
def __init__(self, theProject):
Tokenizer.__init__(self, theProject)
self.genMode = self.M_EXPORT
self.cssStyles = True
self.fullHTML = []
self.repDict = {
"<" : "&lt;",
">" : "&gt;",
"&" : "&amp;",
nwUnicode.U_ENDASH : nwUnicode.H_ENDASH,
nwUnicode.U_EMDASH : nwUnicode.H_EMDASH,
nwUnicode.U_HELLIP : nwUnicode.H_HELLIP,
nwUnicode.U_NBSP : nwUnicode.H_NBSP,
nwUnicode.U_THNSP : nwUnicode.H_THNSP,
nwUnicode.U_THNBSP : nwUnicode.H_THNBSP,
nwUnicode.U_MAPOSS : nwUnicode.H_RSQUO,
}
self.revDict = {}
self.reReplace = []
self.reReverse = []
self._buildRegEx()
# Internals
self._trMap = {}
self.setReplaceUnicode(False)
return
@@ -73,7 +59,7 @@ class ToHtml(Tokenizer):
need to make a few changes to formatting, which is managed by
these flags.
"""
self.genMode = self.M_PREVIEW
self.genMode = self.M_PREVIEW
self.doKeywords = True
self.doComments = doComments
self.doSynopsis = doSynopsis
@@ -87,31 +73,35 @@ class ToHtml(Tokenizer):
self.cssStyles = cssStyles
return
def setReplaceUnicode(self, doReplace):
"""Set the translation map to either minimal or full unicode for
html entities replacement.
"""
# Control characters must always be replaced
# Angle brackets are replaced later as they are also used in
# formatting codes
self._trMap = str.maketrans({"&": "&amp;"})
if doReplace:
# Extend to all relevant Unicode characters
self._trMap.update(str.maketrans(nwHtmlUnicode.U_TO_H))
return
##
# Class Methods
##
def doAutoReplace(self):
def getFullResultSize(self):
"""Return the size of the full HTML result.
"""
return sum([len(x) for x in self.fullHTML])
def doPreProcessing(self):
"""Extend the auto-replace to also properly encode some unicode
characters into their respective HTML entities.
"""
Tokenizer.doAutoReplace(self)
self.theText = self.reReplace.sub(
lambda x: self.repDict[x.group(0)], self.theText
)
return
def doPostProcessing(self):
"""Reverse the html entities replacement on the markdown text.
Otherwise, all the &something; bits will also be in there.
"""
Tokenizer.doPostProcessing(self)
if self.genMode == self.M_PREVIEW:
# Doesn't matter for preview as we don't use the markdown
return
self.theMarkdown = self.reReverse.sub(
lambda x: self.revDict[x.group(0)], self.theMarkdown
)
Tokenizer.doPreProcessing(self)
self.theText = self.theText.translate(self._trMap)
return
def doConvert(self):
@@ -119,22 +109,22 @@ class ToHtml(Tokenizer):
to theResult.
"""
if self.genMode == self.M_PREVIEW:
htmlTags = { # HTML4 + CSS2
self.FMT_B_B : "<b>",
self.FMT_B_E : "</b>",
self.FMT_I_B : "<i>",
self.FMT_I_E : "</i>",
self.FMT_D_B : "<span style='text-decoration: line-through;'>",
self.FMT_D_E : "</span>",
htmlTags = { # HTML4 + CSS2
self.FMT_B_B: "<b>",
self.FMT_B_E: "</b>",
self.FMT_I_B: "<i>",
self.FMT_I_E: "</i>",
self.FMT_D_B: "<span style='text-decoration: line-through;'>",
self.FMT_D_E: "</span>",
}
else:
htmlTags = { # HTML5
self.FMT_B_B : "<strong>",
self.FMT_B_E : "</strong>",
self.FMT_I_B : "<em>",
self.FMT_I_E : "</em>",
self.FMT_D_B : "<del>",
self.FMT_D_E : "</del>",
htmlTags = { # HTML5
self.FMT_B_B: "<strong>",
self.FMT_B_E: "</strong>",
self.FMT_I_B: "<em>",
self.FMT_I_E: "</em>",
self.FMT_D_B: "<del>",
self.FMT_D_E: "</del>",
}
if self.isNovel and self.genMode != self.M_PREVIEW:
@@ -158,32 +148,43 @@ class ToHtml(Tokenizer):
thisPar = []
parStyle = None
tmpResult = []
hasHardBreak = False
for tType, tLine, tText, tFormat, tStyle in self.theTokens:
# Replace < and > before adding html tags
tText = tText.replace("<", "&lt;").replace(">", "&gt;")
# Styles
aStyle = []
if tStyle is not None and self.cssStyles:
if tStyle & self.A_LEFT:
aStyle.append("text-align: left;")
if tStyle & self.A_RIGHT:
elif tStyle & self.A_RIGHT:
aStyle.append("text-align: right;")
if tStyle & self.A_CENTRE:
elif tStyle & self.A_CENTRE:
aStyle.append("text-align: center;")
if tStyle & self.A_JUSTIFY:
elif tStyle & self.A_JUSTIFY:
aStyle.append("text-align: justify;")
if tStyle & self.A_PBB:
aStyle.append("page-break-before: always;")
if tStyle & self.A_PBB_AV:
aStyle.append("page-break-before: avoid;")
if tStyle & self.A_PBB_NO:
aStyle.append("page-break-before: never;")
elif tStyle & self.A_PBB_AUT:
aStyle.append("page-break-before: auto;")
if tStyle & self.A_PBA:
aStyle.append("page-break-after: always;")
if tStyle & self.A_PBA_AV:
aStyle.append("page-break-after: avoid;")
if tStyle & self.A_PBA_NO:
aStyle.append("page-break-after: never;")
elif tStyle & self.A_PBA_AUT:
aStyle.append("page-break-after: auto;")
if tStyle & self.A_Z_BTMMRG:
aStyle.append("margin-bottom: 0;")
if tStyle & self.A_Z_TOPMRG:
aStyle.append("margin-top: 0;")
if tStyle & self.A_IND_L:
aStyle.append("margin-left: %dpx;" % self.mainConf.tabWidth)
if tStyle & self.A_IND_R:
aStyle.append("margin-right: %dpx;" % self.mainConf.tabWidth)
if len(aStyle) > 0:
hStyle = " style='%s'" % (" ".join(aStyle))
@@ -199,16 +200,15 @@ class ToHtml(Tokenizer):
if tType == self.T_EMPTY:
if parStyle is None:
parStyle = ""
if hasHardBreak and self.cssStyles:
if len(thisPar) > 1 and self.cssStyles:
parClass = " class='break'"
else:
parClass = ""
if len(thisPar) > 0:
tTemp = "".join(thisPar)
tTemp = "<br/>".join(thisPar)
tmpResult.append("<p%s%s>%s</p>\n" % (parStyle, parClass, tTemp.rstrip()))
thisPar = []
parStyle = None
hasHardBreak = False
elif tType == self.T_TITLE:
tHead = tText.replace(r"\\", "<br/>")
@@ -241,12 +241,8 @@ class ToHtml(Tokenizer):
if parStyle is None:
parStyle = hStyle
for xPos, xLen, xFmt in reversed(tFormat):
tTemp = tTemp[:xPos]+htmlTags[xFmt]+tTemp[xPos+xLen:]
if tText.endswith(" "):
thisPar.append(tTemp.rstrip()+"<br/>")
hasHardBreak = True
else:
thisPar.append(tTemp.rstrip()+" ")
tTemp = tTemp[:xPos] + htmlTags[xFmt] + tTemp[xPos+xLen:]
thisPar.append(tTemp.rstrip())
elif tType == self.T_SYNOPSIS and self.doSynopsis:
tmpResult.append(self._formatSynopsis(tText))
@@ -255,11 +251,60 @@ class ToHtml(Tokenizer):
tmpResult.append(self._formatComments(tText))
elif tType == self.T_KEYWORD and self.doKeywords:
tmpResult.append(self._formatKeywords(tText))
tTemp = "<p%s>%s</p>\n" % (hStyle, self._formatKeywords(tText))
tmpResult.append(tTemp)
self.theResult = "".join(tmpResult)
tmpResult = []
if self.genMode != self.M_PREVIEW:
self.fullHTML.append(self.theResult)
return
def saveHTML5(self, savePath):
"""Save the data to an .html file.
"""
with open(savePath, mode="w", encoding="utf-8") as outFile:
theStyle = self.getStyleSheet()
theStyle.append("article {width: 800px; margin: 40px auto;}")
bodyText = "".join(self.fullHTML)
bodyText = bodyText.replace("\t", "&#09;").rstrip()
theHtml = (
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<meta charset='utf-8'>\n"
"<title>{projTitle:s}</title>\n"
"</head>\n"
"<style>\n"
"{htmlStyle:s}\n"
"</style>\n"
"<body>\n"
"<article>\n"
"{bodyText:s}\n"
"</article>\n"
"</body>\n"
"</html>\n"
).format(
projTitle=self.theProject.projName,
htmlStyle="\n".join(theStyle),
bodyText=bodyText,
)
outFile.write(theHtml)
return
def replaceTabs(self, nSpaces=8, spaceChar="&nbsp;"):
"""Replace tabs with spaces in the html.
"""
htmlText = []
eightSpace = spaceChar*nSpaces
for aLine in self.fullHTML:
htmlText.append(aLine.replace("\t", eightSpace))
self.fullHTML = htmlText
return
def getStyleSheet(self):
@@ -269,22 +314,86 @@ class ToHtml(Tokenizer):
if not self.cssStyles:
return theStyles
if self.doJustify:
theStyles.append(r"p {text-align: justify;}")
else:
theStyles.append(r"p {text-align: left;}")
mScale = self.lineHeight/1.15
textAlign = "justify" if self.doJustify else "left"
theStyles.append(r"h1, h2 {color: rgb(66, 113, 174);}")
theStyles.append(r"h3, h4 {color: rgb(50, 50, 50);}")
theStyles.append(r"h1, h2, h3, h4 {page-break-after: avoid;}")
theStyles.append(r"a {color: rgb(66, 113, 174);}")
theStyles.append(r".title {font-size: 2.5em;}")
theStyles.append(r".tags {color: rgb(245, 135, 31); font-weight: bold;}")
theStyles.append(r".break {text-align: left;}")
theStyles.append(r".sep {text-align: center; margin-top: 1em; margin-bottom: 1em;}")
theStyles.append(r".skip {margin-top: 1em; margin-bottom: 1em;}")
theStyles.append(r".synopsis {font-style: italic;}")
theStyles.append(r".comment {font-style: italic; color: rgb(100, 100, 100);}")
theStyles.append("body {font-family: '%s'; font-size: %dpt;}" % (
self.textFont, self.textSize
))
theStyles.append((
"p {"
"text-align: %s; line-height: %d%%; "
"margin-top: %.2fem; margin-bottom: %.2fem;"
"}"
) % (
textAlign,
round(100 * self.lineHeight),
mScale * self.marginText[0],
mScale * self.marginText[1],
))
theStyles.append((
"h1 {"
"color: rgb(66, 113, 174); "
"page-break-after: avoid; "
"margin-top: %.2fem; "
"margin-bottom: %.2fem;"
"}"
) % (
mScale * self.marginHead1[0], mScale * self.marginHead1[1]
))
theStyles.append((
"h2 {"
"color: rgb(66, 113, 174); "
"page-break-after: avoid; "
"margin-top: %.2fem; "
"margin-bottom: %.2fem;"
"}"
) % (
mScale * self.marginHead2[0], mScale * self.marginHead2[1]
))
theStyles.append((
"h3 {"
"color: rgb(50, 50, 50); "
"page-break-after: avoid; "
"margin-top: %.2fem; "
"margin-bottom: %.2fem;"
"}"
) % (
mScale * self.marginHead3[0], mScale * self.marginHead3[1]
))
theStyles.append((
"h4 {"
"color: rgb(50, 50, 50); "
"page-break-after: avoid; "
"margin-top: %.2fem; "
"margin-bottom: %.2fem;"
"}"
) % (
mScale * self.marginHead4[0], mScale * self.marginHead4[1]
))
theStyles.append((
".title {"
"font-size: 2.5em; "
"margin-top: %.2fem; "
"margin-bottom: %.2fem;"
"}"
) % (
mScale * self.marginTitle[0], mScale * self.marginTitle[1]
))
theStyles.append((
".sep, .skip {"
"text-align: center; "
"margin-top: %.2fem; "
"margin-bottom: %.2fem;}"
) % (
mScale, mScale
))
theStyles.append("a {color: rgb(66, 113, 174);}")
theStyles.append(".tags {color: rgb(245, 135, 31); font-weight: bold;}")
theStyles.append(".break {text-align: left;}")
theStyles.append(".synopsis {font-style: italic;}")
theStyles.append(".comment {font-style: italic; color: rgb(100, 100, 100);}")
return theStyles
@@ -296,17 +405,20 @@ class ToHtml(Tokenizer):
"""Apply HTML formatting to synopsis.
"""
if self.genMode == self.M_PREVIEW:
return "<p class='comment'><span class='synopsis'>Synopsis: </span>%s</p>\n" % tText
sSynop = self._trSynopsis
return f"<p class='comment'><span class='synopsis'>{sSynop}:</span> {tText}</p>\n"
else:
return "<p class='synopsis'><strong>Synopsis: </strong>%s</p>\n" % tText
sSynop = self._localLookup("Synopsis")
return f"<p class='synopsis'><strong>{sSynop}:</strong> {tText}</p>\n"
def _formatComments(self, tText):
"""Apply HTML formatting to comments.
"""
if self.genMode == self.M_PREVIEW:
return "<p class='comment'>%s</p>\n" % tText
return f"<p class='comment'>{tText}</p>\n"
else:
return "<p class='comment'><strong>Comment: </strong>%s</p>\n" % tText
sComm = self._localLookup("Comment")
return f"<p class='comment'><strong>{sComm}:</strong> {tText}</p>\n"
def _formatKeywords(self, tText):
"""Apply HTML formatting to keywords.
@@ -338,18 +450,6 @@ class ToHtml(Tokenizer):
))
retText += ", ".join(refTags)
return "<div>%s</div>" % retText
def _buildRegEx(self):
"""Build the regular expressions
"""
self.revDict = dict(map(reversed, self.repDict.items()))
self.reReplace = re.compile(
"|".join([re.escape(k) for k in self.repDict.keys()]), flags=re.DOTALL
)
self.reReverse = re.compile(
"|".join([re.escape(k) for k in self.revDict.keys()]), flags=re.DOTALL
)
return
return retText
# END Class ToHtml

View File

@@ -1,112 +1,138 @@
# -*- coding: utf-8 -*-
"""novelWriter Text Tokenizer
"""
novelWriter – Text Tokenizer
============================
Splits a piece of novelWriter markdown text into its elements
novelWriter – Text Tokenizer
==============================
Splits a piece of novelWriter markdown text into its elements
File History:
Created: 2019-05-05 [0.0.1]
File History:
Created: 2019-05-05 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This file is a part of novelWriter
Copyright 2018–2021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
import nw
import re
import logging
from operator import itemgetter
from PyQt5.QtCore import QRegularExpression
from functools import partial
from PyQt5.QtCore import QCoreApplication, QRegularExpression
from nw.enum import nwItemLayout, nwItemType
from nw.common import numberToRoman
from nw.constants import nwConst, nwRegEx, nwUnicode
from nw.core.document import NWDoc
from nw.core.tools import numberToWord, numberToRoman
from nw.constants import nwConst, nwItemLayout, nwItemType, nwRegEx
logger = logging.getLogger(__name__)
class Tokenizer():
FMT_B_B = 1 # Begin bold
FMT_B_E = 2 # End bold
FMT_I_B = 3 # Begin italics
FMT_I_E = 4 # End italics
FMT_D_B = 5 # Begin strikeout
FMT_D_E = 6 # End strikeout
# In-Text Format
FMT_B_B = 1 # Begin bold
FMT_B_E = 2 # End bold
FMT_I_B = 3 # Begin italics
FMT_I_E = 4 # End italics
FMT_D_B = 5 # Begin strikeout
FMT_D_E = 6 # End strikeout
T_EMPTY = 1 # Empty line (new paragraph)
T_SYNOPSIS = 2 # Synopsis comment
T_COMMENT = 3 # Comment line
T_KEYWORD = 4 # Command line
T_TITLE = 5 # Title
T_HEAD1 = 6 # Header 1
T_HEAD2 = 7 # Header 2
T_HEAD3 = 8 # Header 3
T_HEAD4 = 9 # Header 4
T_TEXT = 10 # Text line
T_SEP = 11 # Scene separator
T_SKIP = 12 # Paragraph break
# Block Type
T_EMPTY = 1 # Empty line (new paragraph)
T_SYNOPSIS = 2 # Synopsis comment
T_COMMENT = 3 # Comment line
T_KEYWORD = 4 # Command line
T_TITLE = 5 # Title
T_HEAD1 = 6 # Header 1
T_HEAD2 = 7 # Header 2
T_HEAD3 = 8 # Header 3
T_HEAD4 = 9 # Header 4
T_TEXT = 10 # Text line
T_SEP = 11 # Scene separator
T_SKIP = 12 # Paragraph break
A_NONE = 0 # No special style
A_LEFT = 1 # Left aligned
A_RIGHT = 2 # Right aligned
A_CENTRE = 4 # Centred
A_JUSTIFY = 8 # Justified
A_PBB = 16 # Page break before always
A_PBB_AV = 32 # Page break before avoid
A_PBB_NO = 64 # Page break before never
A_PBA = 128 # Page break after always
A_PBA_AV = 256 # Page break after avoid
A_PBA_NO = 512 # Page break after avoid
# Block Style
A_NONE = 0x0000 # No special style
A_LEFT = 0x0001 # Left aligned
A_RIGHT = 0x0002 # Right aligned
A_CENTRE = 0x0004 # Centred
A_JUSTIFY = 0x0008 # Justified
A_PBB = 0x0010 # Page break before always
A_PBB_AUT = 0x0020 # Page break before auto
A_PBA = 0x0040 # Page break after always
A_PBA_AUT = 0x0080 # Page break after auto
A_Z_TOPMRG = 0x0100 # Zero top margin
A_Z_BTMMRG = 0x0200 # Zero bottom margin
A_IND_L = 0x0400 # Left indentation
A_IND_R = 0x0800 # Right indentation
def __init__(self, theProject, theParent):
def __init__(self, theProject):
self.theProject = theProject
self.theParent = theParent
self.theParent = theProject.theParent
self.mainConf = nw.CONFIG
# Data Variables
self.theText = None # The raw text to be tokenized
self.theHandle = None # The handle associated with the text
self.theItem = None # The NWItem associated with the handle
self.theTokens = None # The list of the processed tokens
self.theResult = None # The result text after conversion
self.theMarkdown = None # The result text in novelWriter markdown
self.theText = "" # The raw text to be tokenized
self.theHandle = None # The handle associated with the text
self.theItem = None # The NWItem associated with the handle
self.theTokens = [] # The list of the processed tokens
self.theResult = "" # The result of the last document
self.keepMarkdown = False # Whether to keep the markdown text
self.theMarkdown = [] # The result novelWriter markdown of all documents
# User Settings
self.doBodyText = True # Include body text
self.doSynopsis = False # Also process synopsis comments
self.doComments = False # Also process comments
self.doKeywords = False # Also process keywords like tags and references
self.doJustify = False # Justify text
self.textFont = "Serif" # Output text font
self.textSize = 11 # Output text size
self.textFixed = False # Fixed width text
self.lineHeight = 1.15 # Line height in units of em
self.blockIndent = 4.00 # Block indent in units of em
self.doJustify = False # Justify text
self.doBodyText = True # Include body text
self.doSynopsis = False # Also process synopsis comments
self.doComments = False # Also process comments
self.doKeywords = False # Also process keywords like tags and references
self.fmtTitle = "%title%" # Formatting for titles
self.fmtChapter = "%title%" # Formatting for numbered chapters
self.fmtUnNum = "%title%" # Formatting for unnumbered chapters
self.fmtScene = "%title%" # Formatting for scenes
self.fmtSection = "%title%" # Formatting for sections
# Margins
self.marginTitle = (1.000, 0.500)
self.marginHead1 = (1.000, 0.500)
self.marginHead2 = (0.834, 0.500)
self.marginHead3 = (0.584, 0.500)
self.marginHead4 = (0.584, 0.500)
self.marginText = (0.000, 0.584)
self.marginMeta = (0.000, 0.584)
self.hideScene = False # Do not include scene headers
self.hideSection = False # Do not include section headers
# Title Formats
self.fmtTitle = "%title%" # Formatting for titles
self.fmtChapter = "%title%" # Formatting for numbered chapters
self.fmtUnNum = "%title%" # Formatting for unnumbered chapters
self.fmtScene = "%title%" # Formatting for scenes
self.fmtSection = "%title%" # Formatting for sections
self.linkHeaders = False # Add an anchor before headers
self.hideScene = False # Do not include scene headers
self.hideSection = False # Do not include section headers
self.linkHeaders = False # Add an anchor before headers
# Instance Variables
self.numChapter = 0 # Counter for chapter numbers
self.numChScene = 0 # Counter for scene number within chapter
self.numAbsScene = 0 # Counter for scene number within novel
self.firstScene = False # Flag to indicate that the first scene of the chapter
self.numChapter = 0 # Counter for chapter numbers
self.numChScene = 0 # Counter for scene number within chapter
self.numAbsScene = 0 # Counter for scene number within novel
self.firstScene = False # Flag to indicate that the first scene of the chapter
# This File
self.isNone = False
@@ -123,6 +149,13 @@ class Tokenizer():
# Error Handling
self.errData = []
# Function Mapping
self._localLookup = self.theProject.localLookup
self.tr = partial(QCoreApplication.translate, "Tokenizer")
# Cached Translations
self._trSynopsis = self.tr("Synopsis")
return
##
@@ -151,6 +184,52 @@ class Tokenizer():
self.hideSection = hideSection
return
def setFont(self, textFont, textSize, textFixed=False):
self.textFont = textFont
self.textSize = round(int(textSize))
self.textFixed = textFixed
return
def setLineHeight(self, lineHeight):
self.lineHeight = min(max(float(lineHeight), 0.5), 5.0)
return
def setBlockIndent(self, blockIndent):
self.blockIndent = min(max(float(blockIndent), 0.0), 10.0)
return
def setJustify(self, doJustify):
self.doJustify = doJustify
return
def setTitleMargins(self, mUpper, mLower):
self.marginTitle = (float(mUpper), float(mLower))
return
def setHead1Margins(self, mUpper, mLower):
self.marginHead1 = (float(mUpper), float(mLower))
return
def setHead2Margins(self, mUpper, mLower):
self.marginHead2 = (float(mUpper), float(mLower))
return
def setHead3Margins(self, mUpper, mLower):
self.marginHead3 = (float(mUpper), float(mLower))
return
def setHead4Margins(self, mUpper, mLower):
self.marginHead4 = (float(mUpper), float(mLower))
return
def setTextMargins(self, mUpper, mLower):
self.marginText = (float(mUpper), float(mLower))
return
def setMetaMargins(self, mUpper, mLower):
self.marginMeta = (float(mUpper), float(mLower))
return
def setLinkHeaders(self, linkHeaders):
self.linkHeaders = linkHeaders
return
@@ -171,8 +250,8 @@ class Tokenizer():
self.doKeywords = doKeywords
return
def setJustify(self, doJustify):
self.doJustify = doJustify
def setKeepMarkdown(self, keepMarkdown):
self.keepMarkdown = keepMarkdown
return
##
@@ -189,12 +268,13 @@ class Tokenizer():
if theItem.itemType != nwItemType.ROOT:
return False
theTitle = "Notes: %s" % theItem.itemName
theTitle = "%s: %s" % (self._localLookup("Notes"), theItem.itemName)
self.theTokens = []
self.theTokens.append((
self.T_TITLE, 0, theTitle, None, self.A_PBB | self.A_CENTRE
))
self.theMarkdown = "# %s\n\n" % theTitle
if self.keepMarkdown:
self.theMarkdown.append("# %s\n\n" % theTitle)
return True
@@ -207,20 +287,23 @@ class Tokenizer():
if self.theItem is None:
return False
self.theText = ""
if theText is not None:
# If the text is set, just use that
self.theText = theText
else:
# Otherwise, load it from file
theDocument = NWDoc(self.theProject, self.theParent)
self.theText = theDocument.openDocument(theHandle)
theDoc = NWDoc(self.theProject, theHandle)
theText = theDoc.readDocument()
if theText:
self.theText = theText
docSize = len(self.theText)
if docSize > nwConst.MAX_DOCSIZE:
errVal = "Document '%s' is too big (%.2f MB). Skipping." % (
self.theItem.itemName, docSize/1.0e6
errVal = self.tr("Document '{0}' is too big ({1} MB). Skipping.").format(
self.theItem.itemName, f"{docSize/1.0e6:.2f}"
)
self.theText = "# ERROR\n\n%s\n\n" % errVal
self.theText = "# %s\n\n%s\n\n" % (self.tr("ERROR"), errVal)
self.errData.append(errVal)
self.isNone = self.theItem.itemLayout == nwItemLayout.NO_LAYOUT
@@ -236,26 +319,10 @@ class Tokenizer():
return True
def getResult(self):
"""Return the result from the conversion.
"""
return self.theResult
def getResultSize(self):
"""Return the size of the result from the conversion.
"""
if self.theResult is None:
return 0
return len(self.theResult)
def getFilteredMarkdown(self):
"""Return the novelWriter markdown after the filters have been applied.
"""
return self.theMarkdown
def doAutoReplace(self):
"""Run through the user's auto-replace dictionary.
def doPreProcessing(self):
"""Run trough the various replace doctionaries.
"""
# Process the user's auto-replace dictionary
if len(self.theProject.autoReplace) > 0:
repDict = {}
for aKey, aVal in self.theProject.autoReplace.items():
@@ -263,6 +330,10 @@ class Tokenizer():
xRep = re.compile("|".join([re.escape(k) for k in repDict.keys()]), flags=re.DOTALL)
self.theText = xRep.sub(lambda x: repDict[x.group(0)], self.theText)
# Process the character translation map
trDict = {nwUnicode.U_MAPOSS: nwUnicode.U_RSQUO}
self.theText = self.theText.translate(str.maketrans(trDict))
return
def doPostProcessing(self):
@@ -270,9 +341,9 @@ class Tokenizer():
does the standard escaped characters.
"""
escapeDict = {
r"\*" : "*",
r"\~" : "~",
r"\_" : "_",
r"\*": "*",
r"\~": "~",
r"\_": "_",
}
escReplace = re.compile(
"|".join([re.escape(k) for k in escapeDict.keys()]), flags=re.DOTALL
@@ -304,8 +375,13 @@ class Tokenizer():
(QRegularExpression(nwRegEx.FMT_ST), [None, self.FMT_D_B, None, self.FMT_D_E]),
]
# Determine default text alignment
if self.isTitle or self.isPart:
defAlign = self.A_CENTRE
else:
defAlign = self.A_NONE
self.theTokens = []
self.theMarkdown = ""
tmpMarkdown = []
nLine = 0
for aLine in self.theText.splitlines():
@@ -314,94 +390,99 @@ class Tokenizer():
# Tag lines starting with specific characters
if len(aLine.strip()) == 0:
self.theTokens.append((
self.T_EMPTY,
nLine,
"",
None,
self.A_NONE
self.T_EMPTY, nLine, "", None, defAlign
))
tmpMarkdown.append("\n")
if self.keepMarkdown:
tmpMarkdown.append("\n")
elif aLine[0] == "%":
cLine = aLine[1:].lstrip()
synTag = cLine[:9].lower()
if synTag == "synopsis:":
self.theTokens.append((
self.T_SYNOPSIS,
nLine,
cLine[9:].strip(),
None,
self.A_NONE
self.T_SYNOPSIS, nLine, cLine[9:].strip(), None, defAlign
))
if self.doSynopsis:
if self.doSynopsis and self.keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
else:
self.theTokens.append((
self.T_COMMENT,
nLine,
aLine[1:].strip(),
None,
self.A_NONE
self.T_COMMENT, nLine, aLine[1:].strip(), None, defAlign
))
if self.doComments:
if self.doComments and self.keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[0] == "@":
self.theTokens.append((
self.T_KEYWORD,
nLine,
aLine[1:].strip(),
None,
self.A_NONE
self.T_KEYWORD, nLine, aLine[1:].strip(), None, defAlign
))
if self.doKeywords:
if self.doKeywords and self.keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:2] == "# ":
self.theTokens.append((
self.T_HEAD1,
nLine,
aLine[2:].strip(),
None,
self.A_NONE
self.T_HEAD1, nLine, aLine[2:].strip(), None, defAlign
))
tmpMarkdown.append("%s\n" % aLine)
if self.keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:3] == "## ":
self.theTokens.append((
self.T_HEAD2,
nLine,
aLine[3:].strip(),
None,
self.A_NONE
self.T_HEAD2, nLine, aLine[3:].strip(), None, defAlign
))
tmpMarkdown.append("%s\n" % aLine)
if self.keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:4] == "### ":
self.theTokens.append((
self.T_HEAD3,
nLine,
aLine[4:].strip(),
None,
self.A_NONE
self.T_HEAD3, nLine, aLine[4:].strip(), None, defAlign
))
tmpMarkdown.append("%s\n" % aLine)
if self.keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:5] == "#### ":
self.theTokens.append((
self.T_HEAD4,
nLine,
aLine[5:].strip(),
None,
self.A_NONE
self.T_HEAD4, nLine, aLine[5:].strip(), None, defAlign
))
tmpMarkdown.append("%s\n" % aLine)
if self.keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
else:
if not self.doBodyText:
# Skip all body text
continue
# Check Alignment and Indentation
tagLeft = False
tagRight = False
indLeft = False
indRight = False
if aLine.startswith(">>"):
tagRight = True
aLine = aLine[2:].lstrip(" ")
elif aLine.startswith(">"):
indLeft = True
aLine = aLine[1:].lstrip(" ")
if aLine.endswith("<<"):
tagLeft = True
aLine = aLine[:-2].rstrip(" ")
elif aLine.endswith("<"):
indRight = True
aLine = aLine[:-1].rstrip(" ")
textAlign = defAlign
if tagLeft and tagRight:
textAlign = self.A_CENTRE
elif tagLeft:
textAlign = self.A_LEFT
elif tagRight:
textAlign = self.A_RIGHT
if indLeft:
textAlign |= self.A_IND_L
if indRight:
textAlign |= self.A_IND_R
# Otherwise we use RegEx to find formatting tags within a line of text
fmtPos = []
for theRX, theKeys in rxFormats:
@@ -418,26 +499,44 @@ class Tokenizer():
# sorted by position
fmtPos = sorted(fmtPos, key=itemgetter(0))
self.theTokens.append((
self.T_TEXT,
nLine,
aLine,
fmtPos,
self.A_NONE
self.T_TEXT, nLine, aLine, fmtPos, textAlign
))
tmpMarkdown.append("%s\n" % aLine)
if self.keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
# Always add an empty line at the end
self.theTokens.append((
self.T_EMPTY,
nLine,
"",
None,
self.A_NONE
self.T_EMPTY, nLine, "", None, defAlign
))
tmpMarkdown.append("\n")
if self.keepMarkdown:
tmpMarkdown.append("\n")
self.theMarkdown = "".join(tmpMarkdown)
tmpMarkdown = []
if self.keepMarkdown:
self.theMarkdown.append("".join(tmpMarkdown))
# Second Pass
# ===========
# Some items need a second pass
pToken = (self.T_EMPTY, 0, "", None, defAlign)
nToken = (self.T_EMPTY, 0, "", None, defAlign)
tCount = len(self.theTokens)
for n, tToken in enumerate(self.theTokens):
if n > 0:
pToken = self.theTokens[n-1]
if n < tCount - 1:
nToken = self.theTokens[n+1]
if tToken[0] == self.T_KEYWORD:
aStyle = tToken[4]
if pToken[0] == self.T_KEYWORD:
aStyle |= self.A_Z_TOPMRG
if nToken[0] == self.T_KEYWORD:
aStyle |= self.A_Z_BTMMRG
self.theTokens[n] = (
tToken[0], tToken[1], tToken[2], tToken[3], aStyle
)
return
@@ -452,9 +551,7 @@ class Tokenizer():
# For novel files, we need to handle chapter numbering, scene
# numbering, and scene breaks
if self.isNovel:
for n in range(len(self.theTokens)):
tToken = self.theTokens[n]
for n, tToken in enumerate(self.theTokens):
# In case we see text before a scene, we reset the flag
if tToken[0] == self.T_TEXT:
@@ -466,11 +563,7 @@ class Tokenizer():
tTemp = self._formatHeading(self.fmtTitle, tToken[2])
self.theTokens[n] = (
tToken[0],
tToken[1],
tTemp,
None,
self.A_NONE
tToken[0], tToken[1], tTemp, None, self.A_NONE
)
elif tToken[0] == self.T_HEAD2:
@@ -488,11 +581,7 @@ class Tokenizer():
# Format the chapter header
self.theTokens[n] = (
tToken[0],
tToken[1],
tTemp,
None,
self.A_PBB
tToken[0], tToken[1], tTemp, None, self.A_PBB
)
# Set scene variables
@@ -509,53 +598,29 @@ class Tokenizer():
tTemp = self._formatHeading(self.fmtScene, tToken[2])
if tTemp == "" and self.hideScene:
self.theTokens[n] = (
self.T_EMPTY,
tToken[1],
"",
None,
self.A_NONE
self.T_EMPTY, tToken[1], "", None, self.A_NONE
)
elif tTemp == "" and not self.hideScene:
if self.firstScene:
self.theTokens[n] = (
self.T_EMPTY,
tToken[1],
"",
None,
self.A_NONE
self.T_EMPTY, tToken[1], "", None, self.A_NONE
)
else:
self.theTokens[n] = (
self.T_SKIP,
tToken[1],
"",
None,
self.A_NONE
self.T_SKIP, tToken[1], "", None, self.A_NONE
)
elif tTemp == self.fmtScene:
if self.firstScene:
self.theTokens[n] = (
self.T_EMPTY,
tToken[1],
"",
None,
self.A_NONE
self.T_EMPTY, tToken[1], "", None, self.A_NONE
)
else:
self.theTokens[n] = (
self.T_SEP,
tToken[1],
tTemp,
None,
self.A_CENTRE
self.T_SEP, tToken[1], tTemp, None, self.A_CENTRE
)
else:
self.theTokens[n] = (
tToken[0],
tToken[1],
tTemp,
None,
self.A_NONE
tToken[0], tToken[1], tTemp, None, self.A_NONE
)
# Definitely no longer the first scene
@@ -568,104 +633,67 @@ class Tokenizer():
tTemp = self._formatHeading(self.fmtSection, tToken[2])
if tTemp == "" and self.hideSection:
self.theTokens[n] = (
self.T_EMPTY,
tToken[1],
"",
None,
self.A_NONE
self.T_EMPTY, tToken[1], "", None, self.A_NONE
)
elif tTemp == "" and not self.hideSection:
self.theTokens[n] = (
self.T_SKIP,
tToken[1],
"",
None,
self.A_NONE
self.T_SKIP, tToken[1], "", None, self.A_NONE
)
elif tTemp == self.fmtSection:
self.theTokens[n] = (
self.T_SEP,
tToken[1],
tTemp,
None,
self.A_CENTRE
self.T_SEP, tToken[1], tTemp, None, self.A_CENTRE
)
else:
self.theTokens[n] = (
tToken[0],
tToken[1],
tTemp,
None,
self.A_NONE
tToken[0], tToken[1], tTemp, None, self.A_NONE
)
# For title page and partitions, we need to centre all text.
# For partition, we also add a page break before, and for
# both types we always add a page break after the content.
# We also swap header level 1 with a title type instead.
# For title page we use a different title class, and we will set
# an automatic page break before (i.e. added if needed). For
# partitions we always need a page break before.
if self.isTitle or self.isPart:
for n, tToken in enumerate(self.theTokens):
aStyle = tToken[4]
if n == 0:
if self.isTitle:
aStyle |= self.A_PBB_AUT
else:
aStyle |= self.A_PBB
if tToken[0] == self.T_HEAD1:
if self.isTitle:
self.theTokens[n] = (
self.T_TITLE,
tToken[1],
tToken[2],
tToken[3],
self.A_PBB_NO | self.A_CENTRE
self.T_TITLE, tToken[1], tToken[2], tToken[3], aStyle
)
else:
self.theTokens[n] = (
tToken[0],
tToken[1],
tToken[2],
tToken[3],
self.A_PBB | self.A_CENTRE
tToken[0], tToken[1], tToken[2], tToken[3], aStyle
)
else:
self.theTokens[n] = (
tToken[0],
tToken[1],
tToken[2],
tToken[3],
self.A_CENTRE
)
# Add a page break after the last entry
n = len(self.theTokens) - 1
if n >= 0:
tToken = self.theTokens[n]
self.theTokens[n] = (
tToken[0],
tToken[1],
tToken[2],
tToken[3],
tToken[4] | self.A_PBA
if len(self.theTokens) > 0:
tToken = self.theTokens[-1]
self.theTokens[-1] = (
tToken[0], tToken[1], tToken[2], tToken[3], tToken[4] | self.A_PBA
)
# A single page is always left-aligned and starts on a fresh
# page, unless it's empty.
if self.isPage:
for n, tToken in enumerate(self.theTokens):
if n == 0:
self.theTokens[n] = (
tToken[0],
tToken[1],
tToken[2],
tToken[3],
self.A_LEFT | self.A_PBB
)
else:
self.theTokens[n] = (
tToken[0],
tToken[1],
tToken[2],
tToken[3],
self.A_LEFT
)
# A single page always starts on a fresh page, unless it's empty.
if self.isPage and len(self.theTokens) > 0:
tToken = self.theTokens[0]
self.theTokens[0] = (
tToken[0], tToken[1], tToken[2], tToken[3], tToken[4] | self.A_PBB
)
return True
def saveRawMarkdown(self, savePath):
"""Save the data to a plain text file.
"""
with open(savePath, mode="w", encoding="utf-8") as outFile:
for nwdPage in self.theMarkdown:
outFile.write(nwdPage)
return
##
# Internal Functions
##
@@ -678,11 +706,12 @@ class Tokenizer():
theTitle = theTitle.replace(r"%sc%", str(self.numChScene))
theTitle = theTitle.replace(r"%sca%", str(self.numAbsScene))
if r"%chw%" in theTitle:
theTitle = theTitle.replace(r"%chw%", numberToWord(self.numChapter, "en"))
theTitle = theTitle.replace(r"%chw%", self._localLookup(self.numChapter))
if r"%chi%" in theTitle:
theTitle = theTitle.replace(r"%chi%", numberToRoman(self.numChapter, True))
if r"%chI%" in theTitle:
theTitle = theTitle.replace(r"%chI%", numberToRoman(self.numChapter, False))
return theTitle
return theTitle[:1].upper() + theTitle[1:]
# END Class Tokenizer

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