Merge pull request #21 from vkbo/improvements

Improvements
This commit is contained in:
Veronica K. Berglyd Olsen
2019-05-26 17:14:37 +02:00
committed by GitHub
21 changed files with 397 additions and 305 deletions
+94 -102
View File
@@ -25,6 +25,11 @@ class Config:
WIN_WIDTH = 0 WIN_WIDTH = 0
WIN_HEIGHT = 1 WIN_HEIGHT = 1
CNF_STR = 0
CNF_INT = 1
CNF_BOOL = 2
CNF_LIST = 3
def __init__(self): def __init__(self):
# Set Application Variables # Set Application Variables
@@ -38,6 +43,7 @@ class Config:
self.confFile = None self.confFile = None
self.homePath = None self.homePath = None
self.appPath = None self.appPath = None
self.appRoot = None
self.guiPath = None self.guiPath = None
self.themePath = None self.themePath = None
@@ -60,6 +66,7 @@ class Config:
self.textWidth = 600 self.textWidth = 600
self.textMargin = [40, 40] self.textMargin = [40, 40]
self.textSize = 13 self.textSize = 13
self.tabWidth = 40
self.doJustify = True self.doJustify = True
self.autoSelect = True self.autoSelect = True
self.doReplace = True self.doReplace = True
@@ -68,7 +75,7 @@ class Config:
self.doReplaceDash = True self.doReplaceDash = True
self.doReplaceDots = True self.doReplaceDots = True
self.wordCountTimer = 5.0 self.wordCountTimer = 5.0
self.fmtDoubleQuotes = ["",""] self.fmtDoubleQuotes = ["",""]
self.fmtSingleQuotes = ["",""] self.fmtSingleQuotes = ["",""]
self.fmtApostrophe = "" self.fmtApostrophe = ""
@@ -95,6 +102,7 @@ class Config:
self.confFile = self.appHandle+".conf" self.confFile = self.appHandle+".conf"
self.homePath = path.expanduser("~") self.homePath = path.expanduser("~")
self.appPath = path.dirname(__file__) self.appPath = path.dirname(__file__)
self.appRoot = path.join(self.appPath,path.pardir)
self.guiPath = path.join(self.appPath,"gui") self.guiPath = path.join(self.appPath,"gui")
self.themePath = path.join(self.appPath,"themes") self.themePath = path.join(self.appPath,"themes")
@@ -117,140 +125,105 @@ class Config:
def loadConfig(self): def loadConfig(self):
logger.debug("Loading config file") logger.debug("Loading config file")
confParser = configparser.ConfigParser() cnfParse = configparser.ConfigParser()
try: try:
confParser.read_file(open(path.join(self.confPath,self.confFile))) cnfParse.read_file(open(path.join(self.confPath,self.confFile)))
except Exception as e: except Exception as e:
logger.error("Could not load config file") logger.error("Could not load config file")
return False return False
# Get options
## Main ## Main
cnfSec = "Main" cnfSec = "Main"
if confParser.has_section(cnfSec): self.guiTheme = self._parseLine(cnfParse, cnfSec, "theme", self.CNF_STR, self.guiTheme)
if confParser.has_option(cnfSec,"theme"):
self.guiTheme = confParser.get(cnfSec,"theme")
## Sizes ## Sizes
cnfSec = "Sizes" cnfSec = "Sizes"
if confParser.has_section(cnfSec): self.winGeometry = self._parseLine(cnfParse, cnfSec, "geometry", self.CNF_LIST, self.winGeometry)
if confParser.has_option(cnfSec,"geometry"): self.treeColWidth = self._parseLine(cnfParse, cnfSec, "treecols", self.CNF_LIST, self.treeColWidth)
self.winGeometry = self.unpackList( self.mainPanePos = self._parseLine(cnfParse, cnfSec, "mainpane", self.CNF_LIST, self.mainPanePos)
confParser.get(cnfSec,"geometry"), 2, self.winGeometry self.docPanePos = self._parseLine(cnfParse, cnfSec, "docpane", self.CNF_LIST, self.docPanePos)
)
if confParser.has_option(cnfSec,"treecols"):
self.treeColWidth = self.unpackList(
confParser.get(cnfSec,"treecols"), 3, self.treeColWidth
)
if confParser.has_option(cnfSec,"mainpane"):
self.mainPanePos = self.unpackList(
confParser.get(cnfSec,"mainpane"), 2, self.mainPanePos
)
if confParser.has_option(cnfSec,"docpane"):
self.docPanePos = self.unpackList(
confParser.get(cnfSec,"docpane"), 2, self.docPanePos
)
## Project ## Project
cnfSec = "Project" cnfSec = "Project"
if confParser.has_section(cnfSec): self.autoSaveProj = self._parseLine(cnfParse, cnfSec, "autosaveproject", self.CNF_INT, self.autoSaveProj)
if confParser.has_option(cnfSec,"autosaveproject"): self.autoSaveDoc = self._parseLine(cnfParse, cnfSec, "autosavedoc", self.CNF_INT, self.autoSaveDoc)
self.autoSaveProj = confParser.getint(cnfSec,"autosaveproject")
if confParser.has_option(cnfSec,"autosavedoc"):
self.autoSaveDoc = confParser.getint(cnfSec,"autosavedoc")
## Editor ## Editor
cnfSec = "Editor" cnfSec = "Editor"
if confParser.has_section(cnfSec): self.textFixedW = self._parseLine(cnfParse, cnfSec, "fixedwidth", self.CNF_BOOL, self.textFixedW)
if confParser.has_option(cnfSec,"fixedwidth"): self.textWidth = self._parseLine(cnfParse, cnfSec, "width", self.CNF_INT, self.textWidth)
self.textFixedW = confParser.getboolean(cnfSec,"fixedwidth") self.textMargin = self._parseLine(cnfParse, cnfSec, "margins", self.CNF_LIST, self.textMargin)
if confParser.has_option(cnfSec,"width"): self.textSize = self._parseLine(cnfParse, cnfSec, "textsize", self.CNF_INT, self.textSize)
self.textWidth = confParser.getint(cnfSec,"width") self.tabWidth = self._parseLine(cnfParse, cnfSec, "tabwidth", self.CNF_INT, self.tabWidth)
if confParser.has_option(cnfSec,"margins"): self.doJustify = self._parseLine(cnfParse, cnfSec, "justify", self.CNF_BOOL, self.doJustify)
self.textMargin = self.unpackList( self.autoSelect = self._parseLine(cnfParse, cnfSec, "autoselect", self.CNF_BOOL, self.autoSelect)
confParser.get(cnfSec,"margins"), 2, self.textMargin self.doReplace = self._parseLine(cnfParse, cnfSec, "autoreplace", self.CNF_BOOL, self.doReplace)
) self.doReplaceSQuote = self._parseLine(cnfParse, cnfSec, "repsquotes", self.CNF_BOOL, self.doReplaceSQuote)
if confParser.has_option(cnfSec,"textsize"): self.doReplaceDQuote = self._parseLine(cnfParse, cnfSec, "repdquotes", self.CNF_BOOL, self.doReplaceDQuote)
self.textSize = confParser.getint(cnfSec,"textsize") self.doReplaceDash = self._parseLine(cnfParse, cnfSec, "repdash", self.CNF_BOOL, self.doReplaceDash)
if confParser.has_option(cnfSec,"justify"): self.doReplaceDots = self._parseLine(cnfParse, cnfSec, "repdots", self.CNF_BOOL, self.doReplaceDots)
self.doJustify = confParser.getboolean(cnfSec,"justify") self.spellLanguage = self._parseLine(cnfParse, cnfSec, "spellcheck", self.CNF_STR, self.spellLanguage)
if confParser.has_option(cnfSec,"autoselect"):
self.autoSelect = confParser.getboolean(cnfSec,"autoselect")
if confParser.has_option(cnfSec,"autoreplace"):
self.doReplace = confParser.getboolean(cnfSec,"autoreplace")
if confParser.has_option(cnfSec,"repsquotes"):
self.doReplaceSQuote = confParser.getboolean(cnfSec,"repsquotes")
if confParser.has_option(cnfSec,"repdquotes"):
self.doReplaceDQuote = confParser.getboolean(cnfSec,"repdquotes")
if confParser.has_option(cnfSec,"repdash"):
self.doReplaceDash = confParser.getboolean(cnfSec,"repdash")
if confParser.has_option(cnfSec,"repdots"):
self.doReplaceDots = confParser.getboolean(cnfSec,"repdots")
if confParser.has_option(cnfSec,"spellcheck"):
self.spellLanguage = confParser.get(cnfSec,"spellcheck")
## Path ## Path
cnfSec = "Path" cnfSec = "Path"
if confParser.has_section(cnfSec): for i in range(10):
for i in range(10): self.recentList[i] = self._parseLine(cnfParse, cnfSec, "recent%d" % i,self.CNF_STR, self.recentList[i])
if confParser.has_option(cnfSec,"recent%d" % i):
self.recentList[i] = confParser.get(cnfSec,"recent%d" % i)
return True return True
def saveConfig(self): def saveConfig(self):
logger.debug("Saving config file") logger.debug("Saving config file")
confParser = configparser.ConfigParser() cnfParse = configparser.ConfigParser()
# Set options # Set options
## Main ## Main
cnfSec = "Main" cnfSec = "Main"
confParser.add_section(cnfSec) cnfParse.add_section(cnfSec)
confParser.set(cnfSec,"timestamp", datetime.now().strftime("%Y-%m-%d %H:%M:%S")) cnfParse.set(cnfSec,"timestamp", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
confParser.set(cnfSec,"theme", str(self.guiTheme)) cnfParse.set(cnfSec,"theme", str(self.guiTheme))
## Sizes ## Sizes
cnfSec = "Sizes" cnfSec = "Sizes"
confParser.add_section(cnfSec) cnfParse.add_section(cnfSec)
confParser.set(cnfSec,"geometry", self.packList(self.winGeometry)) cnfParse.set(cnfSec,"geometry", self._packList(self.winGeometry))
confParser.set(cnfSec,"treecols", self.packList(self.treeColWidth)) cnfParse.set(cnfSec,"treecols", self._packList(self.treeColWidth))
confParser.set(cnfSec,"mainpane", self.packList(self.mainPanePos)) cnfParse.set(cnfSec,"mainpane", self._packList(self.mainPanePos))
confParser.set(cnfSec,"docpane", self.packList(self.docPanePos)) cnfParse.set(cnfSec,"docpane", self._packList(self.docPanePos))
## Project ## Project
cnfSec = "Project" cnfSec = "Project"
confParser.add_section(cnfSec) cnfParse.add_section(cnfSec)
confParser.set(cnfSec,"autosaveproject", str(self.autoSaveProj)) cnfParse.set(cnfSec,"autosaveproject", str(self.autoSaveProj))
confParser.set(cnfSec,"autosavedoc", str(self.autoSaveDoc)) cnfParse.set(cnfSec,"autosavedoc", str(self.autoSaveDoc))
## Editor ## Editor
cnfSec = "Editor" cnfSec = "Editor"
confParser.add_section(cnfSec) cnfParse.add_section(cnfSec)
confParser.set(cnfSec,"fixedwidth", str(self.textFixedW)) cnfParse.set(cnfSec,"fixedwidth", str(self.textFixedW))
confParser.set(cnfSec,"width", str(self.textWidth)) cnfParse.set(cnfSec,"width", str(self.textWidth))
confParser.set(cnfSec,"margins", self.packList(self.textMargin)) cnfParse.set(cnfSec,"margins", self._packList(self.textMargin))
confParser.set(cnfSec,"textsize", str(self.textSize)) cnfParse.set(cnfSec,"textsize", str(self.textSize))
confParser.set(cnfSec,"justify", str(self.doJustify)) cnfParse.set(cnfSec,"tabwidth", str(self.tabWidth))
confParser.set(cnfSec,"autoselect", str(self.autoSelect)) cnfParse.set(cnfSec,"justify", str(self.doJustify))
confParser.set(cnfSec,"autoreplace",str(self.doReplace)) cnfParse.set(cnfSec,"autoselect", str(self.autoSelect))
confParser.set(cnfSec,"repsquotes", str(self.doReplaceSQuote)) cnfParse.set(cnfSec,"autoreplace",str(self.doReplace))
confParser.set(cnfSec,"repdquotes", str(self.doReplaceDQuote)) cnfParse.set(cnfSec,"repsquotes", str(self.doReplaceSQuote))
confParser.set(cnfSec,"repdash", str(self.doReplaceDash)) cnfParse.set(cnfSec,"repdquotes", str(self.doReplaceDQuote))
confParser.set(cnfSec,"repdots", str(self.doReplaceDots)) cnfParse.set(cnfSec,"repdash", str(self.doReplaceDash))
confParser.set(cnfSec,"spellcheck", str(self.spellLanguage)) cnfParse.set(cnfSec,"repdots", str(self.doReplaceDots))
cnfParse.set(cnfSec,"spellcheck", str(self.spellLanguage))
## Path ## Path
cnfSec = "Path" cnfSec = "Path"
confParser.add_section(cnfSec) cnfParse.add_section(cnfSec)
for i in range(10): for i in range(10):
confParser.set(cnfSec,"recent%d" % i, str(self.recentList[i])) cnfParse.set(cnfSec,"recent%d" % i, str(self.recentList[i]))
# Write config file # Write config file
try: try:
confParser.write(open(path.join(self.confPath,self.confFile),"w")) cnfParse.write(open(path.join(self.confPath,self.confFile),"w"))
self.confChanged = False self.confChanged = False
except Exception as e: except Exception as e:
logger.error("Could not save config file") logger.error("Could not save config file")
@@ -258,19 +231,6 @@ class Config:
return True return True
def unpackList(self, inStr, listLen, listDefault, castTo=int):
inData = inStr.split(",")
outData = []
for i in range(listLen):
try:
outData.append(castTo(inData[i]))
except:
outData.append(listDefault[i])
return outData
def packList(self, inData):
return ", ".join(str(inVal) for inVal in inData)
## ##
# Setters # Setters
## ##
@@ -316,4 +276,36 @@ class Config:
self.confChanged = True self.confChanged = True
return True return True
##
# Internal Functions
##
def _unpackList(self, inStr, listLen, listDefault, castTo=int):
inData = inStr.split(",")
outData = []
for i in range(listLen):
try:
outData.append(castTo(inData[i]))
except:
outData.append(listDefault[i])
return outData
def _packList(self, inData):
return ", ".join(str(inVal) for inVal in inData)
def _parseLine(self, cnfParse, cnfSec, cnfName, cnfType, cnfDefault):
if cnfParse.has_section(cnfSec):
if cnfParse.has_option(cnfSec, cnfName):
if cnfType == self.CNF_STR:
return cnfParse.get(cnfSec, cnfName)
elif cnfType == self.CNF_INT:
return cnfParse.getint(cnfSec, cnfName)
elif cnfType == self.CNF_BOOL:
return cnfParse.getboolean(cnfSec, cnfName)
elif cnfType == self.CNF_LIST:
return self._unpackList(
cnfParse.get(cnfSec, cnfName), len(cnfDefault), cnfDefault
)
return cnfDefault
# End Class Config # End Class Config
+10 -2
View File
@@ -12,6 +12,15 @@
from nw.enum import nwItemClass, nwItemLayout from nw.enum import nwItemClass, nwItemLayout
class nwFiles():
APP_ICON = "novelWriter.svg"
PROJ_FILE = "nwProject.nwx"
PROJ_DICT = "wordlist.txt"
SESS_INFO = "sessionInfo.log"
# END Class nwFiles
class nwLabels(): class nwLabels():
CLASS_NAME = { CLASS_NAME = {
@@ -59,5 +68,4 @@ class nwLabels():
nwItemLayout.NOTE : "Nt", nwItemLayout.NOTE : "Nt",
} }
# END Class nwLabels
# END nwLabels
-77
View File
@@ -1,77 +0,0 @@
# -*- coding: utf-8 -*-
"""novelWriter GUI About View
novelWriter GUI About View
==============================
Class holding the tab viewing the about information
File History:
Created: 2018-10-02 [0.0.1]
"""
import logging
import nw
from os import path
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QFont
logger = logging.getLogger(__name__)
class GuiAboutView(QWidget):
def __init__(self):
QWidget.__init__(self)
logger.debug("Initialising AboutView ...")
self.mainConf = nw.CONFIG
self.innerBox = QHBoxLayout()
self.outerBox = QVBoxLayout()
logoPath = path.abspath(path.join(self.mainConf.appPath,"..","novelWriter.svg"))
logger.verbose("Loading image: %s" % logoPath)
nwLogo = QSvgWidget(logoPath)
nwLogo.setFixedSize(QSize(300,300))
nwName = QLabel()
nwName.setText(nw.__package__)
nwName.setAlignment(Qt.AlignCenter)
fnName = QFont()
fnName.setPointSize(22)
fnName.setBold(True)
nwName.setFont(fnName)
nwVersion = QLabel()
nwVersion.setText("Version %s" % nw.__version__)
nwVersion.setAlignment(Qt.AlignCenter)
nwCredits = QLabel()
nwCredits.setText("Created By: %s" % ",".join(nw.__credits__))
nwCredits.setAlignment(Qt.AlignCenter)
nwWebsite = QLabel()
nwWebsite.setText("<a href='%s'>%s</a>" % (nw.__website__,nw.__website__))
nwWebsite.setOpenExternalLinks(True)
nwWebsite.setAlignment(Qt.AlignCenter)
self.outerBox.addStretch(1)
self.innerBox.addStretch(1)
self.innerBox.addWidget(nwLogo)
self.innerBox.addStretch(1)
self.outerBox.addLayout(self.innerBox)
self.outerBox.addWidget(nwName)
self.outerBox.addWidget(nwVersion)
self.outerBox.addWidget(nwCredits)
self.outerBox.addWidget(nwWebsite)
self.outerBox.addStretch(1)
self.setLayout(self.outerBox)
logger.debug("AboutView initialisation complete")
return
# END Class GuiAboutView
+6 -1
View File
@@ -104,8 +104,12 @@ class GuiDocEditor(QTextEdit):
mTB = self.mainConf.textMargin[0] mTB = self.mainConf.textMargin[0]
mLR = self.mainConf.textMargin[1] mLR = self.mainConf.textMargin[1]
self.setViewportMargins(mLR,mTB,mLR,mTB) self.setViewportMargins(mLR,mTB,mLR,mTB)
theOpt = QTextOption()
if self.mainConf.tabWidth is not None:
theOpt.setTabStopDistance(self.mainConf.tabWidth)
if self.mainConf.doJustify: if self.mainConf.doJustify:
self.theDoc.setDefaultTextOption(QTextOption(Qt.AlignJustify)) theOpt.setAlignment(Qt.AlignJustify)
self.theDoc.setDefaultTextOption(theOpt)
return True return True
## ##
@@ -376,6 +380,7 @@ class GuiDocEditor(QTextEdit):
self.paraCount = self.wCounter.paraCount self.paraCount = self.wCounter.paraCount
self.theParent.statusBar.setCounts(self.charCount,self.wordCount,self.paraCount) self.theParent.statusBar.setCounts(self.charCount,self.wordCount,self.paraCount)
self.theParent.treeView.propagateCount(tHandle, self.wordCount) self.theParent.treeView.propagateCount(tHandle, self.wordCount)
self.theParent.treeView.projectWordCount()
return return
+2 -1
View File
@@ -194,13 +194,14 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self.setCurrentBlockState(0) self.setCurrentBlockState(0)
if self.theDict is None or not self.spellCheck: if self.theDict is None or not self.spellCheck or theText.startswith("@"):
return return
rxSpell = self.spellRx.globalMatch(theText.replace("_"," "), 0) rxSpell = self.spellRx.globalMatch(theText.replace("_"," "), 0)
while rxSpell.hasNext(): while rxSpell.hasNext():
rxMatch = rxSpell.next() rxMatch = rxSpell.next()
if not self.theDict.check(rxMatch.captured(0)): if not self.theDict.check(rxMatch.captured(0)):
if rxMatch.captured(0) == rxMatch.captured(0).upper(): continue
xPos = rxMatch.capturedStart(0) xPos = rxMatch.capturedStart(0)
xLen = rxMatch.capturedLength(0) xLen = rxMatch.capturedLength(0)
spFmt = self.format(xPos) spFmt = self.format(xPos)
+13 -1
View File
@@ -50,7 +50,7 @@ class GuiDocTree(QTreeWidget):
self.setExpandsOnDoubleClick(True) self.setExpandsOnDoubleClick(True)
self.setIndentation(13) self.setIndentation(13)
self.setColumnCount(4) self.setColumnCount(4)
self.setHeaderLabels(["Name","Count","Flags","Handle"]) self.setHeaderLabels(["Name","Words","Flags","Handle"])
if not self.debugGUI: if not self.debugGUI:
self.hideColumn(self.C_HANDLE) self.hideColumn(self.C_HANDLE)
@@ -286,6 +286,18 @@ class GuiDocTree(QTreeWidget):
self.propagateCount(pHandle, pCount, nDepth+1) self.propagateCount(pHandle, pCount, nDepth+1)
return return
def projectWordCount(self):
nWords = 0
for n in range(self.topLevelItemCount()):
tItem = self.topLevelItem(n)
if tItem == self.orphRoot:
continue
nWords += int(tItem.text(self.C_COUNT))
self.theProject.setProjectWordCount(nWords)
sWords = self.theProject.getSessionWordCount()
self.theParent.statusBar.setStats(nWords,sWords)
return
def buildTree(self): def buildTree(self):
self.clear() self.clear()
for nwItem in self.theProject.getProjectItems(): for nwItem in self.theProject.getProjectItems():
+7
View File
@@ -253,6 +253,13 @@ class GuiMainMenu(QMenuBar):
menuItem.triggered.connect(self.theParent.saveDocument) menuItem.triggered.connect(self.theParent.saveDocument)
self.docuMenu.addAction(menuItem) self.docuMenu.addAction(menuItem)
# Document > Close
menuItem = QAction(QIcon.fromTheme("document-revert"), "Close Document", self)
menuItem.setStatusTip("Close Current Document")
menuItem.setShortcut("Ctrl+W")
menuItem.triggered.connect(self.theParent.closeDocEditor)
self.docuMenu.addAction(menuItem)
# Document > Separator # Document > Separator
self.docuMenu.addSeparator() self.docuMenu.addSeparator()
+83 -20
View File
@@ -13,6 +13,9 @@
import logging import logging
import nw import nw
from time import time
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QIcon, QColor, QPixmap
from PyQt5.QtWidgets import QStatusBar, QLabel, QFrame from PyQt5.QtWidgets import QStatusBar, QLabel, QFrame
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -25,36 +28,74 @@ class GuiMainStatus(QStatusBar):
logger.debug("Initialising GuiMainStatus ...") logger.debug("Initialising GuiMainStatus ...")
self.mainConf = nw.CONFIG self.mainConf = nw.CONFIG
self.refTime = None
self.iconGrey = QPixmap(16,16)
self.iconGrey.fill(QColor(120,120,120))
self.iconYellow = QPixmap(16,16)
self.iconYellow.fill(QColor(120,120, 40))
self.iconGreen = QPixmap(16,16)
self.iconGreen.fill(QColor( 40,120, 0))
self.boxStats = QLabel()
self.boxStats.setToolTip("Project Word Count | Session Word Count")
self.boxTime = QLabel("")
self.boxTime.setToolTip("Session Time")
self.boxTime.setAlignment(Qt.AlignRight)
self.boxTime.setMinimumWidth(80)
self.boxCounts = QLabel() self.boxCounts = QLabel()
self.boxCounts.setToolTip("Character, Word, Paragraph Count") self.boxCounts.setToolTip("Document Character | Word | Paragraph Count")
self.boxCounts.setFrameStyle(QFrame.Panel | QFrame.Sunken);
self.addPermanentWidget(self.boxCounts)
self.projChanged = QLabel("P") self.projChanged = QLabel("")
self.projChanged.setFixedHeight(16)
self.projChanged.setFixedWidth(16)
self.projChanged.setToolTip("Project Changes Saved") self.projChanged.setToolTip("Project Changes Saved")
self.projChanged.setFrameStyle(QFrame.Panel | QFrame.Sunken);
self.addPermanentWidget(self.projChanged)
self.docChanged = QLabel("D") self.docChanged = QLabel("")
self.docChanged.setFixedHeight(16)
self.docChanged.setFixedWidth(16)
self.docChanged.setToolTip("Document Changes Saved") self.docChanged.setToolTip("Document Changes Saved")
self.docChanged.setFrameStyle(QFrame.Panel | QFrame.Sunken);
self.addPermanentWidget(self.docChanged)
self.boxDocHandle = QLabel() self.boxDocHandle = QLabel()
self.boxDocHandle.setFrameStyle(QFrame.Panel | QFrame.Sunken); self.boxDocHandle.setFrameStyle(QFrame.Panel | QFrame.Sunken);
# Add Them
self.addPermanentWidget(self.docChanged)
self.addPermanentWidget(self.boxCounts)
self.addPermanentWidget(QLabel(" "))
self.addPermanentWidget(self.projChanged)
self.addPermanentWidget(self.boxStats)
self.addPermanentWidget(self.boxTime)
if self.mainConf.debugGUI: if self.mainConf.debugGUI:
self.addPermanentWidget(self.boxDocHandle) self.addPermanentWidget(self.boxDocHandle)
self.setSizeGripEnabled(True)
self.sessionTimer = QTimer()
self.sessionTimer.setInterval(1000)
self.sessionTimer.timeout.connect(self._updateTime)
self.sessionTimer.start()
logger.debug("GuiMainStatus initialisation complete") logger.debug("GuiMainStatus initialisation complete")
self.clearStatus()
return
def clearStatus(self):
self.setRefTime(None)
self.setStats(0,0)
self.setCounts(0,0,0) self.setCounts(0,0,0)
self.setDocHandleCount(None) self.setDocHandleCount(None)
self.setProjectStatus(None) self.setProjectStatus(None)
self.setDocumentStatus(None) self.setDocumentStatus(None)
self._updateTime()
return True
self.setSizeGripEnabled(True) def setRefTime(self, theTime):
self.refTime = theTime
return return
def setStatus(self, theMessage, timeOut=10.0): def setStatus(self, theMessage, timeOut=10.0):
@@ -63,28 +104,32 @@ class GuiMainStatus(QStatusBar):
def setProjectStatus(self, isChanged): def setProjectStatus(self, isChanged):
if isChanged is None: if isChanged is None:
self.projChanged.setStyleSheet("QLabel {background-color: rgba(120,120,120,1.0);}") self.projChanged.setPixmap(self.iconGrey)
elif isChanged == True: elif isChanged == True:
self.projChanged.setStyleSheet("QLabel {background-color: rgba(120,120,40,1.0);}") self.projChanged.setPixmap(self.iconYellow)
elif isChanged == False: elif isChanged == False:
self.projChanged.setStyleSheet("QLabel {background-color: rgba(40,120,0,1.0);}") self.projChanged.setPixmap(self.iconGreen)
else: else:
self.projChanged.setStyleSheet("QLabel {background-color: rgba(120,120,120,1.0);}") self.projChanged.setPixmap(self.iconGrey)
return return
def setDocumentStatus(self, isChanged): def setDocumentStatus(self, isChanged):
if isChanged is None: if isChanged is None:
self.docChanged.setStyleSheet("QLabel {background-color: rgba(120,120,120,1.0);}") self.docChanged.setPixmap(self.iconGrey)
elif isChanged == True: elif isChanged == True:
self.docChanged.setStyleSheet("QLabel {background-color: rgba(120,120,40,1.0);}") self.docChanged.setPixmap(self.iconYellow)
elif isChanged == False: elif isChanged == False:
self.docChanged.setStyleSheet("QLabel {background-color: rgba(40,120,0,1.0);}") self.docChanged.setPixmap(self.iconGreen)
else: else:
self.docChanged.setStyleSheet("QLabel {background-color: rgba(120,120,120,1.0);}") self.docChanged.setPixmap(self.iconGrey)
return
def setStats(self, pWC, sWC):
self.boxStats.setText("<b>Project:</b> {:d} : {:d}".format(pWC,sWC))
return return
def setCounts(self, cC, wC, pC): def setCounts(self, cC, wC, pC):
self.boxCounts.setText("<b>C:</b> {:n}&nbsp;&nbsp;<b>W:</b> {:n}&nbsp;&nbsp;<b>P:</b> {:n}".format(cC,wC,pC)) self.boxCounts.setText("<b>Document:</b> {:d} : {:d} : {:d}".format(cC,wC,pC))
return return
def setDocHandleCount(self, theHandle): def setDocHandleCount(self, theHandle):
@@ -94,4 +139,22 @@ class GuiMainStatus(QStatusBar):
self.boxDocHandle.setText("%13s" % theHandle) self.boxDocHandle.setText("%13s" % theHandle)
return return
##
# Internal Functions
##
def _updateTime(self):
if self.refTime is None:
theTime = "00:00:00"
else:
# This is much faster than using datetime format
tS = int(time() - self.refTime)
tM = int(tS/60)
tH = int(tM/60)
tM = tM - tH*60
tS = tS - tM*60 - tH*3600
theTime = "%02d:%02d:%02d" % (tH,tM,tS)
self.boxTime.setText(theTime)
return
# END Class GuiMainStatus # END Class GuiMainStatus
+85 -75
View File
@@ -36,6 +36,7 @@ from nw.project.item import NWItem
from nw.convert.tokenizer import Tokenizer from nw.convert.tokenizer import Tokenizer
from nw.convert.tohtml import ToHtml from nw.convert.tohtml import ToHtml
from nw.enum import nwItemType, nwAlert from nw.enum import nwItemType, nwAlert
from nw.constants import nwFiles
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -53,7 +54,7 @@ class GuiMain(QMainWindow):
self.resize(*self.mainConf.winGeometry) self.resize(*self.mainConf.winGeometry)
self._setWindowTitle() self._setWindowTitle()
self.setWindowIcon(QIcon(path.join(self.mainConf.appPath,"..","novelWriter.svg"))) self.setWindowIcon(QIcon(path.join(self.mainConf.appRoot, nwFiles.APP_ICON)))
self.theTheme.loadTheme() self.theTheme.loadTheme()
# Main GUI Elements # Main GUI Elements
@@ -139,43 +140,11 @@ class GuiMain(QMainWindow):
return return
def makeAlert(self, theMessage, theLevel=nwAlert.INFO):
"""Alert both the user and the logger at the same time. Message can be either a string or an
array of strings. Severity level is 0 = info, 1 = warning, and 2 = error.
"""
if isinstance(theMessage, list):
popMsg = "<br>".join(theMessage)
logMsg = theMessage
else:
popMsg = theMessage
logMsg = [theMessage]
msgBox = QMessageBox()
if theLevel == nwAlert.INFO:
for msgLine in logMsg:
logger.info(msgLine)
msgBox.information(self, "Information", popMsg)
elif theLevel == nwAlert.WARN:
for msgLine in logMsg:
logger.warning(msgLine)
msgBox.warning(self, "Warning", popMsg)
elif theLevel == nwAlert.ERROR:
for msgLine in logMsg:
logger.error(msgLine)
msgBox.critical(self, "Error", popMsg)
elif theLevel == nwAlert.BUG:
for msgLine in logMsg:
logger.error(msgLine)
popMsg += "<br>This is a bug!"
msgBox.critical(self, "Internal Error", popMsg)
return
def clearGUI(self): def clearGUI(self):
self.treeView.clearTree() self.treeView.clearTree()
self.docEditor.clearEditor() self.docEditor.clearEditor()
self.closeDocViewer() self.closeDocViewer()
self.statusBar.clearStatus()
return True return True
## ##
@@ -211,19 +180,22 @@ class GuiMain(QMainWindow):
self.rebuildTree() self.rebuildTree()
self.saveProject() self.saveProject()
self.hasProject = True self.hasProject = True
self.statusBar.setRefTime(self.theProject.projOpened)
return True return True
def closeProject(self, isYes=False): def closeProject(self, isYes=False):
"""Closes the project if one is open.
isYes is passed on from the close application event so the user doesn't get prompted twice.
"""
if not self.hasProject: if not self.hasProject:
# There is no project loaded, everything OK
return True return True
if not isYes: if self.mainConf.showGUI and not isYes:
msgBox = QMessageBox() msgBox = QMessageBox()
msgRes = msgBox.question( msgRes = msgBox.question(
self, "Close Project", self, "Close Project", "Save changes and close current project?"
"Close current project?<br>Unsaved changes will be saved."
) )
if msgRes != QMessageBox.Yes: if msgRes != QMessageBox.Yes:
return False return False
@@ -235,29 +207,38 @@ class GuiMain(QMainWindow):
saveOK = True saveOK = True
if saveOK: if saveOK:
self.theProject.clearProject() self.theProject.closeProject()
self.clearGUI() self.clearGUI()
self.hasProject = False self.hasProject = False
return saveOK return saveOK
def openProject(self, projFile=None): def openProject(self, projFile=None):
"""Open a project.
projFile is passed from the open recent projects menu, so can be set. If not, we pop the dialog.
"""
if projFile is None: if projFile is None:
projFile = self.openProjectDialog() projFile = self.openProjectDialog()
if projFile is None: if projFile is None:
return False return False
# Make sure any open project is cleared out first before we load another one
if not self.closeProject(): if not self.closeProject():
return False return False
self.theProject.openProject(projFile) # Try to open the project
if not self.theProject.openProject(projFile):
return False
# Update GUI
self._setWindowTitle(self.theProject.projName) self._setWindowTitle(self.theProject.projName)
self.rebuildTree() self.rebuildTree()
self.docEditor.setPwl(path.join(self.theProject.projMeta,"wordlist.txt")) self.docEditor.setPwl(path.join(self.theProject.projMeta, nwFiles.PROJ_DICT))
self.docEditor.setSpellCheck(self.theProject.spellCheck) self.docEditor.setSpellCheck(self.theProject.spellCheck)
self.statusBar.setRefTime(self.theProject.projOpened)
self.mainMenu.updateMenu() self.mainMenu.updateMenu()
# Restore previously open documents, if any
if self.theProject.lastEdited is not None: if self.theProject.lastEdited is not None:
self.openDocument(self.theProject.lastEdited) self.openDocument(self.theProject.lastEdited)
if self.theProject.lastViewed is not None: if self.theProject.lastViewed is not None:
@@ -268,7 +249,9 @@ class GuiMain(QMainWindow):
return True return True
def saveProject(self): def saveProject(self):
"""Save the current project.
"""
# If the project is new, it may not have a path, so we need one
if self.theProject.projPath is None: if self.theProject.projPath is None:
projPath = self.saveProjectDialog() projPath = self.saveProjectDialog()
self.theProject.setProjectPath(projPath) self.theProject.setProjectPath(projPath)
@@ -286,13 +269,14 @@ class GuiMain(QMainWindow):
## ##
def closeDocument(self): def closeDocument(self):
self.saveDocument() if self.docEditor.docChanged:
self.saveDocument()
self.theDocument.clearDocument() self.theDocument.clearDocument()
self.docEditor.clearEditor()
return True return True
def openDocument(self, tHandle): def openDocument(self, tHandle):
if self.docEditor.docChanged: self.closeDocument()
self.saveDocument()
self.docEditor.setText(self.theDocument.openDocument(tHandle)) self.docEditor.setText(self.theDocument.openDocument(tHandle))
self.docEditor.setReadOnly(False) self.docEditor.setReadOnly(False)
self.docEditor.setCursorPosition(self.theDocument.theItem.cursorPos) self.docEditor.setCursorPosition(self.theDocument.theItem.cursorPos)
@@ -303,13 +287,13 @@ class GuiMain(QMainWindow):
def saveDocument(self): def saveDocument(self):
if self.theDocument.theItem is not None: if self.theDocument.theItem is not None:
docHtml = self.docEditor.getText() docText = self.docEditor.getText()
cursPos = self.docEditor.getCursorPosition() cursPos = self.docEditor.getCursorPosition()
self.theDocument.theItem.setCharCount(self.docEditor.charCount) self.theDocument.theItem.setCharCount(self.docEditor.charCount)
self.theDocument.theItem.setWordCount(self.docEditor.wordCount) self.theDocument.theItem.setWordCount(self.docEditor.wordCount)
self.theDocument.theItem.setParaCount(self.docEditor.paraCount) self.theDocument.theItem.setParaCount(self.docEditor.paraCount)
self.theDocument.theItem.setCursorPos(cursPos) self.theDocument.theItem.setCursorPos(cursPos)
self.theDocument.saveDocument(docHtml) self.theDocument.saveDocument(docText)
self.docEditor.setDocumentChanged(False) self.docEditor.setDocumentChanged(False)
return True return True
@@ -393,7 +377,9 @@ class GuiMain(QMainWindow):
dlgOpt = QFileDialog.Options() dlgOpt = QFileDialog.Options()
dlgOpt |= QFileDialog.DontUseNativeDialog dlgOpt |= QFileDialog.DontUseNativeDialog
projFile, _ = QFileDialog.getOpenFileName( projFile, _ = QFileDialog.getOpenFileName(
self,"Open novelWriter Project","","novelWriter Project File (nwProject.nwx);;All Files (*)",options=dlgOpt self, "Open novelWriter Project", "",
"novelWriter Project File (%s);;All Files (*)" % nwFiles.PROJ_FILE,
options=dlgOpt
) )
if projFile: if projFile:
return projFile return projFile
@@ -427,26 +413,56 @@ class GuiMain(QMainWindow):
self._setWindowTitle(self.theProject.projName) self._setWindowTitle(self.theProject.projName)
return True return True
def makeAlert(self, theMessage, theLevel=nwAlert.INFO):
"""Alert both the user and the logger at the same time. Message can be either a string or an
array of strings. Severity level is 0 = info, 1 = warning, and 2 = error.
"""
if isinstance(theMessage, list):
popMsg = "<br>".join(theMessage)
logMsg = theMessage
else:
popMsg = theMessage
logMsg = [theMessage]
msgBox = QMessageBox()
if theLevel == nwAlert.INFO:
for msgLine in logMsg:
logger.info(msgLine)
msgBox.information(self, "Information", popMsg)
elif theLevel == nwAlert.WARN:
for msgLine in logMsg:
logger.warning(msgLine)
msgBox.warning(self, "Warning", popMsg)
elif theLevel == nwAlert.ERROR:
for msgLine in logMsg:
logger.error(msgLine)
msgBox.critical(self, "Error", popMsg)
elif theLevel == nwAlert.BUG:
for msgLine in logMsg:
logger.error(msgLine)
popMsg += "<br>This is a bug!"
msgBox.critical(self, "Internal Error", popMsg)
return
## ##
# Main Window Actions # Main Window Actions
## ##
def closeMain(self, isYes=False): def closeMain(self):
if not isYes: if self.mainConf.showGUI:
msgBox = QMessageBox() msgBox = QMessageBox()
msgRes = msgBox.question( msgRes = msgBox.question(
self, "Exit", self, "Exit", "Do you want to save changes and exit?"
"Do you want to exit %s?" % nw.__package__
) )
if msgRes != QMessageBox.Yes: if msgRes != QMessageBox.Yes:
return False return False
logger.info("Exiting %s" % nw.__package__) logger.info("Exiting %s" % nw.__package__)
if self._takeDocumentAction(): self.closeProject(True)
self.saveDocument()
if self._takeProjectAction():
self.saveProject()
self.mainConf.setWinSize(self.width(), self.height()) self.mainConf.setWinSize(self.width(), self.height())
self.mainConf.setTreeColWidths(self.treeView.getColumnSizes()) self.mainConf.setTreeColWidths(self.treeView.getColumnSizes())
self.mainConf.setMainPanePos(self.splitMain.sizes()) self.mainConf.setMainPanePos(self.splitMain.sizes())
@@ -466,6 +482,11 @@ class GuiMain(QMainWindow):
self.docViewer.setFocus() self.docViewer.setFocus()
return return
def closeDocEditor(self):
self.closeDocument()
self.theProject.setLastEdited(None)
return
def closeDocViewer(self): def closeDocViewer(self):
self.docViewer.clearViewer() self.docViewer.clearViewer()
self.theProject.setLastViewed(None) self.theProject.setLastViewed(None)
@@ -488,31 +509,17 @@ class GuiMain(QMainWindow):
return True return True
def _autoSaveProject(self): def _autoSaveProject(self):
if self._takeProjectAction(): 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()
return return
def _autoSaveDocument(self): def _autoSaveDocument(self):
if self._takeDocumentAction(): if self.hasProject and self.docEditor.docChanged and self.theDocument.theItem is not None:
logger.debug("Autosaving document") logger.debug("Autosaving document")
self.saveDocument() self.saveDocument()
return return
def _takeProjectAction(self):
if self.theProject.projPath is None:
return False
if not self.theProject.projChanged:
return False
return True
def _takeDocumentAction(self):
if self.theDocument.theItem is None:
return False
if not self.docEditor.docChanged:
return False
return True
def _makeStatusIcons(self): def _makeStatusIcons(self):
self.statusIcons = {} self.statusIcons = {}
for sLabel, sCol, _ in self.theProject.statusItems: for sLabel, sCol, _ in self.theProject.statusItems:
@@ -541,7 +548,10 @@ class GuiMain(QMainWindow):
return return
def closeEvent(self, theEvent): def closeEvent(self, theEvent):
self.closeMain() if self.closeMain():
theEvent.accept()
else:
theEvent.ignore()
return return
## ##
+53 -9
View File
@@ -19,10 +19,11 @@ from hashlib import sha256
from datetime import datetime from datetime import datetime
from time import time from time import time
from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
from nw.common import checkString, checkBool
from nw.project.item import NWItem from nw.project.item import NWItem
from nw.project.status import NWStatus from nw.project.status import NWStatus
from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
from nw.common import checkString, checkBool, checkInt
from nw.constants import nwFiles
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -34,6 +35,7 @@ class NWProject():
self.theParent = theParent self.theParent = theParent
self.mainConf = self.theParent.mainConf self.mainConf = self.theParent.mainConf
self.projChanged = None self.projChanged = None
self.projOpened = None
# Debug # Debug
self.handleSeed = None self.handleSeed = None
@@ -59,6 +61,8 @@ class NWProject():
self.importItems = None self.importItems = None
self.lastEdited = None self.lastEdited = None
self.lastViewed = None self.lastViewed = None
self.lastWCount = 0
self.currWCount = 0
# Set Defaults # Set Defaults
self.clearProject() self.clearProject()
@@ -119,19 +123,20 @@ class NWProject():
## ##
def newProject(self): def newProject(self):
hNovel = self.newRoot("Novel", nwItemClass.NOVEL) hNovel = self.newRoot("Novel", nwItemClass.NOVEL)
hChars = self.newRoot("Characters", nwItemClass.CHARACTER) hChars = self.newRoot("Characters", nwItemClass.CHARACTER)
hWorld = self.newRoot("Plot", nwItemClass.PLOT) hWorld = self.newRoot("Plot", nwItemClass.PLOT)
hWorld = self.newRoot("World", nwItemClass.WORLD) hWorld = self.newRoot("World", nwItemClass.WORLD)
hChapt = self.newFolder("New Chapter", nwItemClass.NOVEL, hNovel) hChapt = self.newFolder("New Chapter", nwItemClass.NOVEL, hNovel)
hScene = self.newFile("New Scene", nwItemClass.NOVEL, hChapt) hScene = self.newFile("New Scene", nwItemClass.NOVEL, hChapt)
self.projOpened = time()
self.setProjectChanged(True)
return True return True
def clearProject(self): def clearProject(self):
self.projChanged = None self.projChanged = None
self.projOpened = None
# Project Settings # Project Settings
self.projTree = {} self.projTree = {}
@@ -141,7 +146,7 @@ class NWProject():
self.projPath = None self.projPath = None
self.projMeta = None self.projMeta = None
self.projCache = None self.projCache = None
self.projFile = "nwProject.nwx" self.projFile = nwFiles.PROJ_FILE
self.projName = "" self.projName = ""
self.bookTitle = "" self.bookTitle = ""
self.bookAuthors = [] self.bookAuthors = []
@@ -156,13 +161,17 @@ class NWProject():
self.importItems.addEntry("Minor", (200, 50, 0)) self.importItems.addEntry("Minor", (200, 50, 0))
self.importItems.addEntry("Major", (200,150, 0)) self.importItems.addEntry("Major", (200,150, 0))
self.importItems.addEntry("Main", ( 50,200, 0)) self.importItems.addEntry("Main", ( 50,200, 0))
self.lastEdited = None
self.lastViewed = None
self.lastWCount = 0
self.currWCount = 0
return return
def openProject(self, fileName): def openProject(self, fileName):
if not path.isfile(fileName): if not path.isfile(fileName):
fileName = path.join(fileName, "nwProject.nwx") fileName = path.join(fileName, nwFiles.PROJ_FILE)
if not path.isfile(fileName): if not path.isfile(fileName):
self.makeAlert("File not found: %s" % fileName, nwAlert.ERROR) self.makeAlert("File not found: %s" % fileName, nwAlert.ERROR)
return False return False
@@ -215,6 +224,8 @@ class NWProject():
self.lastEdited = checkString(xItem.text,None,True) self.lastEdited = checkString(xItem.text,None,True)
if xItem.tag == "lastViewed": if xItem.tag == "lastViewed":
self.lastViewed = checkString(xItem.text,None,True) self.lastViewed = checkString(xItem.text,None,True)
if xItem.tag == "lastWordCount":
self.lastWCount = checkInt(xItem.text,0,False)
if xItem.tag == "status": if xItem.tag == "status":
self.statusItems.unpackEntries(xItem) self.statusItems.unpackEntries(xItem)
if xItem.tag == "importance": if xItem.tag == "importance":
@@ -242,6 +253,7 @@ class NWProject():
self._scanProjectFolder() self._scanProjectFolder()
self.setProjectChanged(False) self.setProjectChanged(False)
self.projOpened = time()
return True return True
@@ -276,9 +288,10 @@ class NWProject():
# Save Project Settings # Save Project Settings
xSettings = etree.SubElement(nwXML,"settings") xSettings = etree.SubElement(nwXML,"settings")
self._saveProjectValue(xSettings,"spellCheck",self.spellCheck) self._saveProjectValue(xSettings,"spellCheck", self.spellCheck)
self._saveProjectValue(xSettings,"lastEdited",self.lastEdited) self._saveProjectValue(xSettings,"lastEdited", self.lastEdited)
self._saveProjectValue(xSettings,"lastViewed",self.lastViewed) self._saveProjectValue(xSettings,"lastViewed", self.lastViewed)
self._saveProjectValue(xSettings,"lastWordCount",self.currWCount)
xStatus = etree.SubElement(xSettings,"status") xStatus = etree.SubElement(xSettings,"status")
self.statusItems.packEntries(xStatus) self.statusItems.packEntries(xStatus)
@@ -311,6 +324,11 @@ class NWProject():
return True return True
def closeProject(self):
self._appendSessionStats()
self.clearProject()
return True
## ##
# Set Functions # Set Functions
## ##
@@ -365,6 +383,14 @@ class NWProject():
self.setProjectChanged(True) self.setProjectChanged(True)
return True return True
def setProjectWordCount(self, theCount):
self.currWCount = theCount
self.setProjectChanged(True)
return True
def getSessionWordCount(self):
return self.currWCount - self.lastWCount
def setStatusColours(self, newCols): def setStatusColours(self, newCols):
replaceMap = self.statusItems.setNewEntries(newCols) replaceMap = self.statusItems.setNewEntries(newCols)
if self.projTree is not None: if self.projTree is not None:
@@ -576,6 +602,24 @@ class NWProject():
return return
def _appendSessionStats(self):
if self.projMeta is None:
return False
with open(path.join(self.projMeta, nwFiles.SESS_INFO), mode="a+") as outFile:
print((
"Start: {opened:s} "
"End: {closed:s} "
"Words: {words:8d}"
).format(
opened = datetime.fromtimestamp(self.projOpened).strftime("%Y-%m-%d %H:%M:%S"),
closed = datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
words = self.getSessionWordCount(),
), file=outFile)
return True
def _makeHandle(self, addSeed=""): def _makeHandle(self, addSeed=""):
if self.handleSeed is None: if self.handleSeed is None:
newSeed = str(time()) + addSeed newSeed = str(time()) + addSeed
@@ -13,8 +13,12 @@ Some text here would look good as well, and maybe some "dialogue"?
So, this is some __text__ that weve been adding to this document. It is utterly meaningless text, _but_ since this is just dummy text, that doesnt really matter. The text is perfectly happy to live in this document regardless. So, this is some __text__ that weve been adding to this document. It is utterly meaningless text, _but_ since this is just dummy text, that doesnt really matter. The text is perfectly happy to live in this document regardless.
This paragraph is also meaningless. At least a bit. Its also very short. This paragraph is also meaningless. At least a bit. Its also very short. But we could make it less meaningless if we wanted to … but we wont, will we.
This one is a bit longer. “It also has some dialogue in it” she said, before she moved on to check if the spellchecker worked. It did. “Cool,” she concluded. This one is a bit longer. “It also has some dialogue in it” she said, before she moved on to check if the spellchecker worked. It did. “Cool,” she concluded.
@ToDo: Stuff that will be done at some point
+15
View File
@@ -0,0 +1,15 @@
Start: 2019-05-26 14:28:28 End: 2019-05-26 14:28:38 Words: -23
Start: 2019-05-26 14:31:12 End: 2019-05-26 14:31:34 Words: 12
Start: 2019-05-26 14:33:27 End: 2019-05-26 14:33:31 Words: 0
Start: 2019-05-26 14:40:29 End: 2019-05-26 14:40:32 Words: 0
Start: 2019-05-26 14:40:43 End: 2019-05-26 14:40:46 Words: 0
Start: 2019-05-26 14:48:40 End: 2019-05-26 14:48:50 Words: 0
Start: 2019-05-26 14:50:18 End: 2019-05-26 14:50:21 Words: 0
Start: 2019-05-26 14:50:29 End: 2019-05-26 14:50:47 Words: 3
Start: 2019-05-26 15:10:52 End: 2019-05-26 15:11:09 Words: 0
Start: 2019-05-26 15:28:56 End: 2019-05-26 15:29:08 Words: 0
Start: 2019-05-26 15:37:34 End: 2019-05-26 15:37:43 Words: -538
Start: 2019-05-26 15:37:47 End: 2019-05-26 15:38:07 Words: 538
Start: 2019-05-26 15:38:11 End: 2019-05-26 15:43:07 Words: 2
Start: 2019-05-26 15:49:18 End: 2019-05-26 15:49:47 Words: 0
Start: 2019-05-26 15:52:39 End: 2019-05-26 15:52:56 Words: 0
+6 -5
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-24 00:28:28"> <novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-26 15:52:53">
<project> <project>
<name>Sample Project</name> <name>Sample Project</name>
<title>Sample Project</title> <title>Sample Project</title>
@@ -9,7 +9,8 @@
<settings> <settings>
<spellCheck>True</spellCheck> <spellCheck>True</spellCheck>
<lastEdited>636b6aa9b697b</lastEdited> <lastEdited>636b6aa9b697b</lastEdited>
<lastViewed>636b6aa9b697b</lastViewed> <lastViewed>None</lastViewed>
<lastWordCount>540</lastWordCount>
<status> <status>
<entry blue="100" green="100" red="100">New</entry> <entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Notes</entry> <entry blue="0" green="50" red="200">Notes</entry>
@@ -72,10 +73,10 @@
<status>Notes</status> <status>Notes</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>577</charCount> <charCount>656</charCount>
<wordCount>104</wordCount> <wordCount>121</wordCount>
<paraCount>5</paraCount> <paraCount>5</paraCount>
<cursorPos>603</cursorPos> <cursorPos>573</cursorPos>
</item> </item>
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a"> <item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
<name>New File</name> <name>New File</name>
+2 -1
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-23 23:02:29"> <novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:29:02">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
@@ -8,6 +8,7 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<lastWordCount>0</lastWordCount>
<status> <status>
<entry blue="100" green="100" red="100">New</entry> <entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry> <entry blue="0" green="50" red="200">Note</entry>
+2 -1
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 21:14:26"> <novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:29:32">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
@@ -8,6 +8,7 @@
<spellCheck>True</spellCheck> <spellCheck>True</spellCheck>
<lastEdited>31489056e0916</lastEdited> <lastEdited>31489056e0916</lastEdited>
<lastViewed>31489056e0916</lastViewed> <lastViewed>31489056e0916</lastViewed>
<lastWordCount>69</lastWordCount>
<status> <status>
<entry blue="100" green="100" red="100">New</entry> <entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry> <entry blue="0" green="50" red="200">Note</entry>
+2 -1
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 21:35:39"> <novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:31:12">
<project> <project>
<name>Project Name</name> <name>Project Name</name>
<title>Project Title</title> <title>Project Title</title>
@@ -10,6 +10,7 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<lastWordCount>0</lastWordCount>
<status> <status>
<entry blue="100" green="100" red="100">New</entry> <entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry> <entry blue="0" green="50" red="200">Note</entry>
+2 -1
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 21:16:34"> <novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:31:45">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
@@ -8,6 +8,7 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<lastWordCount>0</lastWordCount>
<status> <status>
<entry blue="100" green="100" red="100">New</entry> <entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry> <entry blue="0" green="50" red="200">Note</entry>
+2 -1
View File
@@ -1,5 +1,5 @@
[Main] [Main]
timestamp = 2019-05-18 15:06:44 timestamp = 2019-05-25 23:33:23
theme = default theme = default
[Sizes] [Sizes]
@@ -17,6 +17,7 @@ fixedwidth = True
width = 600 width = 600
margins = 40, 40 margins = 40, 40
textsize = 13 textsize = 13
tabwidth = 40
justify = True justify = True
autoselect = True autoselect = True
autoreplace = True autoreplace = True
+2 -1
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 20:48:51"> <novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:25:27">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
@@ -8,6 +8,7 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<lastWordCount>0</lastWordCount>
<status> <status>
<entry blue="100" green="100" red="100">New</entry> <entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry> <entry blue="0" green="50" red="200">Note</entry>
+2 -1
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 20:52:32"> <novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-25 23:26:15">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
@@ -8,6 +8,7 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<lastWordCount>0</lastWordCount>
<status> <status>
<entry blue="100" green="100" red="100">New</entry> <entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry> <entry blue="0" green="50" red="200">Note</entry>
+4 -4
View File
@@ -27,7 +27,7 @@ def testMainWindows(qtbot, nwTempGUI, nwRef):
nwGUI.theProject.handleSeed = 42 nwGUI.theProject.handleSeed = 42
assert nwGUI.newProject(nwTempGUI, True) assert nwGUI.newProject(nwTempGUI, True)
assert nwGUI.saveProject() assert nwGUI.saveProject()
assert nwGUI.closeProject(True) assert nwGUI.closeProject()
assert len(nwGUI.theProject.projTree) == 0 assert len(nwGUI.theProject.projTree) == 0
assert len(nwGUI.theProject.treeOrder) == 0 assert len(nwGUI.theProject.treeOrder) == 0
@@ -155,7 +155,7 @@ def testMainWindows(qtbot, nwTempGUI, nwRef):
sceneFile = path.join(nwTempGUI,"data_3","1489056e0916_main.nwd") sceneFile = path.join(nwTempGUI,"data_3","1489056e0916_main.nwd")
assert cmpFiles(sceneFile, path.join(nwRef,"gui","1_1489056e0916_main.nwd")) assert cmpFiles(sceneFile, path.join(nwRef,"gui","1_1489056e0916_main.nwd"))
nwGUI.closeMain(True) nwGUI.closeMain()
# qtbot.stopForInteraction() # qtbot.stopForInteraction()
@pytest.mark.gui @pytest.mark.gui
@@ -217,7 +217,7 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef):
projFile = path.join(nwTempGUI,"nwProject.nwx") projFile = path.join(nwTempGUI,"nwProject.nwx")
assert cmpFiles(projFile, path.join(nwRef,"gui","2_nwProject.nwx"), [2]) assert cmpFiles(projFile, path.join(nwRef,"gui","2_nwProject.nwx"), [2])
nwGUI.closeMain(True) nwGUI.closeMain()
# qtbot.stopForInteraction() # qtbot.stopForInteraction()
@pytest.mark.gui @pytest.mark.gui
@@ -263,5 +263,5 @@ def testItemEditor(qtbot, nwTempGUI, nwRef):
projFile = path.join(nwTempGUI,"nwProject.nwx") projFile = path.join(nwTempGUI,"nwProject.nwx")
assert cmpFiles(projFile, path.join(nwRef,"gui","3_nwProject.nwx"), [2]) assert cmpFiles(projFile, path.join(nwRef,"gui","3_nwProject.nwx"), [2])
nwGUI.closeMain(True) nwGUI.closeMain()
# qtbot.stopForInteraction() # qtbot.stopForInteraction()