Merge pull request #419 from vkbo/viewer_tabs
Tab Stop in Document Viewer and Build
This commit is contained in:
@@ -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
@@ -45,10 +45,9 @@ class ToHtml(Tokenizer):
|
||||
self.cssStyles = True
|
||||
|
||||
self.repDict = {
|
||||
"<" : "<",
|
||||
">" : ">",
|
||||
"&" : "&",
|
||||
"\t" : " "*2,
|
||||
"<" : "<",
|
||||
">" : ">",
|
||||
"&" : "&",
|
||||
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"] = " "*8
|
||||
self._buildRegEx()
|
||||
return
|
||||
|
||||
|
||||
+22
-2
@@ -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(" ", " "*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
@@ -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
@@ -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});"
|
||||
|
||||
Reference in New Issue
Block a user