diff --git a/nw/convert/text/tohtml.py b/nw/convert/text/tohtml.py
index 64ddbbb7..3a67df48 100644
--- a/nw/convert/text/tohtml.py
+++ b/nw/convert/text/tohtml.py
@@ -23,6 +23,18 @@ class ToHtml(Tokenizer):
def __init__(self, theProject, theParent):
Tokenizer.__init__(self, theProject, theParent)
+ self.forPreview = False
+ return
+
+ def setPreview(self, forPreview):
+ """If we're using this class to generate markdown preview, we need to make a few changes to
+ formatting, which is selected by this flag.
+ """
+
+ self.forPreview = forPreview
+ if forPreview:
+ self.doKeywords = True
+
return
def doAutoReplace(self):
@@ -103,10 +115,45 @@ class ToHtml(Tokenizer):
self.theResult += "
\n" % tText
elif tType == self.T_KEYWORD and self.doKeywords:
- self.theResult += "@%s
\n" % tText
-
- # print(self.theResult)
+ self.theResult += self._formatTags(tText)
return
+ ##
+ # Internal Functions
+ ##
+
+ def _formatTags(self, tText):
+
+ if not self.forPreview:
+ return "@%s
\n" % tText
+
+ theLabel = {
+ "@tag" : "Tag",
+ "@pov" : "Point of View",
+ "@char" : "Character(s)",
+ "@plot" : "Plot",
+ "@time" : "Time",
+ "@location" : "Location(s)",
+ "@object" : "Object(s)",
+ "@custom" : "Custom",
+ }
+
+ tText = "@"+tText
+ isValid, theBits, thePos = self.theParent.theIndex.scanThis(tText)
+ if not isValid or not theBits:
+ return ""
+
+ retText = ""
+ refTags = []
+ if theBits[0] in theLabel:
+ retText += "%s: " % theLabel[theBits[0]]
+ for tTag in theBits[1:]:
+ refTags.append("%s" % (
+ theBits[0][1:], tTag, tTag
+ ))
+ retText += ", ".join(refTags)
+
+ return "%s
" % retText
+
# END Class ToHtml
diff --git a/nw/gui/elements/docviewer.py b/nw/gui/elements/docviewer.py
index 39342036..b669b2d2 100644
--- a/nw/gui/elements/docviewer.py
+++ b/nw/gui/elements/docviewer.py
@@ -19,7 +19,7 @@ from PyQt5.QtGui import QTextOption, QFont, QPalette, QColor
from nw.convert.tokenizer import Tokenizer
from nw.convert.text.tohtml import ToHtml
-from nw.enum import nwItemType
+from nw.enum import nwAlert, nwItemType
logger = logging.getLogger(__name__)
@@ -46,6 +46,8 @@ class GuiDocViewer(QTextBrowser):
theOpt.setAlignment(Qt.AlignJustify)
self.qDocument.setDefaultTextOption(theOpt)
+ self.anchorClicked.connect(self._linkClicked)
+
logger.debug("DocViewer initialisation complete")
return
@@ -102,6 +104,7 @@ class GuiDocViewer(QTextBrowser):
logger.debug("Generating preview for item %s" % tHandle)
sPos = self.verticalScrollBar().value()
aDoc = ToHtml(self.theProject, self.theParent)
+ aDoc.setPreview(True)
aDoc.setText(tHandle)
aDoc.doAutoReplace()
aDoc.tokenizeText()
@@ -113,6 +116,8 @@ class GuiDocViewer(QTextBrowser):
self.theHandle = tHandle
self.theProject.setLastViewed(tHandle)
+ self.theParent.docMeta.refreshReferences(tHandle)
+
return True
def loadFromTag(self, theTag):
@@ -137,22 +142,59 @@ class GuiDocViewer(QTextBrowser):
# Internal Functions
##
+ def _linkClicked(self, theURL):
+
+ theLink = theURL.url()
+ tHandle = None
+ onLine = 0
+ theTag = ""
+ if len(theLink) > 0:
+ theBits = theLink.split("=")
+ if len(theBits) == 2:
+ theTag = theBits[1]
+ tHandle, onLine = self.theParent.theIndex.getTagSource(theBits[1])
+
+ if tHandle is None:
+ self.theParent.makeAlert((
+ "Could not find the reference for tag '%s'. It either doesn't exist, or the index "
+ "is out of date. The index can be updated from the Tools menu.") % theTag,
+ nwAlert.ERROR
+ )
+ return
+ else:
+ self.loadText(tHandle)
+
+ return
+
def _makeStyleSheet(self):
- self.qDocument.setDefaultStyleSheet((
+ styleSheet = (
"body {{"
- " font-size: {textSize}pt;"
+ " font-size: {textSize:.1f}pt;"
" color: rgb({tColR},{tColG},{tColB});"
"}}\n"
- "h1, h2, h3, h4 {{"
+ "h1 {{"
" color: rgb({hColR},{hColG},{hColB});"
+ " font-size: {h1Size:.1f}pt;"
+ "}}\n"
+ "h2 {{"
+ " color: rgb({hColR},{hColG},{hColB});"
+ " font-size: {h2Size:.1f}pt;"
+ "}}\n"
+ "h3 {{"
+ " color: rgb({hColR},{hColG},{hColB});"
+ " font-size: {h3Size:.1f}pt;"
+ "}}\n"
+ "h4 {{"
+ " color: rgb({hColR},{hColG},{hColB});"
+ " font-size: {h4Size:.1f}pt;"
"}}\n"
"a {{"
" color: rgb({aColR},{aColG},{aColB});"
"}}\n"
"pre {{"
" color: rgb({cColR},{cColG},{cColB});"
- " font-size: {preSize}pt;"
+ " font-size: {preSize:.1f}pt;"
"}}\n"
"mark {{"
" color: rgb({eColR},{eColG},{eColB});"
@@ -163,9 +205,17 @@ class GuiDocViewer(QTextBrowser):
"td {{"
" padding: 0px 4px;"
"}}\n"
+ ".tags {{"
+ " color: rgb({kColR},{kColG},{kColB});"
+ " font-wright: bold;"
+ "}}\n"
).format(
textSize = self.mainConf.textSize,
preSize = self.mainConf.textSize*0.9,
+ h1Size = self.mainConf.textSize*1.8,
+ h2Size = self.mainConf.textSize*1.6,
+ h3Size = self.mainConf.textSize*1.4,
+ h4Size = self.mainConf.textSize*1.2,
tColR = self.theTheme.colText[0],
tColG = self.theTheme.colText[1],
tColB = self.theTheme.colText[2],
@@ -181,7 +231,11 @@ class GuiDocViewer(QTextBrowser):
aColR = self.theTheme.colLink[0],
aColG = self.theTheme.colLink[1],
aColB = self.theTheme.colLink[2],
- ))
+ kColR = self.theTheme.colKey[0],
+ kColG = self.theTheme.colKey[1],
+ kColB = self.theTheme.colKey[2],
+ )
+ self.qDocument.setDefaultStyleSheet(styleSheet)
return True
diff --git a/nw/gui/elements/viewdetails.py b/nw/gui/elements/viewdetails.py
new file mode 100644
index 00000000..38f1260c
--- /dev/null
+++ b/nw/gui/elements/viewdetails.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+"""novelWriter GUI DocView Details
+
+ novelWriter – GUI DocView Details
+===================================
+ Class holding the document view details panel
+
+ File History:
+ Created: 2019-09-31 [0.3.2]
+
+"""
+
+import logging
+import nw
+
+from PyQt5.QtGui import QFont
+from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QGroupBox, QComboBox
+
+from nw.constants import nwLabels
+
+logger = logging.getLogger(__name__)
+
+class GuiDocViewDetails(QWidget):
+
+ def __init__(self, theParent, theProject):
+ QWidget.__init__(self, theParent)
+
+ logger.debug("Initialising DocViewDetails ...")
+ self.mainConf = nw.CONFIG
+ self.debugGUI = self.mainConf.debugGUI
+ self.theParent = theParent
+ self.theProject = theProject
+
+ self.outerBox = QHBoxLayout(self)
+ self.outerBox.setContentsMargins(4,4,4,4)
+
+ self.refTags = QGroupBox("Referenced From", self)
+ self.refTagsForm = QHBoxLayout(self.refTags)
+ self.refTags.setLayout(self.refTagsForm)
+
+ self.refList = QLabel("None")
+ self.refList.linkActivated.connect(self._linkClicked)
+
+ self.refTagsForm.addWidget(self.refList)
+ self.outerBox.addWidget(self.refTags)
+ self.setLayout(self.outerBox)
+ self.setContentsMargins(0,0,0,0)
+
+ logger.debug("DocViewDetails initialisation complete")
+
+ return
+
+ def refreshReferences(self, tHandle):
+
+ theRefs = self.theParent.theIndex.buildReferenceList(tHandle)
+ if theRefs:
+ self.setVisible(True)
+ else:
+ self.setVisible(False)
+ return
+
+ theList = []
+ for tHandle in theRefs:
+ tItem = self.theProject.getItem(tHandle)
+ if tItem is not None:
+ theList.append("%s" % (tHandle,tItem.itemName))
+
+ self.refList.setText(", ".join(theList))
+
+ return
+
+ ##
+ # Internal Functions
+ ##
+
+ def _linkClicked(self, theLink):
+ if len(theLink) == 18:
+ tHandle = theLink[-13:]
+ self.theParent.viewDocument(tHandle)
+ return
+
+# END Class GuiDocViewDetails
diff --git a/nw/gui/statusbar.py b/nw/gui/statusbar.py
index d69f50ee..cbd02b70 100644
--- a/nw/gui/statusbar.py
+++ b/nw/gui/statusbar.py
@@ -25,7 +25,7 @@ class GuiMainStatus(QStatusBar):
def __init__(self, theParent):
QStatusBar.__init__(self, theParent)
- logger.debug("Initialising GuiMainStatus ...")
+ logger.debug("Initialising MainStatus ...")
self.mainConf = nw.CONFIG
self.theParent = theParent
@@ -80,7 +80,7 @@ class GuiMainStatus(QStatusBar):
self.sessionTimer.timeout.connect(self._updateTime)
self.sessionTimer.start()
- logger.debug("GuiMainStatus initialisation complete")
+ logger.debug("MainStatus initialisation complete")
self.clearStatus()
diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py
index a45c9067..6c70e981 100644
--- a/nw/gui/winmain.py
+++ b/nw/gui/winmain.py
@@ -31,6 +31,7 @@ from nw.gui.elements.docviewer import GuiDocViewer
from nw.gui.elements.docdetails import GuiDocDetails
from nw.gui.elements.searchbar import GuiSearchBar
from nw.gui.elements.noticebar import GuiNoticeBar
+from nw.gui.elements.viewdetails import GuiDocViewDetails
from nw.gui.dialogs.configeditor import GuiConfigEditor
from nw.gui.dialogs.projecteditor import GuiProjectEditor
from nw.gui.dialogs.export import GuiExport
@@ -72,14 +73,15 @@ class GuiMain(QMainWindow):
self.setWindowIcon(QIcon(path.join(self.mainConf.appIcon)))
# Main GUI Elements
- self.statusBar = GuiMainStatus(self)
- self.noticeBar = GuiNoticeBar(self)
- self.docEditor = GuiDocEditor(self, self.theProject)
- self.docViewer = GuiDocViewer(self, self.theProject)
- self.docDetails = GuiDocDetails(self, self.theProject)
- self.searchBar = GuiSearchBar(self)
- self.treeView = GuiDocTree(self, self.theProject)
- self.mainMenu = GuiMainMenu(self, self.theProject)
+ self.statusBar = GuiMainStatus(self)
+ self.noticeBar = GuiNoticeBar(self)
+ self.docEditor = GuiDocEditor(self, self.theProject)
+ self.docViewer = GuiDocViewer(self, self.theProject)
+ self.docMeta = GuiDocViewDetails(self, self.theProject)
+ self.searchBar = GuiSearchBar(self)
+ self.treeMeta = GuiDocDetails(self, self.theProject)
+ self.treeView = GuiDocTree(self, self.theProject)
+ self.mainMenu = GuiMainMenu(self, self.theProject)
# Minor Gui Elements
self.statusIcons = []
@@ -90,20 +92,27 @@ class GuiMain(QMainWindow):
self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0,0,0,0)
self.treeBox.addWidget(self.treeView)
- self.treeBox.addWidget(self.docDetails)
+ self.treeBox.addWidget(self.treeMeta)
self.treePane.setLayout(self.treeBox)
- self.docPane = QFrame()
+ self.editPane = QFrame()
+ self.docEdit = QVBoxLayout()
+ self.docEdit.setContentsMargins(0,0,0,0)
+ self.docEdit.addWidget(self.searchBar)
+ self.docEdit.addWidget(self.noticeBar)
+ self.docEdit.addWidget(self.docEditor)
+ self.editPane.setLayout(self.docEdit)
+
+ self.viewPane = QFrame()
self.docView = QVBoxLayout()
self.docView.setContentsMargins(0,0,0,0)
- self.docView.addWidget(self.searchBar)
- self.docView.addWidget(self.noticeBar)
- self.docView.addWidget(self.docEditor)
- self.docPane.setLayout(self.docView)
+ self.docView.addWidget(self.docViewer)
+ self.docView.addWidget(self.docMeta)
+ self.viewPane.setLayout(self.docView)
self.splitView = QSplitter(Qt.Horizontal)
- self.splitView.addWidget(self.docPane)
- self.splitView.addWidget(self.docViewer)
+ self.splitView.addWidget(self.editPane)
+ self.splitView.addWidget(self.viewPane)
self.splitView.splitterMoved.connect(self._splitViewMove)
self.splitMain = QSplitter(Qt.Horizontal)
@@ -117,15 +126,15 @@ class GuiMain(QMainWindow):
self.idxTree = self.splitMain.indexOf(self.treePane)
self.idxMain = self.splitMain.indexOf(self.splitView)
- self.idxEditor = self.splitView.indexOf(self.docPane)
- self.idxViewer = self.splitView.indexOf(self.docViewer)
+ self.idxEditor = self.splitView.indexOf(self.editPane)
+ self.idxViewer = self.splitView.indexOf(self.viewPane)
self.splitMain.setCollapsible(self.idxTree, False)
self.splitMain.setCollapsible(self.idxMain, False)
self.splitView.setCollapsible(self.idxEditor, False)
self.splitView.setCollapsible(self.idxViewer, True)
- self.docViewer.setVisible(False)
+ self.viewPane.setVisible(False)
self.searchBar.setVisible(False)
# Build The Tree View
@@ -365,9 +374,9 @@ class GuiMain(QMainWindow):
logger.debug("No document selected, giving up")
return False
- if self.docViewer.loadText(tHandle) and not self.docViewer.isVisible():
+ if self.docViewer.loadText(tHandle) and not self.viewPane.isVisible():
bPos = self.splitMain.sizes()
- self.docViewer.setVisible(True)
+ self.viewPane.setVisible(True)
vPos = [0,0]
vPos[0] = int(bPos[1]/2)
vPos[1] = bPos[1]-vPos[0]
@@ -669,11 +678,11 @@ class GuiMain(QMainWindow):
self.docViewer.clearViewer()
self.theProject.setLastViewed(None)
bPos = self.splitMain.sizes()
- self.docViewer.setVisible(False)
+ self.viewPane.setVisible(False)
vPos = [bPos[1],0]
self.splitView.setSizes(vPos)
self.docEditor.changeWidth()
- return not self.docViewer.isVisible()
+ return not self.viewPane.isVisible()
##
# Internal Functions
@@ -739,7 +748,7 @@ class GuiMain(QMainWindow):
def _treeSingleClick(self):
sHandle = self.treeView.getSelectedHandle()
if sHandle is not None:
- self.docDetails.buildViewBox(sHandle)
+ self.treeMeta.buildViewBox(sHandle)
return
def _treeDoubleClick(self, tItem, colNo):
diff --git a/nw/project/index.py b/nw/project/index.py
index a55bf14e..86236a61 100644
--- a/nw/project/index.py
+++ b/nw/project/index.py
@@ -319,6 +319,35 @@ class NWIndex():
return True
+ def buildReferenceList(self, theHandle):
+
+ theRefs = {}
+
+ tItem = self.theProject.getItem(theHandle)
+ if theHandle is None:
+ return theRefs
+
+ theTag = None
+ for tTag in self.tagIndex:
+ if theHandle == self.tagIndex[tTag][1]:
+ theTag = tTag
+ break
+
+ if theTag is not None:
+ for tHandle in self.refIndex:
+ for nLine, tKey, tTag, nTitle in self.refIndex[tHandle]:
+ if tTag == theTag:
+ theRefs[tHandle] = nLine
+
+ return theRefs
+
+ def getTagSource(self, theTag):
+ if theTag in self.tagIndex:
+ theRef = self.tagIndex[theTag]
+ if len(theRef) == 3:
+ return theRef[1], theRef[0]
+ return None, 0
+
def buildTagNovelMap(self, theTags, theFilters=None):
tagMap = {}