Merge pull request #419 from vkbo/viewer_tabs

Tab Stop in Document Viewer and Build
This commit is contained in:
Veronica K. Berglyd Olsen
2020-08-18 20:18:00 +02:00
committed by GitHub
5 changed files with 68 additions and 28 deletions
+18 -15
View File
@@ -9,10 +9,10 @@
<img align="left" style="margin: 0 16px 4px 0;" src="https://raw.githubusercontent.com/vkbo/novelWriter/main/assets/icons/96x96/novelwriter.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
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
which allows for easy organisation of text files and notes, built on plain text files for
that allows for easy organisation of text files and notes, built on plain text files for
robustness.
The plain text storage is suitable for version control software, and also well suited for file
@@ -29,7 +29,7 @@ The contributing guide is available in [CONTRIBUTING](CONTRIBUTING.md).
The default branch on this repository switched to `main` on 6. August 2020. If you are running
novelWriter from a git clone, you need to clone the repository again.
Alternatively, you can run the following to get back on the main branch:
Alternatively, you can run the following to get back on the new default branch:
```bash
git remote update
@@ -48,8 +48,8 @@ novelWriter is in a _beta_ state. Please report any issues you may encounter in
tracker.
You should be able to use novelWriter for real projects, but as with all software, please make
regular backups. There is a built in backup feature that can pack the entire project into a zip file
on close. Please check the documentation for further details.
regular backups of your data. There is a built in backup feature that can pack the entire project
into a zip file on close. Please check the documentation for further details.
## License
@@ -80,7 +80,7 @@ novelWriter is _not_ a full-feature Markdown editor. It allows for a minimal set
needed for writing text documents for novels. These are currently limited to:
* Headings level 1 to 4 using the `#` syntax only.
* Emphasised, strong text. These are rendered as italicised and bold.
* 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.
@@ -98,21 +98,24 @@ In addition, novelWriter adds the following, which is otherwise not supported by
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.
* Tabs may be rendered, depending on export format. With Qt 5.10 or higher, the width of a tab in
pixels can be changed in Preferences.
* 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 tabs are exported as-is, also to HTML format. However, most
browsers will treat a tab as a space, so it may not show up like expected if you view the exported
HTML file.
The core export format of novelWriter is HTML5. You can also export the entire project as a single
novelWriter flavour document. In addition, other exports to Open Document, PDF, and plain text is
offered through the Qt library, although with limitations to formatting.
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.
## Implementation
The application is written in Python3 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. It is
in principle work fine on other operating systems as well, as long as dependencies are met. It is
regularly tested on Windows 10.
The application can be started from the source folder with one of the commands:
The application can be started from the source folder with one of the commands, depending on your
Python configuration:
```
./novelWriter.py
python novelWriter.py
@@ -158,7 +161,7 @@ pip install pyenchant
```
PyQt/Qt should be at least 5.3, but ideally 5.10 or higher for nearly all features to work.
Exporting to markdown requires PyQt/Qt 5.14. There are no known minimum for `lxml`, but the code
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.
@@ -237,7 +240,7 @@ clickable in the document view pane, and control-clickable in the editor. They m
quickly navigate between the documents while editing.
## Contribution
## Contributing
If you want to contribute to novelWriter, please follow the coding convention laid out in the
[Style Guide](markdown/style.md). They broadly follow Python PEP8, but there are a few
+3 -5
View File
@@ -45,10 +45,9 @@ class ToHtml(Tokenizer):
self.cssStyles = True
self.repDict = {
"<" : "&lt;",
">" : "&gt;",
"&" : "&amp;",
"\t" : "&emsp;"*2,
"<" : "&lt;",
">" : "&gt;",
"&" : "&amp;",
nwUnicode.U_ENDASH : nwUnicode.H_ENDASH,
nwUnicode.U_EMDASH : nwUnicode.H_EMDASH,
nwUnicode.U_HELLIP : nwUnicode.H_HELLIP,
@@ -77,7 +76,6 @@ class ToHtml(Tokenizer):
self.doKeywords = True
self.doComments = doComments
self.doSynopsis = doSynopsis
self.repDict["\t"] = "&nbsp;"*8
self._buildRegEx()
return
+22 -2
View File
@@ -551,7 +551,6 @@ class GuiBuildNovel(QDialog):
isNone |= theItem.itemClass == nwItemClass.NO_CLASS
isNone |= theItem.itemClass == nwItemClass.TRASH
isNone |= theItem.parHandle == self.theProject.projTree.trashRoot()
isNone |= theItem.parHandle == self.theProject.projTree.archiveRoot()
isNone |= theItem.parHandle is None
isNote = theItem.itemLayout == nwItemLayout.NOTE
isNovel = not isNone and not isNote
@@ -563,6 +562,10 @@ class GuiBuildNovel(QDialog):
if isNovel and not novelFiles:
return False
rootItem = self.theProject.projTree.getRootItem(theItem.itemHandle)
if rootItem.itemClass == nwItemClass.ARCHIVE:
return False
return True
def _saveDocument(self, theFormat):
@@ -1014,13 +1017,30 @@ class GuiBuildNovelDocView(QTextBrowser):
theText = "".join(theText)
self.buildTime = timeStamp
sPos = self.verticalScrollBar().value()
theText = theText.replace("&emsp;", "&nbsp;"*4)
# Refresh the tab stops
if self.mainConf.verQtValue >= 51000:
self.setTabStopDistance(self.mainConf.getTabWidth())
else:
self.setTabStopWidth(self.mainConf.getTabWidth())
theText = theText.replace("\t", "!!tab!!")
theText = theText.replace("<del>", "<span style='text-decoration: line-through;'>")
theText = theText.replace("</del>", "</span>")
self.setHtml(theText)
while self.find("!!tab!!"):
theCursor = self.textCursor()
theCursor.insertText("\t")
self.verticalScrollBar().setValue(sPos)
self._updateBuildAge()
# Since we change the content while it may still be rendering, we mark
# the document dirty again to make sure it's re-rendered properly.
self.qDocument.markContentsDirty(0, self.qDocument.characterCount())
return
def setStyleSheet(self, theStyles=[]):
+6 -2
View File
@@ -206,8 +206,6 @@ class GuiDocEditor(QTextEdit):
# Also set the document text options for the document text flow
theOpt = QTextOption()
if self.mainConf.verQtValue >= 51000:
theOpt.setTabStopDistance(self.mainConf.getTabWidth())
if self.mainConf.doJustify:
theOpt.setAlignment(Qt.AlignJustify)
if self.mainConf.showTabsNSpaces:
@@ -288,6 +286,12 @@ class GuiDocEditor(QTextEdit):
self.hLight.spellCheck = spTemp
qApp.restoreOverrideCursor()
# Refresh the tab stops
if self.mainConf.verQtValue >= 51000:
self.setTabStopDistance(self.mainConf.getTabWidth())
else:
self.setTabStopWidth(self.mainConf.getTabWidth())
return True
def replaceText(self, theText):
+19 -4
View File
@@ -156,7 +156,20 @@ class GuiDocViewer(QTextBrowser):
self.setText("An error occurred while generating the preview.")
return False
self.setHtml(aDoc.theResult)
# Refresh the tab stops
if self.mainConf.verQtValue >= 51000:
self.setTabStopDistance(self.mainConf.getTabWidth())
else:
self.setTabStopWidth(self.mainConf.getTabWidth())
self.setHtml(aDoc.theResult.replace("\t", "!!tab!!"))
# Loop through the text and put back in the tabs. Tabs are removed by
# the setHtml function, so the ToHtml class puts in a placeholder.
while self.find("!!tab!!"):
theCursor = self.textCursor()
theCursor.insertText("\t")
if self.theHandle == tHandle:
self.verticalScrollBar().setValue(sPos)
self.theHandle = tHandle
@@ -167,6 +180,10 @@ class GuiDocViewer(QTextBrowser):
# Make sure the main GUI knows we changed the content
self.theParent.viewMeta.refreshReferences(tHandle)
# Since we change the content while it may still be rendering, we mark
# the document dirty again to make sure it's re-rendered properly.
self.qDocument.markContentsDirty(0, self.qDocument.characterCount())
return True
def reloadText(self):
@@ -188,7 +205,7 @@ class GuiDocViewer(QTextBrowser):
"exist, or the index is out of date. The index can be updated "
"from the Tools menu, or by pressing F9."
) % theTag, nwAlert.ERROR)
return
return False
else:
# Let the parent handle the opening as it also ensures that
# the doc view panel is visible in case this request comes
@@ -357,8 +374,6 @@ class GuiDocViewer(QTextBrowser):
"}}\n"
".comment {{"
" color: rgb({cColR},{cColG},{cColB});"
" margin-left: 1em;"
" margin-right: 1em;"
"}}\n"
".synopsis {{"
" color: rgb({mColR},{mColG},{mColB});"