Merge pull request #115 from vkbo/tweaks

GUI Tweaks
This commit is contained in:
Veronica K. Berglyd Olsen
2019-11-03 01:09:32 +01:00
committed by GitHub
16 changed files with 228 additions and 110 deletions
+30 -3
View File
@@ -62,6 +62,8 @@ class Config:
## General ## General
self.guiTheme = "default" self.guiTheme = "default"
self.guiSyntax = "default_light" self.guiSyntax = "default_light"
## Sizes
self.winGeometry = [1100, 650] self.winGeometry = [1100, 650]
self.treeColWidth = [120, 30, 50] self.treeColWidth = [120, 30, 50]
self.mainPanePos = [300, 800] self.mainPanePos = [300, 800]
@@ -74,7 +76,7 @@ class Config:
## Text Editor ## Text Editor
self.textFont = None self.textFont = None
self.textSize = 12 self.textSize = 12
self.textFixedW = False self.textFixedW = True
self.textWidth = 600 self.textWidth = 600
self.textMargin = 40 self.textMargin = 40
self.tabWidth = 40 self.tabWidth = 40
@@ -94,12 +96,16 @@ class Config:
self.spellLanguage = "en_GB" self.spellLanguage = "en_GB"
# Backup ## Backup
self.backupPath = "" self.backupPath = ""
self.backupOnClose = False self.backupOnClose = False
self.askBeforeBackup = True self.askBeforeBackup = True
# Path ## State
self.showRefPanel = True
self.viewComments = True
## Path
self.recentList = [""]*10 self.recentList = [""]*10
# Check Qt5 Versions # Check Qt5 Versions
@@ -244,6 +250,11 @@ class Config:
self.backupOnClose = self._parseLine(cnfParse, cnfSec, "backuponclose", self.CNF_BOOL, self.backupOnClose) self.backupOnClose = self._parseLine(cnfParse, cnfSec, "backuponclose", self.CNF_BOOL, self.backupOnClose)
self.askBeforeBackup = self._parseLine(cnfParse, cnfSec, "askbeforebackup", self.CNF_BOOL, self.askBeforeBackup) self.askBeforeBackup = self._parseLine(cnfParse, cnfSec, "askbeforebackup", self.CNF_BOOL, self.askBeforeBackup)
## State
cnfSec = "State"
self.showRefPanel = self._parseLine(cnfParse, cnfSec, "showrefpanel", self.CNF_BOOL, self.showRefPanel)
self.viewComments = self._parseLine(cnfParse, cnfSec, "viewcomments", self.CNF_BOOL, self.viewComments)
## Path ## Path
cnfSec = "Path" cnfSec = "Path"
self.lastPath = self._parseLine(cnfParse, cnfSec, "lastpath", self.CNF_STR, self.lastPath) self.lastPath = self._parseLine(cnfParse, cnfSec, "lastpath", self.CNF_STR, self.lastPath)
@@ -312,6 +323,12 @@ class Config:
cnfParse.set(cnfSec,"backuponclose", str(self.backupOnClose)) cnfParse.set(cnfSec,"backuponclose", str(self.backupOnClose))
cnfParse.set(cnfSec,"askbeforebackup",str(self.askBeforeBackup)) cnfParse.set(cnfSec,"askbeforebackup",str(self.askBeforeBackup))
## State
cnfSec = "State"
cnfParse.add_section(cnfSec)
cnfParse.set(cnfSec,"showrefpanel",str(self.showRefPanel))
cnfParse.set(cnfSec,"viewcomments",str(self.viewComments))
## Path ## Path
cnfSec = "Path" cnfSec = "Path"
cnfParse.add_section(cnfSec) cnfParse.add_section(cnfSec)
@@ -385,6 +402,16 @@ class Config:
self.confChanged = True self.confChanged = True
return True return True
def setShowRefPanel(self, checkState):
self.showRefPanel = checkState
self.confChanged = True
return
def setViewComments(self, checkState):
self.viewComments = checkState
self.confChanged = True
return
## ##
# Internal Functions # Internal Functions
## ##
+27
View File
@@ -32,6 +32,20 @@ class nwFiles():
# END Class nwFiles # 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"
# END Class nwKeyWords
class nwLabels(): class nwLabels():
CLASS_NAME = { CLASS_NAME = {
@@ -42,6 +56,7 @@ class nwLabels():
nwItemClass.WORLD : "Locations", nwItemClass.WORLD : "Locations",
nwItemClass.TIMELINE : "Timeline", nwItemClass.TIMELINE : "Timeline",
nwItemClass.OBJECT : "Objects", nwItemClass.OBJECT : "Objects",
nwItemClass.ENTITY : "Entity",
nwItemClass.CUSTOM : "Custom", nwItemClass.CUSTOM : "Custom",
nwItemClass.TRASH : "Trash", nwItemClass.TRASH : "Trash",
} }
@@ -53,6 +68,7 @@ class nwLabels():
nwItemClass.WORLD : "L", nwItemClass.WORLD : "L",
nwItemClass.TIMELINE : "T", nwItemClass.TIMELINE : "T",
nwItemClass.OBJECT : "O", nwItemClass.OBJECT : "O",
nwItemClass.ENTITY : "E",
nwItemClass.CUSTOM : "X", nwItemClass.CUSTOM : "X",
nwItemClass.TRASH : "R", nwItemClass.TRASH : "R",
} }
@@ -78,6 +94,17 @@ class nwLabels():
nwItemLayout.SCENE : "Sc", nwItemLayout.SCENE : "Sc",
nwItemLayout.NOTE : "Nt", 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 : "Time",
nwKeyWords.WORLD_KEY : "Locations",
nwKeyWords.OBJECT_KEY : "Objects",
nwKeyWords.ENTITY_KEY : "Entities",
nwKeyWords.CUSTOM_KEY : "Custom",
}
# END Class nwLabels # END Class nwLabels
+13 -16
View File
@@ -15,7 +15,7 @@ import re
import nw import nw
from nw.convert.tokenizer import Tokenizer from nw.convert.tokenizer import Tokenizer
from nw.constants import nwUnicode from nw.constants import nwUnicode, nwLabels
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -26,7 +26,7 @@ class ToHtml(Tokenizer):
self.forPreview = False self.forPreview = False
return return
def setPreview(self, forPreview): def setPreview(self, forPreview, doComments):
"""If we're using this class to generate markdown preview, we need to make a few changes to """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. formatting, which is selected by this flag.
""" """
@@ -34,6 +34,7 @@ class ToHtml(Tokenizer):
self.forPreview = forPreview self.forPreview = forPreview
if forPreview: if forPreview:
self.doKeywords = True self.doKeywords = True
self.doComments = doComments
return return
@@ -118,7 +119,7 @@ class ToHtml(Tokenizer):
thisPar.append(tTemp.rstrip()+" ") thisPar.append(tTemp.rstrip()+" ")
elif tType == self.T_COMMENT and self.doComments: elif tType == self.T_COMMENT and self.doComments:
self.theResult += "<div class='comment'>%s</div>\n" % tText self.theResult += self._formatComments(tText)
elif tType == self.T_KEYWORD and self.doKeywords: elif tType == self.T_KEYWORD and self.doKeywords:
self.theResult += self._formatTags(tText) self.theResult += self._formatTags(tText)
@@ -134,17 +135,6 @@ class ToHtml(Tokenizer):
if not self.forPreview: if not self.forPreview:
return "<pre>@%s</pre>\n" % tText return "<pre>@%s</pre>\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 tText = "@"+tText
isValid, theBits, thePos = self.theParent.theIndex.scanThis(tText) isValid, theBits, thePos = self.theParent.theIndex.scanThis(tText)
if not isValid or not theBits: if not isValid or not theBits:
@@ -152,8 +142,8 @@ class ToHtml(Tokenizer):
retText = "" retText = ""
refTags = [] refTags = []
if theBits[0] in theLabel: if theBits[0] in nwLabels.KEY_NAME:
retText += "<span class='tags'>%s:</span>&nbsp;" % theLabel[theBits[0]] retText += "<span class='tags'>%s:</span>&nbsp;" % nwLabels.KEY_NAME[theBits[0]]
for tTag in theBits[1:]: for tTag in theBits[1:]:
refTags.append("<a href='#%s=%s'>%s</a>" % ( refTags.append("<a href='#%s=%s'>%s</a>" % (
theBits[0][1:], tTag, tTag theBits[0][1:], tTag, tTag
@@ -162,4 +152,11 @@ class ToHtml(Tokenizer):
return "<div>%s</div>" % retText return "<div>%s</div>" % retText
def _formatComments(self, tText):
if not self.forPreview:
return "<div class='comment'>%s</div>\n" % tText
return "<p class='comment'>%s</p>\n" % tText
# END Class ToHtml # END Class ToHtml
+3 -2
View File
@@ -31,8 +31,9 @@ class nwItemClass(Enum):
WORLD = 4 WORLD = 4
TIMELINE = 5 TIMELINE = 5
OBJECT = 6 OBJECT = 6
CUSTOM = 7 ENTITY = 7
TRASH = 8 CUSTOM = 8
TRASH = 9
# END Enum nwItemClass # END Enum nwItemClass
+9 -9
View File
@@ -322,17 +322,17 @@ class GuiConfigEditEditor(QWidget):
self.textFlowForm = QGridLayout(self) self.textFlowForm = QGridLayout(self)
self.textFlow.setLayout(self.textFlowForm) self.textFlow.setLayout(self.textFlowForm)
self.textFlowFixed = QCheckBox("Fixed width",self) self.textFlowFixed = QCheckBox("Max text width",self)
self.textFlowFixed.setToolTip("Make text in editor fixed width and scale margins instead.") self.textFlowFixed.setToolTip("Maximum width of the text.")
if self.mainConf.textFixedW: if self.mainConf.textFixedW:
self.textFlowFixed.setCheckState(Qt.Checked) self.textFlowFixed.setCheckState(Qt.Checked)
else: else:
self.textFlowFixed.setCheckState(Qt.Unchecked) self.textFlowFixed.setCheckState(Qt.Unchecked)
self.textFlowWidth = QSpinBox(self) self.textFlowMax = QSpinBox(self)
self.textFlowWidth.setMinimum(300) self.textFlowMax.setMinimum(300)
self.textFlowWidth.setMaximum(10000) self.textFlowMax.setMaximum(10000)
self.textFlowWidth.setSingleStep(10) self.textFlowMax.setSingleStep(10)
self.textFlowWidth.setValue(self.mainConf.textWidth) self.textFlowMax.setValue(self.mainConf.textWidth)
self.textFlowJustify = QCheckBox("Justify text",self) self.textFlowJustify = QCheckBox("Justify text",self)
self.textFlowJustify.setToolTip("Justify text in main document editor.") self.textFlowJustify.setToolTip("Justify text in main document editor.")
@@ -342,7 +342,7 @@ class GuiConfigEditEditor(QWidget):
self.textFlowJustify.setCheckState(Qt.Unchecked) self.textFlowJustify.setCheckState(Qt.Unchecked)
self.textFlowForm.addWidget(self.textFlowFixed, 0, 0) self.textFlowForm.addWidget(self.textFlowFixed, 0, 0)
self.textFlowForm.addWidget(self.textFlowWidth, 0, 1) self.textFlowForm.addWidget(self.textFlowMax, 0, 1)
self.textFlowForm.addWidget(QLabel("px"), 0, 2) self.textFlowForm.addWidget(QLabel("px"), 0, 2)
self.textFlowForm.addWidget(self.textFlowJustify, 1, 0) self.textFlowForm.addWidget(self.textFlowJustify, 1, 0)
self.textFlowForm.setColumnStretch(4, 1) self.textFlowForm.setColumnStretch(4, 1)
@@ -519,7 +519,7 @@ class GuiConfigEditEditor(QWidget):
self.mainConf.textFont = textFont self.mainConf.textFont = textFont
self.mainConf.textSize = textSize self.mainConf.textSize = textSize
textWidth = self.textFlowWidth.value() textWidth = self.textFlowMax.value()
textFixedW = self.textFlowFixed.isChecked() textFixedW = self.textFlowFixed.isChecked()
doJustify = self.textFlowJustify.isChecked() doJustify = self.textFlowJustify.isChecked()
+17 -4
View File
@@ -16,9 +16,9 @@ import nw
from time import time from time import time
from PyQt5.QtCore import Qt, QTimer, QSizeF from PyQt5.QtCore import Qt, QTimer, QSizeF
from PyQt5.QtWidgets import qApp, QTextEdit, QAction, QMenu, QShortcut from PyQt5.QtWidgets import qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, QPalette, QTextDocument QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, QPalette, QTextDocument,
) )
from nw.project.document import NWDoc from nw.project.document import NWDoc
@@ -293,8 +293,8 @@ class GuiDocEditor(QTextEdit):
tW = self.mainConf.textWidth tW = self.mainConf.textWidth
wW = self.width() wW = self.width()
tM = int((wW - sW - tW)/2) tM = int((wW - sW - tW)/2)
if tM < 0: if tM < self.mainConf.textMargin:
tM = 0 tM = self.mainConf.textMargin
docFormat = self.qDocument.rootFrame().frameFormat() docFormat = self.qDocument.rootFrame().frameFormat()
docFormat.setLeftMargin(tM) docFormat.setLeftMargin(tM)
docFormat.setRightMargin(tM) docFormat.setRightMargin(tM)
@@ -332,6 +332,19 @@ class GuiDocEditor(QTextEdit):
def isEmpty(self): def isEmpty(self):
return self.qDocument.isEmpty() return self.qDocument.isEmpty()
def revealLocation(self):
if self.theHandle is not None:
msgBox = QMessageBox()
msgBox.information(self, "File Location", (
"File details for the currently open file<br>"
"Handle: {handle:s}<br>"
"Location: {fileLoc:s}"
).format(
handle = self.theHandle,
fileLoc = str(self.nwDocument.fileLoc)
))
return
## ##
# Document Events and Maintenance # Document Events and Maintenance
## ##
+36 -15
View File
@@ -18,7 +18,7 @@ from PyQt5.QtGui import QIcon, QFont, QColor
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication
from nw.project.item import NWItem from nw.project.item import NWItem
from nw.enum import nwItemType, nwItemClass, nwAlert from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
from nw.constants import nwLabels from nw.constants import nwLabels
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -62,9 +62,14 @@ class GuiDocTree(QTreeWidget):
self.setDragEnabled(True) self.setDragEnabled(True)
self.setDragDropMode(QAbstractItemView.InternalMove) self.setDragDropMode(QAbstractItemView.InternalMove)
# But don't allow drop on root level
trRoot = self.invisibleRootItem()
trRoot.setFlags(trRoot.flags() ^ Qt.ItemIsDropEnabled)
# Set Multiple Selection by CTRL # Set Multiple Selection by CTRL
self.setSelectionMode(QAbstractItemView.ExtendedSelection) # Disabled for now, until the merge files option has been added
self.setSelectionBehavior(QAbstractItemView.SelectRows) # self.setSelectionMode(QAbstractItemView.ExtendedSelection)
# self.setSelectionBehavior(QAbstractItemView.SelectRows)
for colN in range(len(self.mainConf.treeColWidth)): for colN in range(len(self.mainConf.treeColWidth)):
self.setColumnWidth(colN,self.mainConf.treeColWidth[colN]) self.setColumnWidth(colN,self.mainConf.treeColWidth[colN])
@@ -183,7 +188,7 @@ class GuiDocTree(QTreeWidget):
nIndex = tIndex + nStep nIndex = tIndex + nStep
if nIndex < 0 or nIndex >= nChild: if nIndex < 0 or nIndex >= nChild:
return False return False
cItem = self.takeTopLevelItem(tIndex) cItem = self.takeTopLevelItem(tIndex)
self.insertTopLevelItem(nIndex, cItem) self.insertTopLevelItem(nIndex, cItem)
else: else:
tIndex = pItem.indexOfChild(tItem) tIndex = pItem.indexOfChild(tItem)
@@ -191,7 +196,7 @@ class GuiDocTree(QTreeWidget):
nIndex = tIndex + nStep nIndex = tIndex + nStep
if nIndex < 0 or nIndex >= nChild: if nIndex < 0 or nIndex >= nChild:
return False return False
cItem = pItem.takeChild(tIndex) cItem = pItem.takeChild(tIndex)
pItem.insertChild(nIndex, cItem) pItem.insertChild(nIndex, cItem)
self.clearSelection() self.clearSelection()
cItem.setSelected(True) cItem.setSelected(True)
@@ -446,17 +451,28 @@ class GuiDocTree(QTreeWidget):
return return
def _updateItemParent(self, tHandle): def _updateItemParent(self, tHandle):
"""Update the parent handle of an item so that the information in the project is consistent
with the treeView. Also move the word count over to the new parent tree.
"""
trItemS = self._getTreeItem(tHandle) trItemS = self._getTreeItem(tHandle)
nwItemS = self.theProject.getItem(tHandle) nwItemS = self.theProject.getItem(tHandle)
trItemP = trItemS.parent() trItemP = trItemS.parent()
if trItemP is None: if trItemP is None:
logger.error("Failed to find new parent item of %s" % tHandle) logger.error("Failed to find new parent item of %s" % tHandle)
return return False
pHandle = trItemP.text(self.C_HANDLE) pHandle = trItemP.text(self.C_HANDLE)
wC = int(trItemS.text(self.C_COUNT))
self.propagateCount(tHandle, -wC)
nwItemS.setParent(pHandle) nwItemS.setParent(pHandle)
self.propagateCount(tHandle, wC)
self.setTreeItemValues(tHandle) self.setTreeItemValues(tHandle)
self.theProject.setProjectChanged(True) self.theProject.setProjectChanged(True)
return
logger.debug("The parent of item %s has been changed to %s" % (tHandle,pHandle))
return True
def _moveOrphanedItem(self, tHandle, dHandle): def _moveOrphanedItem(self, tHandle, dHandle):
trItemS = self._getTreeItem(tHandle) trItemS = self._getTreeItem(tHandle)
@@ -505,25 +521,30 @@ class GuiDocTree(QTreeWidget):
dnItem = self.theProject.getItem(dHandle) dnItem = self.theProject.getItem(dHandle)
isSame = snItem.itemClass == dnItem.itemClass isSame = snItem.itemClass == dnItem.itemClass
isNone = snItem.itemClass == nwItemClass.NO_CLASS isNone = snItem.itemClass == nwItemClass.NO_CLASS
isNote = snItem.itemLayout == nwItemLayout.NOTE
onFile = dnItem.itemType == nwItemType.FILE onFile = dnItem.itemType == nwItemType.FILE
isRoot = snItem.itemType == nwItemType.ROOT isRoot = snItem.itemType == nwItemType.ROOT
onRoot = dnItem.itemType == nwItemType.ROOT onRoot = dnItem.itemType == nwItemType.ROOT
isOnTop = self.dropIndicatorPosition() == QAbstractItemView.OnItem isOnTop = self.dropIndicatorPosition() == QAbstractItemView.OnItem
isAbove = self.dropIndicatorPosition() == QAbstractItemView.AboveItem if (isSame or isNone or isNote) and not (onFile and isOnTop) and not isRoot:
isBelow = self.dropIndicatorPosition() == QAbstractItemView.BelowItem logger.debug("Drag'n'drop of item %s accepted" % sHandle)
if (isSame or isNone) and not (onFile and isOnTop) and not isRoot:
logger.verbose("Drag'n'drop of item %s accepted" % sHandle)
QTreeWidget.dropEvent(self, theEvent) QTreeWidget.dropEvent(self, theEvent)
if isNone: if isNone:
self._moveOrphanedItem(sHandle, dHandle) self._moveOrphanedItem(sHandle, dHandle)
self._cleanOrphanedRoot() self._cleanOrphanedRoot()
else: else:
self._updateItemParent(sHandle) self._updateItemParent(sHandle)
elif isRoot and (isAbove or isBelow) and onRoot: if not isSame:
logger.verbose("Drag'n'drop of item %s accepted" % sHandle) logger.debug("Item %s class has been changed from %s to %s" % (
QTreeWidget.dropEvent(self, theEvent) sHandle,
snItem.itemClass.name,
dnItem.itemClass.name
))
snItem.setClass(dnItem.itemClass)
self.setTreeItemValues(sHandle)
else: else:
logger.verbose("Drag'n'drop of item %s not accepted" % sHandle) logger.debug("Drag'n'drop of item %s not accepted" % sHandle)
self.makeAlert("The item cannot be moved to that location.", nwAlert.ERROR)
return return
+14 -9
View File
@@ -105,7 +105,7 @@ class GuiDocViewer(QTextBrowser):
logger.debug("Generating preview for item %s" % tHandle) logger.debug("Generating preview for item %s" % tHandle)
sPos = self.verticalScrollBar().value() sPos = self.verticalScrollBar().value()
aDoc = ToHtml(self.theProject, self.theParent) aDoc = ToHtml(self.theProject, self.theParent)
aDoc.setPreview(True) aDoc.setPreview(True, self.mainConf.viewComments)
aDoc.setText(tHandle) aDoc.setText(tHandle)
aDoc.doAutoReplace() aDoc.doAutoReplace()
aDoc.tokenizeText() aDoc.tokenizeText()
@@ -117,10 +117,14 @@ class GuiDocViewer(QTextBrowser):
self.theHandle = tHandle self.theHandle = tHandle
self.theProject.setLastViewed(tHandle) self.theProject.setLastViewed(tHandle)
self.theParent.docMeta.refreshReferences(tHandle) self.theParent.viewMeta.refreshReferences(tHandle)
return True return True
def reloadText(self):
self.loadText(self.theHandle)
return
def loadFromTag(self, theTag): def loadFromTag(self, theTag):
logger.debug("Loading document from tag '%s'" % theTag) logger.debug("Loading document from tag '%s'" % theTag)
@@ -180,10 +184,6 @@ class GuiDocViewer(QTextBrowser):
"a {{" "a {{"
" color: rgb({aColR},{aColG},{aColB});" " color: rgb({aColR},{aColG},{aColB});"
"}}\n" "}}\n"
"pre {{"
" color: rgb({cColR},{cColG},{cColB});"
" font-size: {preSize:.1f}pt;"
"}}\n"
"mark {{" "mark {{"
" color: rgb({eColR},{eColG},{eColB});" " color: rgb({eColR},{eColG},{eColB});"
"}}\n" "}}\n"
@@ -197,6 +197,11 @@ class GuiDocViewer(QTextBrowser):
" color: rgb({kColR},{kColG},{kColB});" " color: rgb({kColR},{kColG},{kColB});"
" font-wright: bold;" " font-wright: bold;"
"}}\n" "}}\n"
".comment {{"
" color: rgb({cColR},{cColG},{cColB});"
" margin-left: 1em;"
" margin-right: 1em;"
"}}\n"
).format( ).format(
textSize = self.mainConf.textSize, textSize = self.mainConf.textSize,
preSize = self.mainConf.textSize*0.9, preSize = self.mainConf.textSize*0.9,
@@ -212,9 +217,9 @@ class GuiDocViewer(QTextBrowser):
eColR = self.theTheme.colEmph[0], eColR = self.theTheme.colEmph[0],
eColG = self.theTheme.colEmph[1], eColG = self.theTheme.colEmph[1],
eColB = self.theTheme.colEmph[2], eColB = self.theTheme.colEmph[2],
aColR = self.theTheme.colLink[0], aColR = self.theTheme.colVal[0],
aColG = self.theTheme.colLink[1], aColG = self.theTheme.colVal[1],
aColB = self.theTheme.colLink[2], aColB = self.theTheme.colVal[2],
kColR = self.theTheme.colKey[0], kColR = self.theTheme.colKey[0],
kColG = self.theTheme.colKey[1], kColG = self.theTheme.colKey[1],
kColB = self.theTheme.colKey[2], kColB = self.theTheme.colKey[2],
+6 -11
View File
@@ -6,7 +6,7 @@
Class holding the document view details panel Class holding the document view details panel
File History: File History:
Created: 2019-09-31 [0.3.2] Created: 2019-10-31 [0.3.2]
""" """
@@ -20,7 +20,7 @@ from PyQt5.QtWidgets import (
QSizePolicy, QCheckBox, QGridLayout QSizePolicy, QCheckBox, QGridLayout
) )
from nw.constants import nwLabels from nw.constants import nwLabels
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -48,7 +48,6 @@ class GuiDocViewDetails(QWidget):
self.showHide.setToolButtonStyle(Qt.ToolButtonIconOnly) self.showHide.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.showHide.setArrowType(Qt.DownArrow) self.showHide.setArrowType(Qt.DownArrow)
self.showHide.setCheckable(True) self.showHide.setCheckable(True)
self.showHide.setChecked(True)
self.showHide.setIconSize(QSize(16,16)) self.showHide.setIconSize(QSize(16,16))
self.showHide.toggled.connect(self._doShowHide) self.showHide.toggled.connect(self._doShowHide)
@@ -66,8 +65,7 @@ class GuiDocViewDetails(QWidget):
self.scrollBox.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scrollBox.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scrollBox.setFrameStyle(QFrame.NoFrame) self.scrollBox.setFrameStyle(QFrame.NoFrame)
self.scrollBox.setWidgetResizable(True) self.scrollBox.setWidgetResizable(True)
self.scrollBox.setMaximumHeight(300) self.scrollBox.setFixedHeight(80)
self.scrollBox.setMinimumHeight(60)
self.scrollBox.setWidget(self.refList) self.scrollBox.setWidget(self.refList)
self.outerBox.addWidget(self.showHide, 0, 0) self.outerBox.addWidget(self.showHide, 0, 0)
@@ -79,6 +77,8 @@ class GuiDocViewDetails(QWidget):
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self.setContentsMargins(0,0,0,0) self.setContentsMargins(0,0,0,0)
self._doShowHide(self.mainConf.showRefPanel)
logger.debug("DocViewDetails initialisation complete") logger.debug("DocViewDetails initialisation complete")
return return
@@ -91,12 +91,6 @@ class GuiDocViewDetails(QWidget):
return return
theRefs = self.theParent.theIndex.buildReferenceList(tHandle) theRefs = self.theParent.theIndex.buildReferenceList(tHandle)
if theRefs:
self.setVisible(True)
else:
self.setVisible(False)
return
theList = [] theList = []
for tHandle in theRefs: for tHandle in theRefs:
tItem = self.theProject.getItem(tHandle) tItem = self.theProject.getItem(tHandle)
@@ -120,6 +114,7 @@ class GuiDocViewDetails(QWidget):
def _doShowHide(self, chState): def _doShowHide(self, chState):
self.scrollBox.setVisible(chState) self.scrollBox.setVisible(chState)
self.mainConf.setShowRefPanel(chState)
if chState: if chState:
self.showHide.setArrowType(Qt.DownArrow) self.showHide.setArrowType(Qt.DownArrow)
else: else:
+25 -1
View File
@@ -112,6 +112,11 @@ class GuiMainMenu(QMenuBar):
self.toolsSpellCheck.setChecked(False) self.toolsSpellCheck.setChecked(False)
return True return True
def _toggleViewComments(self):
self.mainConf.setViewComments(self.docViewComments.isChecked())
self.theParent.docViewer.reloadText()
return True
def _showAbout(self): def _showAbout(self):
listPrefix = "&nbsp;&nbsp;&bull;&nbsp;&nbsp;" listPrefix = "&nbsp;&nbsp;&bull;&nbsp;&nbsp;"
aboutMsg = ( aboutMsg = (
@@ -163,6 +168,10 @@ class GuiMainMenu(QMenuBar):
self.updateRecentProjects() self.updateRecentProjects()
return True return True
def _showDocumentLocation(self):
self.theParent.docEditor.revealLocation()
return True
## ##
# Menu Builders # Menu Builders
## ##
@@ -235,6 +244,7 @@ class GuiMainMenu(QMenuBar):
self.rootItems[nwItemClass.WORLD] = QAction("Location Root", rootMenu) self.rootItems[nwItemClass.WORLD] = QAction("Location Root", rootMenu)
self.rootItems[nwItemClass.TIMELINE] = QAction("Timeline Root", rootMenu) self.rootItems[nwItemClass.TIMELINE] = QAction("Timeline Root", rootMenu)
self.rootItems[nwItemClass.OBJECT] = QAction("Object Root", rootMenu) self.rootItems[nwItemClass.OBJECT] = QAction("Object Root", rootMenu)
self.rootItems[nwItemClass.ENTITY] = QAction("Entity Root", rootMenu)
self.rootItems[nwItemClass.CUSTOM] = QAction("Custom Root", rootMenu) self.rootItems[nwItemClass.CUSTOM] = QAction("Custom Root", rootMenu)
nCount = 0 nCount = 0
for itemClass in self.rootItems.keys(): for itemClass in self.rootItems.keys():
@@ -330,10 +340,24 @@ class GuiMainMenu(QMenuBar):
menuItem.triggered.connect(self.theParent.closeDocViewer) menuItem.triggered.connect(self.theParent.closeDocViewer)
self.docuMenu.addAction(menuItem) self.docuMenu.addAction(menuItem)
# Document > Toggle View Comments
self.docViewComments = QAction("View Comments", self)
self.docViewComments.setStatusTip("Show comments in view panel")
self.docViewComments.setCheckable(True)
self.docViewComments.setChecked(self.mainConf.viewComments)
self.docViewComments.toggled.connect(self._toggleViewComments)
self.docuMenu.addAction(self.docViewComments)
# Document > Separator # Document > Separator
self.docuMenu.addSeparator() self.docuMenu.addSeparator()
# Document > Close Preview # Document > Show File Details
menuItem = QAction("Show File Details", self)
menuItem.setStatusTip("Shows a message box with the document location in the project folder")
menuItem.triggered.connect(self._showDocumentLocation)
self.docuMenu.addAction(menuItem)
# Document > Import From File
menuItem = QAction("Import from File", self) menuItem = QAction("Import from File", self)
menuItem.setStatusTip("Import document from a text or markdown file") menuItem.setStatusTip("Import document from a text or markdown file")
menuItem.setShortcut("Ctrl+Shift+I") menuItem.setShortcut("Ctrl+Shift+I")
+5 -5
View File
@@ -77,7 +77,7 @@ class GuiMain(QMainWindow):
self.noticeBar = GuiNoticeBar(self) self.noticeBar = GuiNoticeBar(self)
self.docEditor = GuiDocEditor(self, self.theProject) self.docEditor = GuiDocEditor(self, self.theProject)
self.docViewer = GuiDocViewer(self, self.theProject) self.docViewer = GuiDocViewer(self, self.theProject)
self.docMeta = GuiDocViewDetails(self, self.theProject) self.viewMeta = GuiDocViewDetails(self, self.theProject)
self.searchBar = GuiSearchBar(self) self.searchBar = GuiSearchBar(self)
self.treeMeta = GuiDocDetails(self, self.theProject) self.treeMeta = GuiDocDetails(self, self.theProject)
self.treeView = GuiDocTree(self, self.theProject) self.treeView = GuiDocTree(self, self.theProject)
@@ -107,7 +107,7 @@ class GuiMain(QMainWindow):
self.docView = QVBoxLayout() self.docView = QVBoxLayout()
self.docView.setContentsMargins(0,0,0,0) self.docView.setContentsMargins(0,0,0,0)
self.docView.addWidget(self.docViewer) self.docView.addWidget(self.docViewer)
self.docView.addWidget(self.docMeta) self.docView.addWidget(self.viewMeta)
self.docView.setStretch(0, 1) self.docView.setStretch(0, 1)
self.viewPane.setLayout(self.docView) self.viewPane.setLayout(self.docView)
@@ -313,7 +313,7 @@ class GuiMain(QMainWindow):
return True return True
def saveProject(self): def saveProject(self, isAuto=False):
"""Save the current project. """Save the current project.
""" """
if not self.hasProject: if not self.hasProject:
@@ -327,7 +327,7 @@ class GuiMain(QMainWindow):
return False return False
self.treeView.saveTreeOrder() self.treeView.saveTreeOrder()
self.theProject.saveProject() self.theProject.saveProject(isAuto)
self.theIndex.saveIndex() self.theIndex.saveIndex()
self.mainMenu.updateRecentProjects() self.mainMenu.updateRecentProjects()
@@ -703,7 +703,7 @@ class GuiMain(QMainWindow):
def _autoSaveProject(self): def _autoSaveProject(self):
if self.hasProject and self.theProject.projChanged and self.theProject.projPath is not None: if self.hasProject and self.theProject.projChanged and self.theProject.projPath is not None:
logger.debug("Autosaving project") logger.debug("Autosaving project")
self.saveProject() self.saveProject(isAuto=True)
return return
def _autoSaveDocument(self): def _autoSaveDocument(self):
+1 -3
View File
@@ -17,18 +17,16 @@ from os import path, mkdir, listdir
from shutil import make_archive from shutil import make_archive
from datetime import datetime from datetime import datetime
from nw.enum import nwAlert from nw.enum import nwAlert
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class NWBackup(): class NWBackup():
def __init__(self, theParent, theProject): def __init__(self, theParent, theProject):
self.mainConf = nw.CONFIG self.mainConf = nw.CONFIG
self.theParent = theParent self.theParent = theParent
self.theProject = theProject self.theProject = theProject
return return
def zipIt(self): def zipIt(self):
+3 -1
View File
@@ -31,6 +31,7 @@ class NWDoc():
self.theItem = None self.theItem = None
self.docHandle = None self.docHandle = None
self.docEditable = False self.docEditable = False
self.fileLoc = None
# Internal Mapping # Internal Mapping
self.makeAlert = self.theParent.makeAlert self.makeAlert = self.theParent.makeAlert
@@ -58,7 +59,8 @@ class NWDoc():
self.docEditable = False self.docEditable = False
docDir, docFile = self._assemblePath(self.FILE_MN) docDir, docFile = self._assemblePath(self.FILE_MN)
logger.debug("Opening document %s" % path.join(docDir,docFile)) self.fileLoc = path.join(docDir,docFile)
logger.debug("Opening document %s" % self.fileLoc)
dataDir = path.join(self.theProject.projPath, docDir) dataDir = path.join(self.theProject.projPath, docDir)
docPath = path.join(dataDir, docFile) docPath = path.join(dataDir, docFile)
+30 -27
View File
@@ -14,37 +14,37 @@ import logging
import json import json
import nw import nw
from os import path from os import path
from nw.project.document import NWDoc from nw.project.document import NWDoc
from nw.enum import nwItemType, nwItemClass, nwItemLayout from nw.enum import nwItemType, nwItemClass, nwItemLayout
from nw.constants import nwFiles from nw.constants import nwFiles, nwKeyWords
from nw.enum import nwAlert from nw.enum import nwAlert
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class NWIndex(): class NWIndex():
TAG_KEY = "@tag" VALID_KEYS = [
POV_KEY = "@pov" nwKeyWords.TAG_KEY,
CHAR_KEY = "@char" nwKeyWords.PLOT_KEY,
PLOT_KEY = "@plot" nwKeyWords.POV_KEY,
TIME_KEY = "@time" nwKeyWords.CHAR_KEY,
WORLD_KEY = "@location" nwKeyWords.WORLD_KEY,
OBJECT_KEY = "@object" nwKeyWords.TIME_KEY,
CUSTOM_KEY = "@custom" nwKeyWords.OBJECT_KEY,
nwKeyWords.ENTITY_KEY,
NOTE_KEYS = [TAG_KEY] nwKeyWords.CUSTOM_KEY
NOVEL_KEYS = [PLOT_KEY, POV_KEY, CHAR_KEY, WORLD_KEY, TIME_KEY, OBJECT_KEY, CUSTOM_KEY] ]
VALID_KEYS = [TAG_KEY, PLOT_KEY, POV_KEY, CHAR_KEY, WORLD_KEY, TIME_KEY, OBJECT_KEY, CUSTOM_KEY]
TAG_CLASS = { TAG_CLASS = {
CHAR_KEY : [nwItemClass.CHARACTER, 1], nwKeyWords.CHAR_KEY : [nwItemClass.CHARACTER, 1],
POV_KEY : [nwItemClass.CHARACTER, 2], nwKeyWords.POV_KEY : [nwItemClass.CHARACTER, 2],
PLOT_KEY : [nwItemClass.PLOT, 1], nwKeyWords.PLOT_KEY : [nwItemClass.PLOT, 1],
TIME_KEY : [nwItemClass.TIMELINE, 1], nwKeyWords.TIME_KEY : [nwItemClass.TIMELINE, 1],
WORLD_KEY : [nwItemClass.WORLD, 1], nwKeyWords.WORLD_KEY : [nwItemClass.WORLD, 1],
OBJECT_KEY : [nwItemClass.OBJECT, 1], nwKeyWords.OBJECT_KEY : [nwItemClass.OBJECT, 1],
CUSTOM_KEY : [nwItemClass.CUSTOM, 1], nwKeyWords.ENTITY_KEY : [nwItemClass.ENTITY, 1],
nwKeyWords.CUSTOM_KEY : [nwItemClass.CUSTOM, 1],
} }
def __init__(self, theProject, theParent): def __init__(self, theProject, theParent):
@@ -79,9 +79,13 @@ class NWIndex():
def deleteHandle(self, tHandle): def deleteHandle(self, tHandle):
delTags = []
for tTag in self.tagIndex: for tTag in self.tagIndex:
if self.tagIndex[tTag][1] == tHandle: if self.tagIndex[tTag][1] == tHandle:
self.tagIndex.pop(tTag, None) delTags.append(tTag)
for tTag in delTags:
self.tagIndex.pop(tTag, None)
self.refIndex.pop(tHandle, None) self.refIndex.pop(tHandle, None)
self.novelIndex.pop(tHandle, None) self.novelIndex.pop(tHandle, None)
@@ -275,10 +279,9 @@ class NWIndex():
if not isValid or len(theBits) == 0: if not isValid or len(theBits) == 0:
return False return False
theKey = theBits[0] if theBits[0] != nwKeyWords.TAG_KEY:
if theKey in self.NOVEL_KEYS:
for aVal in theBits[1:]: for aVal in theBits[1:]:
self.refIndex[tHandle].append([nLine, theKey, aVal, nTitle]) self.refIndex[tHandle].append([nLine, theBits[0], aVal, nTitle])
return True return True
@@ -290,7 +293,7 @@ class NWIndex():
if not isValid or len(theBits) != 2: if not isValid or len(theBits) != 2:
return False return False
if theBits[0] == self.TAG_KEY: if theBits[0] == nwKeyWords.TAG_KEY:
self.tagIndex[theBits[1]] = [nLine, tHandle, itemClass.name] self.tagIndex[theBits[1]] = [nLine, tHandle, itemClass.name]
return True return True
@@ -355,7 +358,7 @@ class NWIndex():
return isGood return isGood
# If we have a tag, only the first value is accepted, the rest is ignored # If we have a tag, only the first value is accepted, the rest is ignored
if theBits[0] == self.TAG_KEY and nBits > 1: if theBits[0] == nwKeyWords.TAG_KEY and nBits > 1:
isGood[0] = True isGood[0] = True
if theBits[1] in self.tagIndex.keys(): if theBits[1] in self.tagIndex.keys():
if self.tagIndex[theBits[1]][1] == tItem.itemHandle: if self.tagIndex[theBits[1]][1] == tItem.itemHandle:
+3 -2
View File
@@ -280,7 +280,7 @@ class NWProject():
return True return True
def saveProject(self): def saveProject(self, isAuto=False):
if self.projPath is None: if self.projPath is None:
self.makeAlert("Project path not set, cannot save.", nwAlert.ERROR) self.makeAlert("Project path not set, cannot save.", nwAlert.ERROR)
@@ -296,7 +296,8 @@ class NWProject():
logger.debug("Saving project: %s" % self.projPath) logger.debug("Saving project: %s" % self.projPath)
# Save a copy of the current file, just in case # Save a copy of the current file, just in case
self._maintainPrevious() if not isAuto:
self._maintainPrevious()
# Root element and project details # Root element and project details
logger.debug("Writing project meta") logger.debug("Writing project meta")
+6 -2
View File
@@ -1,5 +1,5 @@
[Main] [Main]
timestamp = 2019-10-29 19:20:27 timestamp = 2019-11-03 00:40:02
theme = default theme = default
syntax = default_light syntax = default_light
@@ -16,7 +16,7 @@ autosavedoc = 30
[Editor] [Editor]
textfont = None textfont = None
textsize = 12 textsize = 12
fixedwidth = False fixedwidth = True
width = 600 width = 600
margin = 40 margin = 40
tabwidth = 40 tabwidth = 40
@@ -38,6 +38,10 @@ backuppath =
backuponclose = False backuponclose = False
askbeforebackup = True askbeforebackup = True
[State]
showrefpanel = True
viewcomments = True
[Path] [Path]
lastpath = lastpath =
recent0 = recent0 =