+11
-1
@@ -1,2 +1,12 @@
|
|||||||
|
# Python Temp
|
||||||
__pycache__
|
__pycache__
|
||||||
*.bak
|
|
||||||
|
# Sample Project
|
||||||
|
sample/**/cache
|
||||||
|
sample/**/wordlist.txt
|
||||||
|
sample/**/*.bak
|
||||||
|
|
||||||
|
# PyTest
|
||||||
|
tests/temp
|
||||||
|
.pytest_cache
|
||||||
|
pytestdebug.log
|
||||||
|
|||||||
+5
-4
@@ -64,8 +64,7 @@ logger = logging.getLogger(__name__)
|
|||||||
CONFIG = Config()
|
CONFIG = Config()
|
||||||
|
|
||||||
def main(sysArgs):
|
def main(sysArgs):
|
||||||
"""
|
"""Parses command line, sets up logging, and launches main GUI.
|
||||||
Parses command line, sets up logging, and launches main GUI.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Valid Input Options
|
# Valid Input Options
|
||||||
@@ -149,10 +148,10 @@ def main(sysArgs):
|
|||||||
showGUI = False
|
showGUI = False
|
||||||
elif inOpt in ("-D","--debuggui"):
|
elif inOpt in ("-D","--debuggui"):
|
||||||
debugLevel = logging.DEBUG
|
debugLevel = logging.DEBUG
|
||||||
debugStr = "{name:>22}:{lineno:<4d} {levelname:8} {message:}"
|
debugStr = "{name:>20}:{lineno:<4d} {levelname:8} {message:}"
|
||||||
debugGUI = True
|
debugGUI = True
|
||||||
|
|
||||||
# Set GUI options
|
# Set Config Options
|
||||||
CONFIG.showGUI = showGUI
|
CONFIG.showGUI = showGUI
|
||||||
CONFIG.debugGUI = debugGUI
|
CONFIG.debugGUI = debugGUI
|
||||||
|
|
||||||
@@ -179,6 +178,8 @@ def main(sysArgs):
|
|||||||
|
|
||||||
logger.setLevel(debugLevel)
|
logger.setLevel(debugLevel)
|
||||||
|
|
||||||
|
CONFIG.initConfig(confPath)
|
||||||
|
|
||||||
nwApp = QApplication([])
|
nwApp = QApplication([])
|
||||||
nwGUI = NovelWriter()
|
nwGUI = NovelWriter()
|
||||||
exit(nwApp.exec_())
|
exit(nwApp.exec_())
|
||||||
|
|||||||
+51
-29
@@ -6,7 +6,7 @@
|
|||||||
This class reads and store the main preferences of the application
|
This class reads and store the main preferences of the application
|
||||||
|
|
||||||
File History:
|
File History:
|
||||||
Created: 2018-0+-22 [0.0.1]
|
Created: 2018-09-22 [0.0.1]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -28,25 +28,18 @@ class Config:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
# Set Application Variables
|
# Set Application Variables
|
||||||
self.appName = nw.__package__
|
self.appName = nw.__package__
|
||||||
self.appHandle = nw.__package__.lower()
|
self.appHandle = nw.__package__.lower()
|
||||||
self.showGUI = True
|
self.showGUI = True
|
||||||
self.debugGUI = False
|
self.debugGUI = False
|
||||||
|
|
||||||
# Set Paths
|
# Set Paths
|
||||||
self.confPath = user_config_dir(self.appHandle)
|
self.confPath = None
|
||||||
self.confFile = self.appHandle+".conf"
|
self.confFile = None
|
||||||
self.homePath = path.expanduser("~")
|
self.homePath = None
|
||||||
self.appPath = path.dirname(__file__)
|
self.appPath = None
|
||||||
self.guiPath = path.join(self.appPath,"gui")
|
self.guiPath = None
|
||||||
self.themePath = path.join(self.appPath,"themes")
|
self.themePath = None
|
||||||
self.recentList = [""]*10
|
|
||||||
|
|
||||||
# If config folder does not exist, make it.
|
|
||||||
# This assumes that the os config folder itself exists.
|
|
||||||
# TODO: This does not work on Windows
|
|
||||||
if not path.isdir(self.confPath):
|
|
||||||
mkdir(self.confPath)
|
|
||||||
|
|
||||||
# Set default values
|
# Set default values
|
||||||
self.confChanged = False
|
self.confChanged = False
|
||||||
@@ -81,13 +74,8 @@ class Config:
|
|||||||
|
|
||||||
self.spellLanguage = "en_GB"
|
self.spellLanguage = "en_GB"
|
||||||
|
|
||||||
# Check if config file exists
|
# Path
|
||||||
if path.isfile(path.join(self.confPath,self.confFile)):
|
self.recentList = [""]*10
|
||||||
self.loadConfig()
|
|
||||||
|
|
||||||
# Save a copy of the default config if no file exists
|
|
||||||
if not path.isfile(path.join(self.confPath,self.confFile)):
|
|
||||||
self.saveConfig()
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -95,11 +83,41 @@ class Config:
|
|||||||
# Actions
|
# Actions
|
||||||
##
|
##
|
||||||
|
|
||||||
|
def initConfig(self, confPath=None):
|
||||||
|
|
||||||
|
if confPath is None:
|
||||||
|
self.confPath = user_config_dir(self.appHandle)
|
||||||
|
else:
|
||||||
|
logger.info("Setting config from alternative path: %s" % confPath)
|
||||||
|
self.confPath = confPath
|
||||||
|
|
||||||
|
self.confFile = self.appHandle+".conf"
|
||||||
|
self.homePath = path.expanduser("~")
|
||||||
|
self.appPath = path.dirname(__file__)
|
||||||
|
self.guiPath = path.join(self.appPath,"gui")
|
||||||
|
self.themePath = path.join(self.appPath,"themes")
|
||||||
|
|
||||||
|
# If config folder does not exist, make it.
|
||||||
|
# This assumes that the os config folder itself exists.
|
||||||
|
# TODO: This does not work on Windows
|
||||||
|
if not path.isdir(self.confPath):
|
||||||
|
mkdir(self.confPath)
|
||||||
|
|
||||||
|
# Check if config file exists
|
||||||
|
if path.isfile(path.join(self.confPath,self.confFile)):
|
||||||
|
# If it exists, load it
|
||||||
|
self.loadConfig()
|
||||||
|
else:
|
||||||
|
# If it does not exist, save a copy of the defaults
|
||||||
|
self.saveConfig()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def loadConfig(self):
|
def loadConfig(self):
|
||||||
|
|
||||||
logger.debug("Loading config file")
|
logger.debug("Loading config file")
|
||||||
confParser = configparser.ConfigParser()
|
confParser = configparser.ConfigParser()
|
||||||
confParser.readfp(open(path.join(self.confPath,self.confFile)))
|
confParser.read_file(open(path.join(self.confPath,self.confFile)))
|
||||||
|
|
||||||
# Get options
|
# Get options
|
||||||
|
|
||||||
@@ -214,10 +232,14 @@ class Config:
|
|||||||
confParser.set(cnfSec,"recent%d" % i, str(self.recentList[i]))
|
confParser.set(cnfSec,"recent%d" % i, str(self.recentList[i]))
|
||||||
|
|
||||||
# Write config file
|
# Write config file
|
||||||
confParser.write(open(path.join(self.confPath,self.confFile),"w"))
|
try:
|
||||||
self.confChanged = False
|
confParser.write(open(path.join(self.confPath,self.confFile),"w"))
|
||||||
|
self.confChanged = False
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Could not save config file")
|
||||||
|
return False
|
||||||
|
|
||||||
return
|
return True
|
||||||
|
|
||||||
def unpackList(self, inStr, listLen, listDefault, castTo=int):
|
def unpackList(self, inStr, listLen, listDefault, castTo=int):
|
||||||
inData = inStr.split(",")
|
inData = inStr.split(",")
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class GuiDocDetails(QFrame):
|
|||||||
logger.debug("Initialising DocDetails ...")
|
logger.debug("Initialising DocDetails ...")
|
||||||
self.mainConf = nw.CONFIG
|
self.mainConf = nw.CONFIG
|
||||||
self.debugGUI = self.mainConf.debugGUI
|
self.debugGUI = self.mainConf.debugGUI
|
||||||
|
self.theParent = theParent
|
||||||
self.theProject = theProject
|
self.theProject = theProject
|
||||||
|
|
||||||
self.mainBox = QGridLayout(self)
|
self.mainBox = QGridLayout(self)
|
||||||
@@ -70,11 +71,11 @@ class GuiDocDetails(QFrame):
|
|||||||
colTwo = [""]*4
|
colTwo = [""]*4
|
||||||
else:
|
else:
|
||||||
itemStatus = nwItem.itemStatus
|
itemStatus = nwItem.itemStatus
|
||||||
if itemStatus < 0 or itemStatus >= len(self.theProject.statusLabels):
|
if itemStatus < 0 or itemStatus >= len(self.theParent.statusLabels):
|
||||||
itemStatus = 0
|
itemStatus = 0
|
||||||
colTwo = [
|
colTwo = [
|
||||||
nwItem.itemName,
|
nwItem.itemName,
|
||||||
self.theProject.statusLabels[itemStatus],
|
self.theParent.statusLabels[itemStatus],
|
||||||
nwLabels.CLASS_NAME[nwItem.itemClass],
|
nwLabels.CLASS_NAME[nwItem.itemClass],
|
||||||
nwLabels.LAYOUT_NAME[nwItem.itemLayout],
|
nwLabels.LAYOUT_NAME[nwItem.itemLayout],
|
||||||
]
|
]
|
||||||
|
|||||||
+2
-2
@@ -252,12 +252,12 @@ class GuiDocTree(QTreeWidget):
|
|||||||
if nwItem.itemType == nwItemType.FILE:
|
if nwItem.itemType == nwItemType.FILE:
|
||||||
tStatus += "."+nwLabels.LAYOUT_FLAG[nwItem.itemLayout]
|
tStatus += "."+nwLabels.LAYOUT_FLAG[nwItem.itemLayout]
|
||||||
nStatus = nwItem.itemStatus
|
nStatus = nwItem.itemStatus
|
||||||
if nStatus < 0 or nStatus >= len(self.theProject.statusIcons):
|
if nStatus < 0 or nStatus >= len(self.theParent.statusIcons):
|
||||||
nStatus = 0
|
nStatus = 0
|
||||||
|
|
||||||
trItem.setText(self.C_NAME,tName)
|
trItem.setText(self.C_NAME,tName)
|
||||||
trItem.setText(self.C_FLAGS,tStatus)
|
trItem.setText(self.C_FLAGS,tStatus)
|
||||||
trItem.setIcon(self.C_FLAGS,self.theProject.statusIcons[nStatus])
|
trItem.setIcon(self.C_FLAGS,self.theParent.statusIcons[nStatus])
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
+26
-3
@@ -15,7 +15,7 @@ import nw
|
|||||||
|
|
||||||
from os import path
|
from os import path
|
||||||
from PyQt5.QtWidgets import QWidget, QMainWindow, QVBoxLayout, QFrame, QSplitter, QFileDialog, QStackedWidget, QShortcut, QMessageBox
|
from PyQt5.QtWidgets import QWidget, QMainWindow, QVBoxLayout, QFrame, QSplitter, QFileDialog, QStackedWidget, QShortcut, QMessageBox
|
||||||
from PyQt5.QtGui import QIcon
|
from PyQt5.QtGui import QIcon, QPixmap, QColor
|
||||||
from PyQt5.QtCore import Qt, QTimer
|
from PyQt5.QtCore import Qt, QTimer
|
||||||
|
|
||||||
from nw.gui.doctree import GuiDocTree
|
from nw.gui.doctree import GuiDocTree
|
||||||
@@ -57,6 +57,10 @@ class GuiMain(QMainWindow):
|
|||||||
self.mainMenu = GuiMainMenu(self, self.theProject)
|
self.mainMenu = GuiMainMenu(self, self.theProject)
|
||||||
self.statusBar = GuiMainStatus(self)
|
self.statusBar = GuiMainStatus(self)
|
||||||
|
|
||||||
|
# Minor Gui Elements
|
||||||
|
self.statusIcons = []
|
||||||
|
self.statusLabels = []
|
||||||
|
|
||||||
# Assemble Main Window
|
# Assemble Main Window
|
||||||
self.stackPane = QStackedWidget()
|
self.stackPane = QStackedWidget()
|
||||||
self.stackNone = self.stackPane.addWidget(QWidget())
|
self.stackNone = self.stackPane.addWidget(QWidget())
|
||||||
@@ -82,7 +86,7 @@ class GuiMain(QMainWindow):
|
|||||||
self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
|
self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
|
||||||
self.treeView.itemDoubleClicked.connect(self._treeDoubleClick)
|
self.treeView.itemDoubleClicked.connect(self._treeDoubleClick)
|
||||||
self.treeView.buildTree()
|
self.treeView.buildTree()
|
||||||
QShortcut(Qt.Key_Return, self.treeView, context=Qt.WidgetShortcut, activated=self._treeKeyPressReturn)
|
self._makeStatusIcons()
|
||||||
|
|
||||||
# Set Main Window Elements
|
# Set Main Window Elements
|
||||||
self.setMenuBar(self.mainMenu)
|
self.setMenuBar(self.mainMenu)
|
||||||
@@ -106,7 +110,15 @@ class GuiMain(QMainWindow):
|
|||||||
self.asDocTimer.timeout.connect(self._autoSaveDocument)
|
self.asDocTimer.timeout.connect(self._autoSaveDocument)
|
||||||
self.asDocTimer.start()
|
self.asDocTimer.start()
|
||||||
|
|
||||||
self.show()
|
# Keyboard Shortcuts
|
||||||
|
QShortcut(Qt.Key_Return, self.treeView, context=Qt.WidgetShortcut, activated=self._treeKeyPressReturn)
|
||||||
|
|
||||||
|
# Forward Functions
|
||||||
|
self.setStatus = self.statusBar.setStatus
|
||||||
|
self.setProjectStatus = self.statusBar.setProjectStatus
|
||||||
|
|
||||||
|
if self.mainConf.showGUI:
|
||||||
|
self.show()
|
||||||
|
|
||||||
logger.debug("GUI initialisation complete")
|
logger.debug("GUI initialisation complete")
|
||||||
|
|
||||||
@@ -162,6 +174,7 @@ class GuiMain(QMainWindow):
|
|||||||
self.treeView.buildTree()
|
self.treeView.buildTree()
|
||||||
self.mainMenu.updateRecentProjects()
|
self.mainMenu.updateRecentProjects()
|
||||||
self._setWindowTitle(self.theProject.projName)
|
self._setWindowTitle(self.theProject.projName)
|
||||||
|
self._makeStatusIcons()
|
||||||
self.docEditor.setPwl(path.join(self.theProject.projMeta,"wordlist.txt"))
|
self.docEditor.setPwl(path.join(self.theProject.projMeta,"wordlist.txt"))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -341,6 +354,16 @@ class GuiMain(QMainWindow):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _makeStatusIcons(self):
|
||||||
|
self.statusIcons = []
|
||||||
|
self.statusLabels = []
|
||||||
|
for sLabel, sR, sG, sB in self.theProject.statusCols:
|
||||||
|
theIcon = QPixmap(32,32)
|
||||||
|
theIcon.fill(QColor(sR,sG,sB))
|
||||||
|
self.statusIcons.append(QIcon(theIcon))
|
||||||
|
self.statusLabels.append(sLabel)
|
||||||
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Events
|
# Events
|
||||||
##
|
##
|
||||||
|
|||||||
+17
-25
@@ -19,8 +19,6 @@ from hashlib import sha256
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from PyQt5.QtGui import QIcon, QPixmap, QColor
|
|
||||||
|
|
||||||
from nw.enum import nwItemType, nwItemClass, nwItemLayout
|
from nw.enum import nwItemType, nwItemClass, nwItemLayout
|
||||||
from nw.project.item import NWItem
|
from nw.project.item import NWItem
|
||||||
|
|
||||||
@@ -31,10 +29,13 @@ class NWProject():
|
|||||||
def __init__(self, theParent):
|
def __init__(self, theParent):
|
||||||
|
|
||||||
# Internal
|
# Internal
|
||||||
self.mainConf = nw.CONFIG
|
|
||||||
self.theParent = theParent
|
self.theParent = theParent
|
||||||
|
self.mainConf = self.theParent.mainConf
|
||||||
self.projChanged = None
|
self.projChanged = None
|
||||||
|
|
||||||
|
# Debug
|
||||||
|
self.handleSeed = None
|
||||||
|
|
||||||
# Project Settings
|
# Project Settings
|
||||||
self.projTree = None
|
self.projTree = None
|
||||||
self.treeOrder = None
|
self.treeOrder = None
|
||||||
@@ -48,8 +49,6 @@ class NWProject():
|
|||||||
self.bookTitle = None
|
self.bookTitle = None
|
||||||
self.bookAuthors = None
|
self.bookAuthors = None
|
||||||
self.statusCols = None
|
self.statusCols = None
|
||||||
self.statusIcons = None
|
|
||||||
self.statusLabels = None
|
|
||||||
|
|
||||||
self.clearProject()
|
self.clearProject()
|
||||||
|
|
||||||
@@ -60,6 +59,9 @@ class NWProject():
|
|||||||
##
|
##
|
||||||
|
|
||||||
def newRoot(self, rootName, rootClass):
|
def newRoot(self, rootName, rootClass):
|
||||||
|
if not self.checkRootUnique(rootClass):
|
||||||
|
self.theParent.makeAlert("Duplicate root item detected!",2)
|
||||||
|
return None
|
||||||
newItem = NWItem()
|
newItem = NWItem()
|
||||||
newItem.setName(rootName)
|
newItem.setName(rootName)
|
||||||
newItem.setType(nwItemType.ROOT)
|
newItem.setType(nwItemType.ROOT)
|
||||||
@@ -110,7 +112,7 @@ class NWProject():
|
|||||||
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)
|
||||||
|
|
||||||
return
|
return True
|
||||||
|
|
||||||
def clearProject(self):
|
def clearProject(self):
|
||||||
|
|
||||||
@@ -128,16 +130,12 @@ class NWProject():
|
|||||||
self.projName = ""
|
self.projName = ""
|
||||||
self.bookTitle = ""
|
self.bookTitle = ""
|
||||||
self.bookAuthors = []
|
self.bookAuthors = []
|
||||||
|
|
||||||
self.statusCols = [
|
self.statusCols = [
|
||||||
("New", 100,100,100),
|
("New", 100,100,100),
|
||||||
("Note", 200, 50, 0),
|
("Note", 200, 50, 0),
|
||||||
("Draft", 200,150, 0),
|
("Draft", 200,150, 0),
|
||||||
("Finished", 50,200, 0),
|
("Finished", 50,200, 0),
|
||||||
]
|
]
|
||||||
self.statusIcons = []
|
|
||||||
self.statusLabels = []
|
|
||||||
self._makeStatusIcons()
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -205,9 +203,8 @@ class NWProject():
|
|||||||
nwItem.setFromTag(xValue.tag,xValue.text)
|
nwItem.setFromTag(xValue.tag,xValue.text)
|
||||||
self._appendItem(tHandle,pHandle,nwItem)
|
self._appendItem(tHandle,pHandle,nwItem)
|
||||||
|
|
||||||
self._makeStatusIcons()
|
|
||||||
self.mainConf.setRecent(self.projPath)
|
self.mainConf.setRecent(self.projPath)
|
||||||
self.theParent.statusBar.setStatus("Opened Project: %s" % self.projName)
|
self.theParent.setStatus("Opened Project: %s" % self.projName)
|
||||||
|
|
||||||
self._scanProjectFolder()
|
self._scanProjectFolder()
|
||||||
self.setProjectChanged(False)
|
self.setProjectChanged(False)
|
||||||
@@ -267,7 +264,7 @@ class NWProject():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
self.mainConf.setRecent(self.projPath)
|
self.mainConf.setRecent(self.projPath)
|
||||||
self.theParent.statusBar.setStatus("Saved Project: %s" % self.projName)
|
self.theParent.setStatus("Saved Project: %s" % self.projName)
|
||||||
self.setProjectChanged(False)
|
self.setProjectChanged(False)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -310,7 +307,7 @@ class NWProject():
|
|||||||
|
|
||||||
def setProjectChanged(self, bValue):
|
def setProjectChanged(self, bValue):
|
||||||
self.projChanged = bValue
|
self.projChanged = bValue
|
||||||
self.theParent.statusBar.setProjectStatus(self.projChanged)
|
self.theParent.setProjectStatus(self.projChanged)
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -430,18 +427,13 @@ class NWProject():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _makeStatusIcons(self):
|
|
||||||
self.statusIcons = []
|
|
||||||
self.statusLabels = []
|
|
||||||
for sLabel, sR, sG, sB in self.statusCols:
|
|
||||||
theIcon = QPixmap(32,32)
|
|
||||||
theIcon.fill(QColor(sR,sG,sB))
|
|
||||||
self.statusIcons.append(QIcon(theIcon))
|
|
||||||
self.statusLabels.append(sLabel)
|
|
||||||
return
|
|
||||||
|
|
||||||
def _makeHandle(self, addSeed=""):
|
def _makeHandle(self, addSeed=""):
|
||||||
newSeed = str(time()) + addSeed
|
if self.handleSeed is None:
|
||||||
|
newSeed = str(time()) + addSeed
|
||||||
|
else:
|
||||||
|
# This is used for debugging
|
||||||
|
newSeed = str(self.handleSeed)
|
||||||
|
self.handleSeed += 1
|
||||||
logger.verbose("Generating handle with seed '%s'" % newSeed)
|
logger.verbose("Generating handle with seed '%s'" % newSeed)
|
||||||
itemHandle = sha256(newSeed.encode()).hexdigest()[0:13]
|
itemHandle = sha256(newSeed.encode()).hexdigest()[0:13]
|
||||||
if itemHandle in self.projTree.keys():
|
if itemHandle in self.projTree.keys():
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""novelWriter Test Dummy GUI Classes
|
||||||
|
"""
|
||||||
|
|
||||||
|
class DummyMain():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.mainConf = None
|
||||||
|
return
|
||||||
|
|
||||||
|
def makeAlert(self, theMessage, theLevel):
|
||||||
|
if theLevel == 1:
|
||||||
|
lvlMsg = "WARNING: "
|
||||||
|
elif theLevel == 2:
|
||||||
|
lvlMsg = "ERROR: "
|
||||||
|
else:
|
||||||
|
lvlMsg = ""
|
||||||
|
if isinstance(theMessage, list):
|
||||||
|
for msgLine in logMsg:
|
||||||
|
print(lvlMsg+msgLine)
|
||||||
|
else:
|
||||||
|
print(lvlMsg+theMessage)
|
||||||
|
return
|
||||||
|
|
||||||
|
def setStatus(self, theMessage):
|
||||||
|
return
|
||||||
|
|
||||||
|
def setProjectStatus(self, isChanged):
|
||||||
|
return
|
||||||
|
|
||||||
|
# END Class GuiMain
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""novelWriter Test Tools
|
||||||
|
"""
|
||||||
|
|
||||||
|
from os import path, mkdir
|
||||||
|
|
||||||
|
def ensureDir(theDir):
|
||||||
|
if not path.isdir(theDir):
|
||||||
|
mkdir(theDir)
|
||||||
|
return
|
||||||
|
|
||||||
|
def cmpFiles(fileOne, fileTwo, ignoreLines=[]):
|
||||||
|
foOne = open(fileOne,mode="r")
|
||||||
|
foTwo = open(fileTwo,mode="r")
|
||||||
|
|
||||||
|
txtOne = foOne.readlines()
|
||||||
|
txtTwo = foTwo.readlines()
|
||||||
|
|
||||||
|
if len(txtOne) != len(txtTwo):
|
||||||
|
print("Files are not the same length")
|
||||||
|
return False
|
||||||
|
|
||||||
|
diffFound = False
|
||||||
|
for n in range(len(txtOne)):
|
||||||
|
lnOne = txtOne[n].strip()
|
||||||
|
lnTwo = txtTwo[n].strip()
|
||||||
|
|
||||||
|
if n+1 in ignoreLines:
|
||||||
|
print("Ignoring line %d" % (n+1))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if lnOne != lnTwo:
|
||||||
|
print("Diff on line %d:" % (n+1))
|
||||||
|
print(" << '%s'" % lnOne)
|
||||||
|
print(" >> '%s'" % lnTwo)
|
||||||
|
diffFound = True
|
||||||
|
|
||||||
|
foOne.close()
|
||||||
|
foTwo.close()
|
||||||
|
|
||||||
|
return not diffFound
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<novelWriterXML appVersion="0.1.0" fileVersion="1.0" timeStamp="2019-05-12 14:21:08">
|
||||||
|
<project>
|
||||||
|
<name></name>
|
||||||
|
<title></title>
|
||||||
|
</project>
|
||||||
|
<content count="6">
|
||||||
|
<item handle="73475cb40a568" order="None" parent="None">
|
||||||
|
<name>Novel</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>NOVEL</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="44cb730c42048" order="None" parent="None">
|
||||||
|
<name>Characters</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>CHARACTER</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="71ee45a3c0db9" order="None" parent="None">
|
||||||
|
<name>Plot</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>PLOT</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="811786ad1ae74" order="None" parent="None">
|
||||||
|
<name>World</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>WORLD</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="25fc0e7096fc6" order="None" parent="73475cb40a568">
|
||||||
|
<name>New Chapter</name>
|
||||||
|
<type>FOLDER</type>
|
||||||
|
<class>NOVEL</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="31489056e0916" order="None" parent="25fc0e7096fc6">
|
||||||
|
<name>New Scene</name>
|
||||||
|
<type>FILE</type>
|
||||||
|
<class>NOVEL</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
<layout>SCENE</layout>
|
||||||
|
<charCount>0</charCount>
|
||||||
|
<wordCount>0</wordCount>
|
||||||
|
<paraCount>0</paraCount>
|
||||||
|
</item>
|
||||||
|
</content>
|
||||||
|
</novelWriterXML>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
[Main]
|
||||||
|
timestamp = 2019-05-12 12:04:16
|
||||||
|
|
||||||
|
[Sizes]
|
||||||
|
geometry = 1100, 650
|
||||||
|
treecols = 120, 30, 50
|
||||||
|
mainpane = 300, 800
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
autosaveproject = 60
|
||||||
|
autosavedoc = 30
|
||||||
|
|
||||||
|
[Editor]
|
||||||
|
fixedwidth = True
|
||||||
|
width = 600
|
||||||
|
margins = 40, 40
|
||||||
|
textsize = 13
|
||||||
|
justify = True
|
||||||
|
autoselect = True
|
||||||
|
autoreplace = True
|
||||||
|
repsquotes = True
|
||||||
|
repdquotes = True
|
||||||
|
repdash = True
|
||||||
|
repdots = True
|
||||||
|
spellcheck = en_GB
|
||||||
|
|
||||||
|
[Path]
|
||||||
|
recent0 =
|
||||||
|
recent1 =
|
||||||
|
recent2 =
|
||||||
|
recent3 =
|
||||||
|
recent4 =
|
||||||
|
recent5 =
|
||||||
|
recent6 =
|
||||||
|
recent7 =
|
||||||
|
recent8 =
|
||||||
|
recent9 =
|
||||||
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<novelWriterXML appVersion="0.1.0" fileVersion="1.0" timeStamp="2019-05-12 14:40:19">
|
||||||
|
<project>
|
||||||
|
<name></name>
|
||||||
|
<title></title>
|
||||||
|
</project>
|
||||||
|
<content count="10">
|
||||||
|
<item handle="73475cb40a568" order="None" parent="None">
|
||||||
|
<name>Novel</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>NOVEL</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="44cb730c42048" order="None" parent="None">
|
||||||
|
<name>Characters</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>CHARACTER</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="71ee45a3c0db9" order="None" parent="None">
|
||||||
|
<name>Plot</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>PLOT</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="811786ad1ae74" order="None" parent="None">
|
||||||
|
<name>World</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>WORLD</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="25fc0e7096fc6" order="None" parent="73475cb40a568">
|
||||||
|
<name>New Chapter</name>
|
||||||
|
<type>FOLDER</type>
|
||||||
|
<class>NOVEL</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="31489056e0916" order="None" parent="25fc0e7096fc6">
|
||||||
|
<name>New Scene</name>
|
||||||
|
<type>FILE</type>
|
||||||
|
<class>NOVEL</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
<layout>SCENE</layout>
|
||||||
|
<charCount>0</charCount>
|
||||||
|
<wordCount>0</wordCount>
|
||||||
|
<paraCount>0</paraCount>
|
||||||
|
</item>
|
||||||
|
<item handle="39fa9ec190eee" order="None" parent="None">
|
||||||
|
<name>Timeline</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>TIMELINE</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="d029fa3a95e17" order="None" parent="None">
|
||||||
|
<name>Object</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>OBJECT</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="81b8a03f97e87" order="None" parent="None">
|
||||||
|
<name>Custom1</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>CUSTOM</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
<item handle="da4ea2a5506f2" order="None" parent="None">
|
||||||
|
<name>Custom2</name>
|
||||||
|
<type>ROOT</type>
|
||||||
|
<class>CUSTOM</class>
|
||||||
|
<status>0</status>
|
||||||
|
<expanded>False</expanded>
|
||||||
|
</item>
|
||||||
|
</content>
|
||||||
|
</novelWriterXML>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""novelWriter Config Class Tester
|
||||||
|
"""
|
||||||
|
|
||||||
|
import nw
|
||||||
|
from nwtools import *
|
||||||
|
from os import path, unlink
|
||||||
|
from nw.config import Config
|
||||||
|
|
||||||
|
theConf = Config()
|
||||||
|
testDir = path.dirname(__file__)
|
||||||
|
testTemp = path.join(testDir,"temp")
|
||||||
|
testRef = path.join(testDir,"reference")
|
||||||
|
tmpConf = path.join(testTemp,"novelwriter.conf")
|
||||||
|
refConf = path.join(testRef, "novelwriter.conf")
|
||||||
|
|
||||||
|
ensureDir(testTemp)
|
||||||
|
|
||||||
|
# Clean out old stuff
|
||||||
|
if path.isfile(tmpConf):
|
||||||
|
unlink(tmpConf)
|
||||||
|
|
||||||
|
def testConfigInit():
|
||||||
|
assert theConf.initConfig(testTemp)
|
||||||
|
assert cmpFiles(tmpConf, refConf, [2])
|
||||||
|
|
||||||
|
def testConfigSave():
|
||||||
|
assert theConf.saveConfig()
|
||||||
|
assert cmpFiles(tmpConf, refConf, [2])
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""novelWriter Project Class Tester
|
||||||
|
"""
|
||||||
|
|
||||||
|
import nw
|
||||||
|
import types
|
||||||
|
from os import path, unlink
|
||||||
|
|
||||||
|
from nwtools import *
|
||||||
|
from nwdummy import DummyMain
|
||||||
|
|
||||||
|
from nw.config import Config
|
||||||
|
from nw.project.project import NWProject
|
||||||
|
from nw.project.item import NWItem
|
||||||
|
from nw.enum import nwItemClass
|
||||||
|
|
||||||
|
theConf = Config()
|
||||||
|
theMain = DummyMain()
|
||||||
|
theMain.mainConf = theConf
|
||||||
|
testDir = path.dirname(__file__)
|
||||||
|
testTemp = path.join(testDir,"temp")
|
||||||
|
testRef = path.join(testDir,"reference")
|
||||||
|
testProj = path.join(testTemp,"proj")
|
||||||
|
|
||||||
|
ensureDir(testTemp)
|
||||||
|
ensureDir(testProj)
|
||||||
|
|
||||||
|
theConf.initConfig(testRef)
|
||||||
|
theProject = NWProject(theMain)
|
||||||
|
theProject.handleSeed = 42
|
||||||
|
|
||||||
|
projFile = path.join(testProj,"nwProject.nwx")
|
||||||
|
|
||||||
|
def testProjectNew():
|
||||||
|
assert theProject.newProject()
|
||||||
|
assert theProject.setProjectPath(testProj)
|
||||||
|
assert theProject.saveProject()
|
||||||
|
assert cmpFiles(projFile, path.join(testRef,"new_nwProject.nwx"), [2])
|
||||||
|
|
||||||
|
def testProjectOpen():
|
||||||
|
assert theProject.openProject(projFile)
|
||||||
|
|
||||||
|
def testProjectSave():
|
||||||
|
assert theProject.saveProject()
|
||||||
|
assert cmpFiles(projFile, path.join(testRef,"new_nwProject.nwx"), [2])
|
||||||
|
assert not theProject.projChanged
|
||||||
|
|
||||||
|
def testProjectNewRoot():
|
||||||
|
assert theProject.openProject(projFile)
|
||||||
|
assert isinstance(theProject.newRoot("Novel", nwItemClass.NOVEL), type(None))
|
||||||
|
assert isinstance(theProject.newRoot("Plot", nwItemClass.PLOT), type(None))
|
||||||
|
assert isinstance(theProject.newRoot("Character", nwItemClass.CHARACTER), type(None))
|
||||||
|
assert isinstance(theProject.newRoot("World", nwItemClass.WORLD), type(None))
|
||||||
|
assert isinstance(theProject.newRoot("Timeline", nwItemClass.TIMELINE), str)
|
||||||
|
assert isinstance(theProject.newRoot("Object", nwItemClass.OBJECT), str)
|
||||||
|
assert isinstance(theProject.newRoot("Custom1", nwItemClass.CUSTOM), str)
|
||||||
|
assert isinstance(theProject.newRoot("Custom2", nwItemClass.CUSTOM), str)
|
||||||
|
assert theProject.projChanged
|
||||||
|
assert theProject.saveProject()
|
||||||
|
assert cmpFiles(projFile, path.join(testRef,"roots_nwProject.nwx"), [2])
|
||||||
|
assert not theProject.projChanged
|
||||||
Reference in New Issue
Block a user