Merge pull request #17 from vkbo/extended_project_editor

Extended Project Editor
This commit is contained in:
Veronica K. Berglyd Olsen
2019-05-22 23:38:33 +02:00
committed by GitHub
18 changed files with 668 additions and 303 deletions
+1 -12
View File
@@ -70,20 +70,9 @@ class GuiDocDetails(QFrame):
if nwItem is None: if nwItem is None:
colTwo = [""]*4 colTwo = [""]*4
else: else:
itemStatus = nwItem.itemStatus
if nwItem.itemClass == nwItemClass.NOVEL:
if itemStatus < 0 or itemStatus >= len(self.theParent.statusLabels):
statusLabel = self.theParent.statusLabels[0]
else:
statusLabel = self.theParent.statusLabels[itemStatus]
else:
if itemStatus < 0 or itemStatus >= len(self.theParent.importLabels):
statusLabel = self.theParent.importLabels[0]
else:
statusLabel = self.theParent.importLabels[itemStatus]
colTwo = [ colTwo = [
nwItem.itemName, nwItem.itemName,
statusLabel, nwItem.itemStatus,
nwLabels.CLASS_NAME[nwItem.itemClass], nwLabels.CLASS_NAME[nwItem.itemClass],
nwLabels.LAYOUT_NAME[nwItem.itemLayout], nwLabels.LAYOUT_NAME[nwItem.itemLayout],
] ]
-111
View File
@@ -1,111 +0,0 @@
# -*- coding: utf-8 -*-
"""novelWriter GUI Document Tabs
novelWriter GUI Document Tabs
=================================
Class holding the document tab view
File History:
Created: 2018-09-29 [0.0.1]
"""
import logging
import nw
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QTabWidget, QWidget, QVBoxLayout
from nw.gui.doceditor import GuiDocEditor
from nw.gui.projecteditor import GuiProjectEditor
from nw.gui.aboutview import GuiAboutView
logger = logging.getLogger(__name__)
class GuiDocTabs(QTabWidget):
def __init__(self):
QTabWidget.__init__(self)
logger.debug("Initialising DocTabs ...")
self.mainConf = nw.CONFIG
self.tabList = []
self.resize(900,500)
self.setTabsClosable(True)
self.tabBar().tabCloseRequested.connect(self._doCloseTab)
self.createTab(None,nw.DOCTYPE_ABOUT)
logger.debug("DocTabs initialisation complete")
return
def createTab(self, theName=None, tabType=None):
if tabType == nw.DOCTYPE_ABOUT:
self._createTabAbout()
return True
elif tabType == nw.DOCTYPE_PROJECT:
self._createTabProject(theName)
return True
elif tabType == nw.DOCTYPE_DOC:
self._createTabDoc(theName)
return True
return False
#
# Internal Functions
#
def _createTabDoc(self, docName=None):
if docName is None:
tabName = "New Document"
else:
tabName = docName
thisTab = GuiDocEditor()
self.addTab(thisTab,tabName)
self.setCurrentWidget(thisTab)
return True
def _createTabProject(self, projectName=None):
"""Display or create the project settings page.
"""
for i in range(self.count()):
thisTab = self.widget(i)
if isinstance(thisTab, GuiProjectEditor):
self.setCurrentWidget(thisTab)
return True
if projectName is None:
tabName = "New Project"
else:
tabName = projectName
thisTab = GuiProjectEditor()
self.addTab(thisTab,tabName)
self.setCurrentWidget(thisTab)
return True
def _createTabAbout(self):
"""Display or create the About tab.
"""
for i in range(self.count()):
thisTab = self.widget(i)
if isinstance(thisTab, GuiAboutView):
self.setCurrentWidget(thisTab)
return True
thisTab = GuiAboutView()
self.addTab(thisTab,"About")
self.setCurrentWidget(thisTab)
return True
#
# Signals
#
def _doCloseTab(self, tabIdx):
logger.verbose("User requested tab %d to be closed." % tabIdx)
self.removeTab(tabIdx)
logger.verbose("Tab %d closed." % tabIdx)
return
# END Class GuiDocTabs
+7 -11
View File
@@ -229,7 +229,7 @@ class GuiDocTree(QTreeWidget):
trItemP.takeChild(tIndex) trItemP.takeChild(tIndex)
self.clearSelection() self.clearSelection()
trItemP.setSelected(True) trItemP.setSelected(True)
self.theProject.setProjectChanged(True) self.theProject.deleteItem(tHandle)
else: else:
self.makeAlert(["Cannot delete folder.","It is not empty."], nwAlert.ERROR) self.makeAlert(["Cannot delete folder.","It is not empty."], nwAlert.ERROR)
return return
@@ -259,19 +259,15 @@ class GuiDocTree(QTreeWidget):
tStatus = nwLabels.CLASS_FLAG[nwItem.itemClass] tStatus = nwLabels.CLASS_FLAG[nwItem.itemClass]
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 iStatus = nwItem.itemStatus
if tClass == nwItemClass.NOVEL: if tClass == nwItemClass.NOVEL:
if nStatus < 0 or nStatus >= len(self.theParent.statusIcons): iStatus = self.theProject.statusItems.checkEntry(iStatus) # Make sure it's a valid index
flagIcon = self.theParent.statusIcons[0] flagIcon = self.theParent.statusIcons[iStatus]
else:
flagIcon = self.theParent.statusIcons[nStatus]
else: else:
if nStatus < 0 or nStatus >= len(self.theParent.importIcons): iStatus = self.theProject.importItems.checkEntry(iStatus) # Make sure it's a valid index
flagIcon = self.theParent.importIcons[0] flagIcon = self.theParent.importIcons[iStatus]
else:
flagIcon = self.theParent.importIcons[nStatus]
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,flagIcon) trItem.setIcon(self.C_FLAGS,flagIcon)
+4 -4
View File
@@ -55,14 +55,14 @@ class GuiItemEditor(QDialog):
self.editLayout = QComboBox() self.editLayout = QComboBox()
if self.theItem.itemClass == nwItemClass.NOVEL: if self.theItem.itemClass == nwItemClass.NOVEL:
for n in range(len(self.theParent.statusLabels)): for sLabel, _, _ in self.theProject.statusItems:
self.editStatus.addItem( self.editStatus.addItem(
self.theParent.statusIcons[n], self.theParent.statusLabels[n], n self.theParent.statusIcons[sLabel], sLabel, sLabel
) )
else: else:
for n in range(len(self.theParent.statusLabels)): for sLabel, _, _ in self.theProject.importItems:
self.editStatus.addItem( self.editStatus.addItem(
self.theParent.importIcons[n], self.theParent.importLabels[n], n self.theParent.importIcons[sLabel], sLabel, sLabel
) )
self.validLayouts = [] self.validLayouts = []
+228 -32
View File
@@ -13,21 +13,29 @@
import logging import logging
import nw import nw
from os import path from os import path
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QVBoxLayout, QGroupBox, QFormLayout, QLineEdit, QPlainTextEdit, QPushButton from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush
from PyQt5.QtSvg import QSvgWidget from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import (
QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel,
QWidget, QTabWidget, QDialogButtonBox, QListWidget, QListWidgetItem, QPushButton,
QColorDialog, QAbstractItemView
)
from nw.enum import nwAlert
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class GuiProjectEditor(QDialog): class GuiProjectEditor(QDialog):
def __init__(self, guiParent, theProject): def __init__(self, theParent, theProject):
QDialog.__init__(self, guiParent) QDialog.__init__(self, theParent)
logger.debug("Initialising ProjectEditor ...") logger.debug("Initialising ProjectEditor ...")
self.mainConf = nw.CONFIG self.mainConf = nw.CONFIG
self.theParent = theParent
self.theProject = theProject self.theProject = theProject
self.outerBox = QHBoxLayout() self.outerBox = QHBoxLayout()
self.innerBox = QVBoxLayout() self.innerBox = QVBoxLayout()
@@ -37,13 +45,72 @@ class GuiProjectEditor(QDialog):
self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","block.svg")) self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","block.svg"))
self.svgGradient = QSvgWidget(self.gradPath) self.svgGradient = QSvgWidget(self.gradPath)
self.svgGradient.setFixedWidth(80) self.svgGradient.setFixedWidth(80)
self.theProject.countStatus()
self.tabMain = GuiProjectEditMain(self.theParent, self.theProject)
self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject.statusItems)
self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject.importItems)
self.tabWidget = QTabWidget()
self.tabWidget.addTab(self.tabMain, "Settings")
self.tabWidget.addTab(self.tabStatus,"Status")
self.tabWidget.addTab(self.tabImport,"Importance")
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self.outerBox.addWidget(self.svgGradient) self.outerBox.addWidget(self.svgGradient)
self.outerBox.addLayout(self.innerBox) self.outerBox.addLayout(self.innerBox)
self.mainGroup = QGroupBox("Project Settings") self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.mainForm = QFormLayout() self.buttonBox.accepted.connect(self._doSave)
self.buttonBox.rejected.connect(self._doClose)
self.innerBox.addWidget(self.tabWidget)
self.innerBox.addWidget(self.buttonBox)
self.show()
logger.debug("ProjectEditor initialisation complete")
return
def _doSave(self):
logger.verbose("ProjectEditor save button clicked")
projName = self.tabMain.editName.text()
bookTitle = self.tabMain.editTitle.text()
bookAuthors = self.tabMain.editAuthors.toPlainText()
self.theProject.setProjectName(projName)
self.theProject.setBookTitle(bookTitle)
self.theProject.setBookAuthors(bookAuthors)
if self.tabStatus.colChanged:
statusCol = self.tabStatus.getNewList()
self.theProject.setStatusColours(statusCol)
if self.tabImport.colChanged:
importCol = self.tabImport.getNewList()
self.theProject.setImportColours(importCol)
if self.tabStatus.colChanged or self.tabImport.colChanged:
self.theParent.rebuildTree()
self.close()
return
def _doClose(self):
logger.verbose("ProjectEditor close button clicked")
self.close()
return
# END Class GuiProjectEditor
class GuiProjectEditMain(QWidget):
def __init__(self, theParent, theProject):
QWidget.__init__(self, theParent)
self.theParent = theParent
self.theProject = theProject
self.mainForm = QFormLayout()
self.editName = QLineEdit() self.editName = QLineEdit()
self.editTitle = QLineEdit() self.editTitle = QLineEdit()
self.editAuthors = QPlainTextEdit() self.editAuthors = QPlainTextEdit()
@@ -59,40 +126,169 @@ class GuiProjectEditor(QDialog):
bookAuthors += bookAuthor+"\n" bookAuthors += bookAuthor+"\n"
self.editAuthors.setPlainText(bookAuthors) self.editAuthors.setPlainText(bookAuthors)
self.buttonBox = QHBoxLayout() self.setLayout(self.mainForm)
self.closeButton = QPushButton("Close")
self.closeButton.clicked.connect(self._doClose) return
# END Class GuiProjectEditMain
class GuiProjectEditStatus(QWidget):
def __init__(self, theParent, theStatus):
QWidget.__init__(self, theParent)
self.theParent = theParent
self.theStatus = theStatus
self.colData = []
self.colCounts = []
self.colChanged = False
self.selColour = None
self.mainBox = QHBoxLayout()
self.mainForm = QVBoxLayout()
self.listBox = QListWidget()
self.listBox.setDragDropMode(QAbstractItemView.InternalMove)
self.listBox.itemSelectionChanged.connect(self._selectedItem)
self.listBox.model().rowsMoved.connect(self._rowsMoved)
for iName, iCol, nUse in self.theStatus:
self._addItem(iName, iCol, iName, nUse)
self.editName = QLineEdit()
self.newButton = QPushButton("New")
self.delButton = QPushButton("Delete")
self.saveButton = QPushButton("Save") self.saveButton = QPushButton("Save")
self.saveButton.clicked.connect(self._doSave) self.colPixmap = QPixmap(16,16)
self.buttonBox.addStretch(1) self.colPixmap.fill(QColor(120,120,120))
self.buttonBox.addWidget(self.closeButton) self.colButton = QPushButton(QIcon(self.colPixmap),"Colour")
self.buttonBox.addWidget(self.saveButton) self.colButton.setIconSize(self.colPixmap.rect().size())
self.mainGroup.setLayout(self.mainForm) self.newButton.clicked.connect(self._newItem)
self.innerBox.addWidget(self.mainGroup) self.delButton.clicked.connect(self._delItem)
self.innerBox.addLayout(self.buttonBox) self.saveButton.clicked.connect(self._saveItem)
self.colButton.clicked.connect(self._selectColour)
self.show() self.mainForm.addWidget(self.newButton)
self.mainForm.addWidget(self.delButton)
self.mainForm.addStretch(1)
self.mainForm.addWidget(QLabel("<b>Name</b>"))
self.mainForm.addWidget(self.editName)
self.mainForm.addWidget(self.colButton)
self.mainForm.addStretch(1)
self.mainForm.addWidget(self.saveButton)
logger.debug("ProjectEditor initialisation complete") self.mainBox.addWidget(self.listBox)
self.mainBox.addLayout(self.mainForm)
self.setLayout(self.mainBox)
return return
def _doSave(self): def getNewList(self):
logger.verbose("ProjectEditor save button clicked") if self.colChanged:
projName = self.editName.text() newList = []
bookTitle = self.editTitle.text() for n in range(self.listBox.count()):
bookAuthors = self.editAuthors.toPlainText() nItem = self.listBox.item(n)
self.theProject.setProjectName(projName) nIdx = nItem.data(Qt.UserRole)
self.theProject.setBookTitle(bookTitle) newList.append(self.colData[nIdx])
self.theProject.setBookAuthors(bookAuthors) return newList
self.theProject.setProjectChanged(True) return None
self.close()
##
# User Actions
##
def _selectColour(self):
logger.verbose("Item colour button clicked")
if self.selColour is not None:
newCol = QColorDialog.getColor(self.selColour, self, "Select Colour", QColorDialog.DontUseNativeDialog)
if newCol:
self.selColour = newCol
colPixmap = QPixmap(16,16)
colPixmap.fill(newCol)
self.colButton.setIcon(QIcon(colPixmap))
self.colButton.setIconSize(colPixmap.rect().size())
return return
def _doClose(self): def _newItem(self):
logger.verbose("ProjectEditor close button clicked") logger.verbose("New item button clicked")
self.close() newItem = self._addItem("New Item", (0, 0, 0), None, 0)
newItem.setBackground(QBrush(QColor(0,255,0,80)))
self.colChanged = True
return return
# END Class GuiProjectEditor def _delItem(self):
logger.verbose("Delete item button clicked")
selItem = self._getSelectedItem()
if selItem is not None:
iRow = self.listBox.row(selItem)
selIdx = selItem.data(Qt.UserRole)
if self.colCounts[selIdx] == 0:
self.listBox.takeItem(iRow)
self.colChanged = True
else:
self.theParent.makeAlert("Cannot delete status item that is in use.",nwAlert.ERROR)
return
def _saveItem(self):
logger.verbose("Save item button clicked")
selItem = self._getSelectedItem()
iRow = self.listBox.row(selItem)
if selItem is not None:
selIdx = selItem.data(Qt.UserRole)
self.colData[selIdx] = (
self.editName.text().strip(),
self.selColour.red(),
self.selColour.green(),
self.selColour.blue(),
self.colData[selIdx][4]
)
selItem.setText("%s [%d]" % (self.colData[selIdx][0], self.colCounts[selIdx]))
selItem.setIcon(self.colButton.icon())
self.colChanged = True
return
def _addItem(self, iName, iCol, oName, nUse):
newIcon = QPixmap(16,16)
newIcon.fill(QColor(*iCol))
newItem = QListWidgetItem()
newItem.setText("%s [%d]" % (iName, nUse))
newItem.setIcon(QIcon(newIcon))
newItem.setData(Qt.UserRole, len(self.colData))
self.listBox.addItem(newItem)
self.colData.append((iName,*iCol,oName))
self.colCounts.append(nUse)
return newItem
def _selectedItem(self):
logger.verbose("Item selected")
selItem = self._getSelectedItem()
if selItem is not None:
selIdx = selItem.data(Qt.UserRole)
selVal = self.colData[selIdx]
self.selColour = QColor(selVal[1],selVal[2],selVal[3])
newIcon = QPixmap(16,16)
newIcon.fill(self.selColour)
self.editName.setText(selVal[0])
self.colButton.setIcon(QIcon(newIcon))
return
##
# Internal Functions
##
def _getSelectedItem(self):
selItem = self.listBox.selectedItems()
if len(selItem) == 0:
return None
if isinstance(selItem[0], QListWidgetItem):
return selItem[0]
return None
def _rowsMoved(self):
logger.verbose("A drag move event occurred")
self.colChanged = True
return
# END Class GuiProjectEditStatus
+18 -20
View File
@@ -61,10 +61,8 @@ class GuiMain(QMainWindow):
self.statusBar = GuiMainStatus(self) self.statusBar = GuiMainStatus(self)
# Minor Gui Elements # Minor Gui Elements
self.statusIcons = [] self.statusIcons = []
self.statusLabels = [] self.importIcons = []
self.importIcons = []
self.importLabels = []
# Assemble Main Window # Assemble Main Window
self.treePane = QFrame() self.treePane = QFrame()
@@ -186,12 +184,9 @@ class GuiMain(QMainWindow):
projFile = self.openProjectDialog() projFile = self.openProjectDialog()
if projFile is None: if projFile is None:
return False return False
self.treeView.clearTree()
self.theProject.openProject(projFile) self.theProject.openProject(projFile)
self.treeView.buildTree()
self._setWindowTitle(self.theProject.projName) self._setWindowTitle(self.theProject.projName)
self._makeStatusIcons() self.rebuildTree()
self._makeImportIcons()
self.docEditor.setPwl(path.join(self.theProject.projMeta,"wordlist.txt")) self.docEditor.setPwl(path.join(self.theProject.projMeta,"wordlist.txt"))
self.docEditor.setSpellCheck(self.theProject.spellCheck) self.docEditor.setSpellCheck(self.theProject.spellCheck)
self.mainMenu.updateMenu() self.mainMenu.updateMenu()
@@ -302,6 +297,13 @@ class GuiMain(QMainWindow):
return return
def rebuildTree(self):
self._makeStatusIcons()
self._makeImportIcons()
self.treeView.clearTree()
self.treeView.buildTree()
return
## ##
# Main Dialogs # Main Dialogs
## ##
@@ -397,23 +399,19 @@ class GuiMain(QMainWindow):
return True return True
def _makeStatusIcons(self): def _makeStatusIcons(self):
self.statusIcons = [] self.statusIcons = {}
self.statusLabels = [] for sLabel, sCol, _ in self.theProject.statusItems:
for sLabel, sR, sG, sB in self.theProject.statusCols:
theIcon = QPixmap(32,32) theIcon = QPixmap(32,32)
theIcon.fill(QColor(sR,sG,sB)) theIcon.fill(QColor(*sCol))
self.statusIcons.append(QIcon(theIcon)) self.statusIcons[sLabel] = QIcon(theIcon)
self.statusLabels.append(sLabel)
return return
def _makeImportIcons(self): def _makeImportIcons(self):
self.importIcons = [] self.importIcons = {}
self.importLabels = [] for sLabel, sCol, _ in self.theProject.importItems:
for sLabel, sR, sG, sB in self.theProject.importCols:
theIcon = QPixmap(32,32) theIcon = QPixmap(32,32)
theIcon.fill(QColor(sR,sG,sB)) theIcon.fill(QColor(*sCol))
self.importIcons.append(QIcon(theIcon)) self.importIcons[sLabel] = QIcon(theIcon)
self.importLabels.append(sLabel)
return return
## ##
+1 -2
View File
@@ -15,8 +15,7 @@ import nw
from os import path, mkdir, rename, unlink from os import path, mkdir, rename, unlink
from nw.tools.analyse import TextAnalysis from nw.enum import nwAlert
from nw.enum import nwAlert
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
+8 -4
View File
@@ -26,7 +26,9 @@ class NWItem():
MAX_DEPTH = 8 MAX_DEPTH = 8
def __init__(self): def __init__(self, theProject):
self.theProject = theProject
self.itemName = "" self.itemName = ""
self.itemHandle = None self.itemHandle = None
@@ -35,7 +37,7 @@ class NWItem():
self.itemType = nwItemType.NO_TYPE self.itemType = nwItemType.NO_TYPE
self.itemClass = nwItemClass.NO_CLASS self.itemClass = nwItemClass.NO_CLASS
self.itemLayout = nwItemLayout.NO_LAYOUT self.itemLayout = nwItemLayout.NO_LAYOUT
self.itemStatus = 0 self.itemStatus = None
self.isExpanded = False self.isExpanded = False
# Document Meta Data # Document Meta Data
@@ -158,8 +160,10 @@ class NWItem():
return return
def setStatus(self, theStatus): def setStatus(self, theStatus):
theStatus = checkInt(theStatus,0) if self.itemClass == nwItemClass.NOVEL:
self.itemStatus = theStatus self.itemStatus = self.theProject.statusItems.checkEntry(theStatus)
else:
self.itemStatus = self.theProject.importItems.checkEntry(theStatus)
return return
def setExpanded(self, expState): def setExpanded(self, expState):
+76 -28
View File
@@ -13,15 +13,16 @@
import logging import logging
import nw import nw
from os import path, mkdir, listdir from os import path, mkdir, listdir
from lxml import etree from lxml import etree
from hashlib import sha256 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.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
from nw.common import checkString, checkBool from nw.common import checkString, checkBool
from nw.project.item import NWItem from nw.project.item import NWItem
from nw.project.status import NWStatus
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -54,8 +55,8 @@ class NWProject():
# Project Settings # Project Settings
self.spellCheck = False self.spellCheck = False
self.statusCols = None self.statusItems = None
self.importCols = None self.importItems = None
self.lastEdited = None self.lastEdited = None
self.lastViewed = None self.lastViewed = None
@@ -75,23 +76,25 @@ class NWProject():
if not self.checkRootUnique(rootClass): if not self.checkRootUnique(rootClass):
self.makeAlert("Duplicate root item detected!", nwAlert.ERROR) self.makeAlert("Duplicate root item detected!", nwAlert.ERROR)
return None return None
newItem = NWItem() newItem = NWItem(self)
newItem.setName(rootName) newItem.setName(rootName)
newItem.setType(nwItemType.ROOT) newItem.setType(nwItemType.ROOT)
newItem.setClass(rootClass) newItem.setClass(rootClass)
newItem.setStatus(0)
self._appendItem(None,None,newItem) self._appendItem(None,None,newItem)
return newItem.itemHandle return newItem.itemHandle
def newFolder(self, folderName, folderClass, pHandle): def newFolder(self, folderName, folderClass, pHandle):
newItem = NWItem() newItem = NWItem(self)
newItem.setName(folderName) newItem.setName(folderName)
newItem.setType(nwItemType.FOLDER) newItem.setType(nwItemType.FOLDER)
newItem.setClass(folderClass) newItem.setClass(folderClass)
newItem.setStatus(0)
self._appendItem(None,pHandle,newItem) self._appendItem(None,pHandle,newItem)
return newItem.itemHandle return newItem.itemHandle
def newFile(self, fileName, fileClass, pHandle): def newFile(self, fileName, fileClass, pHandle):
newItem = NWItem() newItem = NWItem(self)
newItem.setName(fileName) newItem.setName(fileName)
newItem.setType(nwItemType.FILE) newItem.setType(nwItemType.FILE)
if fileClass == nwItemClass.NOVEL: if fileClass == nwItemClass.NOVEL:
@@ -99,11 +102,12 @@ class NWProject():
else: else:
newItem.setLayout(nwItemLayout.NOTE) newItem.setLayout(nwItemLayout.NOTE)
newItem.setClass(fileClass) newItem.setClass(fileClass)
newItem.setStatus(0)
self._appendItem(None,pHandle,newItem) self._appendItem(None,pHandle,newItem)
return newItem.itemHandle return newItem.itemHandle
def addTrash(self): def addTrash(self):
newItem = NWItem() newItem = NWItem(self)
newItem.setName("Trash") newItem.setName("Trash")
newItem.setType(nwItemType.TRASH) newItem.setType(nwItemType.TRASH)
newItem.setClass(nwItemClass.TRASH) newItem.setClass(nwItemClass.TRASH)
@@ -144,18 +148,16 @@ class NWProject():
self.bookTitle = "" self.bookTitle = ""
self.bookAuthors = [] self.bookAuthors = []
self.spellCheck = False self.spellCheck = False
self.statusCols = [ self.statusItems = NWStatus()
("New", 100,100,100), self.statusItems.addEntry("New", (100,100,100))
("Note", 200, 50, 0), self.statusItems.addEntry("Note", (200, 50, 0))
("Draft", 200,150, 0), self.statusItems.addEntry("Draft", (200,150, 0))
("Finished", 50,200, 0), self.statusItems.addEntry("Finished",( 50,200, 0))
] self.importItems = NWStatus()
self.importCols = [ self.importItems.addEntry("New", (100,100,100))
("None", 100,100,100), self.importItems.addEntry("Minor", (200, 50, 0))
("Minor", 200, 50, 0), self.importItems.addEntry("Major", (200,150, 0))
("Major", 200,150, 0), self.importItems.addEntry("Main", ( 50,200, 0))
("Main", 50,200, 0),
]
return return
@@ -215,6 +217,10 @@ 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 == "status":
self.statusItems.unpackEntries(xItem)
if xItem.tag == "importance":
self.importItems.unpackEntries(xItem)
elif xChild.tag == "content": elif xChild.tag == "content":
logger.debug("Found project content") logger.debug("Found project content")
for xItem in xChild: for xItem in xChild:
@@ -228,7 +234,7 @@ class NWProject():
pHandle = itemAttrib["parent"] pHandle = itemAttrib["parent"]
else: else:
pHandle = None pHandle = None
nwItem = NWItem() nwItem = NWItem(self)
for xValue in xItem: for xValue in xItem:
nwItem.setFromTag(xValue.tag,xValue.text) nwItem.setFromTag(xValue.tag,xValue.text)
self._appendItem(tHandle,pHandle,nwItem) self._appendItem(tHandle,pHandle,nwItem)
@@ -276,6 +282,11 @@ class NWProject():
self._saveProjectValue(xSettings,"lastEdited",self.lastEdited) self._saveProjectValue(xSettings,"lastEdited",self.lastEdited)
self._saveProjectValue(xSettings,"lastViewed",self.lastViewed) self._saveProjectValue(xSettings,"lastViewed",self.lastViewed)
xStatus = etree.SubElement(xSettings,"status")
self.statusItems.packEntries(xStatus)
xStatus = etree.SubElement(xSettings,"importance")
self.importItems.packEntries(xStatus)
# Save Tree Content # Save Tree Content
logger.debug("Writing project content") logger.debug("Writing project content")
xContent = etree.SubElement(nwXML,"content",attrib={"count":str(len(self.treeOrder))}) xContent = etree.SubElement(nwXML,"content",attrib={"count":str(len(self.treeOrder))})
@@ -353,6 +364,26 @@ class NWProject():
self.setProjectChanged(True) self.setProjectChanged(True)
return True return True
def setStatusColours(self, newCols):
replaceMap = self.statusItems.setNewEntries(newCols)
if self.projTree is not None:
for nwItem in self.projTree.values():
if nwItem.itemClass == nwItemClass.NOVEL:
if nwItem.itemStatus in replaceMap.keys():
nwItem.setStatus(replaceMap[nwItem.itemStatus])
self.setProjectChanged(True)
return
def setImportColours(self, newCols,):
replaceMap = self.importItems.setNewEntries(newCols)
if self.projTree is not None:
for nwItem in self.projTree.values():
if nwItem.itemClass != nwItemClass.NOVEL:
if nwItem.itemStatus in replaceMap.keys():
nwItem.setStatus(replaceMap[nwItem.itemStatus])
self.setProjectChanged(True)
return
def setProjectChanged(self, bValue): def setProjectChanged(self, bValue):
self.projChanged = bValue self.projChanged = bValue
self.theParent.setProjectStatus(self.projChanged) self.theParent.setProjectStatus(self.projChanged)
@@ -409,6 +440,13 @@ class NWProject():
# Class Methods # Class Methods
## ##
def deleteItem(self, tHandle):
"""This only removes the item from the order list, but not from the project tree.
"""
self.treeOrder.remove(tHandle)
self.setProjectChanged(True)
return True
def findRootItem(self, theClass): def findRootItem(self, theClass):
for aRoot in self.treeRoots: for aRoot in self.treeRoots:
if theClass == self.projTree[aRoot].itemClass: if theClass == self.projTree[aRoot].itemClass:
@@ -426,6 +464,16 @@ class NWProject():
return False return False
return True return True
def countStatus(self):
self.statusItems.resetCounts()
self.importItems.resetCounts()
for nwItem in self.projTree.values():
if nwItem.itemClass == nwItemClass.NOVEL:
self.statusItems.countEntry(nwItem.itemStatus)
else:
self.importItems.countEntry(nwItem.itemStatus)
return
## ##
# Internal Functions # Internal Functions
## ##
@@ -492,7 +540,7 @@ class NWProject():
nOrph = 0 nOrph = 0
for oHandle in orphanFiles: for oHandle in orphanFiles:
nOrph += 1 nOrph += 1
orItem = NWItem() orItem = NWItem(self)
orItem.setName("Orphaned File %d" % nOrph) orItem.setName("Orphaned File %d" % nOrph)
orItem.setType(nwItemType.FILE) orItem.setType(nwItemType.FILE)
orItem.setClass(nwItemClass.NO_CLASS) orItem.setClass(nwItemClass.NO_CLASS)
+154
View File
@@ -0,0 +1,154 @@
# -*- coding: utf-8 -*-
"""novelWriter Item Status
novelWriter Item Status
===========================
Class holding the project's item statuses
File History:
Created: 2019-05-19 [0.1.3]
"""
import logging
import nw
from lxml import etree
from nw.enum import nwItemClass
from nw.common import checkInt
logger = logging.getLogger(__name__)
class NWStatus():
def __init__(self):
self.theLabels = []
self.theColours = []
self.theCounts = []
self.theMap = {}
self.theLength = 0
self.theIndex = 0
return
def addEntry(self, theLabel, theColours):
theLabel = theLabel.strip()
if self.lookupEntry(theLabel) is None:
self.theLabels.append(theLabel)
self.theColours.append(theColours)
self.theCounts.append(0)
self.theMap[theLabel] = self.theLength
self.theLength += 1
return True
def lookupEntry(self, theLabel):
theLabel = theLabel.strip()
if theLabel in self.theMap.keys():
return self.theMap[theLabel]
return None
def checkEntry(self, theStatus):
if isinstance(theStatus, str):
theStatus = theStatus.strip()
if self.lookupEntry(theStatus) is not None:
return theStatus
theStatus = checkInt(theStatus, 0, False)
if theStatus >= 0 and theStatus < self.theLength:
return self.theLabels[theStatus]
def setNewEntries(self, newList):
replaceMap = {}
if newList is not None:
self.theLabels = []
self.theColours = []
self.theCounts = []
self.theMap = {}
self.theLength = 0
self.theIndex = 0
for nName, nR, nG, nB, oName in newList:
self.addEntry(nName, (nR, nG, nB))
if nName != oName and oName is not None:
replaceMap[oName] = nName
return replaceMap
def resetCounts(self):
self.theCounts = [0]*self.theLength
return
def countEntry(self, theLabel):
theIndex = self.lookupEntry(theLabel)
if theIndex is not None:
self.theCounts[theIndex] += 1
return
def packEntries(self, xParent):
for n in range(self.theLength):
xSub = etree.SubElement(xParent,"entry",attrib={
"red" : str(self.theColours[n][0]),
"green" : str(self.theColours[n][1]),
"blue" : str(self.theColours[n][2]),
})
xSub.text = self.theLabels[n]
return True
def unpackEntries(self, xParent):
theLabels = []
theColours = []
for xChild in xParent:
theLabels.append(xChild.text)
if "red" in xChild.attrib:
cR = checkInt(xChild.attrib["red"],0,False)
else:
cR = 0
if "green" in xChild.attrib:
cG = checkInt(xChild.attrib["green"],0,False)
else:
cG = 0
if "blue" in xChild.attrib:
cB = checkInt(xChild.attrib["blue"],0,False)
else:
cB = 0
theColours.append((cR,cG,cB))
if len(theLabels) > 0:
self.theLabels = []
self.theColours = []
self.theCounts = []
self.theMap = {}
self.theLength = 0
self.theIndex = 0
for n in range(len(theLabels)):
self.addEntry(theLabels[n], theColours[n])
return True
##
# Iterator Bits
##
def __getitem__(self, n):
if n >= 0 and n < self.theLength:
return self.theLabels[n], self.theColours[n], self.theCounts[n]
return None, None, None
def __iter__(self):
self.theIndex = 0
return self
def __next__(self):
if self.theIndex < self.theLength:
theLabel, theColour, theCount = self.__getitem__(self.theIndex)
self.theIndex += 1
return theLabel, theColour, theCount
else:
raise StopIteration
# END Class NWStatus
@@ -15,6 +15,6 @@ So, this is some __text__ that weve been adding to this document. It is utter
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.
This one is a bit longer. “It also has some dialogue in it” she said, before she moved on to check if the spelllchecker 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.
+33 -18
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-19 14:27:22"> <novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 23:27:41">
<project> <project>
<name>Sample Project</name> <name>Sample Project</name>
<title>Sample Project</title> <title>Sample Project</title>
@@ -8,22 +8,37 @@
</project> </project>
<settings> <settings>
<spellCheck>True</spellCheck> <spellCheck>True</spellCheck>
<lastEdited>4cd0bd12b087d</lastEdited> <lastEdited>636b6aa9b697b</lastEdited>
<lastViewed>636b6aa9b697b</lastViewed> <lastViewed>636b6aa9b697b</lastViewed>
<status>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Notes</entry>
<entry blue="0" green="60" red="182">Started</entry>
<entry blue="0" green="129" red="193">1st Draft</entry>
<entry blue="0" green="129" red="193">2nd Draft</entry>
<entry blue="0" green="129" red="193">3rd Draft</entry>
<entry blue="58" green="180" red="58">Finished</entry>
</status>
<importance>
<entry blue="100" green="100" red="100">None</entry>
<entry blue="188" green="122" red="0">Minor</entry>
<entry blue="180" green="0" red="21">Major</entry>
<entry blue="175" green="0" red="117">Main</entry>
</importance>
</settings> </settings>
<content count="14"> <content count="14">
<item handle="7031beac91f75" order="0" parent="None"> <item handle="7031beac91f75" order="0" parent="None">
<name>Novel</name> <name>Novel</name>
<type>ROOT</type> <type>ROOT</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>True</expanded> <expanded>True</expanded>
</item> </item>
<item handle="53b69b83cdafc" order="0" parent="7031beac91f75"> <item handle="53b69b83cdafc" order="0" parent="7031beac91f75">
<name>Title Page</name> <name>Title Page</name>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>2</status> <status>Started</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>TITLE</layout> <layout>TITLE</layout>
<charCount>23</charCount> <charCount>23</charCount>
@@ -35,14 +50,14 @@
<name>Some Chapter</name> <name>Some Chapter</name>
<type>FOLDER</type> <type>FOLDER</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>1</status> <status>Notes</status>
<expanded>True</expanded> <expanded>True</expanded>
</item> </item>
<item handle="96b68994dfa3d" order="0" parent="e7ded148d6e4a"> <item handle="96b68994dfa3d" order="0" parent="e7ded148d6e4a">
<name>New Scene</name> <name>New Scene</name>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>2</status> <status>Started</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>2571</charCount> <charCount>2571</charCount>
@@ -54,19 +69,19 @@
<name>File With Stuff</name> <name>File With Stuff</name>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>1</status> <status>Notes</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>578</charCount> <charCount>577</charCount>
<wordCount>104</wordCount> <wordCount>104</wordCount>
<paraCount>5</paraCount> <paraCount>5</paraCount>
<cursorPos>658</cursorPos> <cursorPos>603</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>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>Notes</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>69</charCount> <charCount>69</charCount>
@@ -78,21 +93,21 @@
<name>Characters</name> <name>Characters</name>
<type>ROOT</type> <type>ROOT</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>None</status>
<expanded>True</expanded> <expanded>True</expanded>
</item> </item>
<item handle="f7e2d9f330615" order="0" parent="f6622b4617424"> <item handle="f7e2d9f330615" order="0" parent="f6622b4617424">
<name>Main Characters</name> <name>Main Characters</name>
<type>FOLDER</type> <type>FOLDER</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>None</status>
<expanded>True</expanded> <expanded>True</expanded>
</item> </item>
<item handle="14298de4d9524" order="0" parent="f7e2d9f330615"> <item handle="14298de4d9524" order="0" parent="f7e2d9f330615">
<name>John Smith</name> <name>John Smith</name>
<type>FILE</type> <type>FILE</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>Minor</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>NOTE</layout> <layout>NOTE</layout>
<charCount>42</charCount> <charCount>42</charCount>
@@ -104,7 +119,7 @@
<name>Jane Smith</name> <name>Jane Smith</name>
<type>FILE</type> <type>FILE</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>Major</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>NOTE</layout> <layout>NOTE</layout>
<charCount>51</charCount> <charCount>51</charCount>
@@ -116,14 +131,14 @@
<name>Locations</name> <name>Locations</name>
<type>ROOT</type> <type>ROOT</type>
<class>WORLD</class> <class>WORLD</class>
<status>0</status> <status>None</status>
<expanded>True</expanded> <expanded>True</expanded>
</item> </item>
<item handle="b3e74dbc1f584" order="0" parent="15c4492bd5107"> <item handle="b3e74dbc1f584" order="0" parent="15c4492bd5107">
<name>Earth</name> <name>Earth</name>
<type>FILE</type> <type>FILE</type>
<class>WORLD</class> <class>WORLD</class>
<status>0</status> <status>None</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>NOTE</layout> <layout>NOTE</layout>
<charCount>0</charCount> <charCount>0</charCount>
@@ -135,14 +150,14 @@
<name>Trash</name> <name>Trash</name>
<type>TRASH</type> <type>TRASH</type>
<class>TRASH</class> <class>TRASH</class>
<status>0</status> <status>None</status>
<expanded>True</expanded> <expanded>True</expanded>
</item> </item>
<item handle="4cd0bd12b087d" order="0" parent="98acd8c76c93a"> <item handle="4cd0bd12b087d" order="0" parent="98acd8c76c93a">
<name>Orphaned File 2</name> <name>Orphaned File 2</name>
<type>FILE</type> <type>FILE</type>
<class>NO_CLASS</class> <class>NO_CLASS</class>
<status>0</status> <status>None</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>NO_LAYOUT</layout> <layout>NO_LAYOUT</layout>
<charCount>14</charCount> <charCount>14</charCount>
+28 -16
View File
@@ -1,60 +1,72 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.2" fileVersion="1.0" timeStamp="2019-05-18 14:55:20"> <novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 21:14:26">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
</project> </project>
<settings> <settings>
<spellCheck>False</spellCheck> <spellCheck>True</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>31489056e0916</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>31489056e0916</lastViewed>
<status>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry>
<entry blue="0" green="150" red="200">Draft</entry>
<entry blue="0" green="200" red="50">Finished</entry>
</status>
<importance>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Minor</entry>
<entry blue="0" green="150" red="200">Major</entry>
<entry blue="0" green="200" red="50">Main</entry>
</importance>
</settings> </settings>
<content count="6"> <content count="6">
<item handle="73475cb40a568" order="0" parent="None"> <item handle="73475cb40a568" order="0" parent="None">
<name>Novel</name> <name>Novel</name>
<type>ROOT</type> <type>ROOT</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>True</expanded>
</item> </item>
<item handle="25fc0e7096fc6" order="0" parent="73475cb40a568"> <item handle="25fc0e7096fc6" order="0" parent="73475cb40a568">
<name>New Chapter</name> <name>New Chapter</name>
<type>FOLDER</type> <type>FOLDER</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>True</expanded>
</item> </item>
<item handle="31489056e0916" order="0" parent="25fc0e7096fc6"> <item handle="31489056e0916" order="0" parent="25fc0e7096fc6">
<name>New Scene</name> <name>New Scene</name>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>0</charCount> <charCount>377</charCount>
<wordCount>0</wordCount> <wordCount>69</wordCount>
<paraCount>0</paraCount> <paraCount>2</paraCount>
<cursorPos>0</cursorPos> <cursorPos>443</cursorPos>
</item> </item>
<item handle="44cb730c42048" order="1" parent="None"> <item handle="44cb730c42048" order="1" parent="None">
<name>Characters</name> <name>Characters</name>
<type>ROOT</type> <type>ROOT</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="71ee45a3c0db9" order="2" parent="None"> <item handle="71ee45a3c0db9" order="2" parent="None">
<name>Plot</name> <name>Plot</name>
<type>ROOT</type> <type>ROOT</type>
<class>PLOT</class> <class>PLOT</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="811786ad1ae74" order="3" parent="None"> <item handle="811786ad1ae74" order="3" parent="None">
<name>World</name> <name>World</name>
<type>ROOT</type> <type>ROOT</type>
<class>WORLD</class> <class>WORLD</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
</content> </content>
+19 -7
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.2" fileVersion="1.0" timeStamp="2019-05-18 14:58:58"> <novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 21:35:39">
<project> <project>
<name>Project Name</name> <name>Project Name</name>
<title>Project Title</title> <title>Project Title</title>
@@ -10,27 +10,39 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<status>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry>
<entry blue="0" green="200" red="50">Finished</entry>
<entry blue="0" green="0" red="0">Final</entry>
</status>
<importance>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Minor</entry>
<entry blue="0" green="150" red="200">Major</entry>
<entry blue="0" green="200" red="50">Main</entry>
</importance>
</settings> </settings>
<content count="6"> <content count="6">
<item handle="73475cb40a568" order="0" parent="None"> <item handle="73475cb40a568" order="0" parent="None">
<name>Novel</name> <name>Novel</name>
<type>ROOT</type> <type>ROOT</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="25fc0e7096fc6" order="0" parent="73475cb40a568"> <item handle="25fc0e7096fc6" order="0" parent="73475cb40a568">
<name>New Chapter</name> <name>New Chapter</name>
<type>FOLDER</type> <type>FOLDER</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="31489056e0916" order="0" parent="25fc0e7096fc6"> <item handle="31489056e0916" order="0" parent="25fc0e7096fc6">
<name>New Scene</name> <name>New Scene</name>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>0</charCount> <charCount>0</charCount>
@@ -42,21 +54,21 @@
<name>Characters</name> <name>Characters</name>
<type>ROOT</type> <type>ROOT</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="71ee45a3c0db9" order="2" parent="None"> <item handle="71ee45a3c0db9" order="2" parent="None">
<name>Plot</name> <name>Plot</name>
<type>ROOT</type> <type>ROOT</type>
<class>PLOT</class> <class>PLOT</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="811786ad1ae74" order="3" parent="None"> <item handle="811786ad1ae74" order="3" parent="None">
<name>World</name> <name>World</name>
<type>ROOT</type> <type>ROOT</type>
<class>WORLD</class> <class>WORLD</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
</content> </content>
+19 -7
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.2" fileVersion="1.0" timeStamp="2019-05-18 15:00:34"> <novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 21:16:34">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
@@ -8,27 +8,39 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<status>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry>
<entry blue="0" green="150" red="200">Draft</entry>
<entry blue="0" green="200" red="50">Finished</entry>
</status>
<importance>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Minor</entry>
<entry blue="0" green="150" red="200">Major</entry>
<entry blue="0" green="200" red="50">Main</entry>
</importance>
</settings> </settings>
<content count="6"> <content count="6">
<item handle="73475cb40a568" order="0" parent="None"> <item handle="73475cb40a568" order="0" parent="None">
<name>Novel</name> <name>Novel</name>
<type>ROOT</type> <type>ROOT</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="25fc0e7096fc6" order="0" parent="73475cb40a568"> <item handle="25fc0e7096fc6" order="0" parent="73475cb40a568">
<name>New Chapter</name> <name>New Chapter</name>
<type>FOLDER</type> <type>FOLDER</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="31489056e0916" order="0" parent="25fc0e7096fc6"> <item handle="31489056e0916" order="0" parent="25fc0e7096fc6">
<name>Just a Page</name> <name>Just a Page</name>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>1</status> <status>Note</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>PAGE</layout> <layout>PAGE</layout>
<charCount>0</charCount> <charCount>0</charCount>
@@ -40,21 +52,21 @@
<name>Characters</name> <name>Characters</name>
<type>ROOT</type> <type>ROOT</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="71ee45a3c0db9" order="2" parent="None"> <item handle="71ee45a3c0db9" order="2" parent="None">
<name>Plot</name> <name>Plot</name>
<type>ROOT</type> <type>ROOT</type>
<class>PLOT</class> <class>PLOT</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="811786ad1ae74" order="3" parent="None"> <item handle="811786ad1ae74" order="3" parent="None">
<name>World</name> <name>World</name>
<type>ROOT</type> <type>ROOT</type>
<class>WORLD</class> <class>WORLD</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
</content> </content>
+19 -7
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.2" fileVersion="1.0" timeStamp="2019-05-18 14:46:29"> <novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 20:48:51">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
@@ -8,48 +8,60 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<status>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry>
<entry blue="0" green="150" red="200">Draft</entry>
<entry blue="0" green="200" red="50">Finished</entry>
</status>
<importance>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Minor</entry>
<entry blue="0" green="150" red="200">Major</entry>
<entry blue="0" green="200" red="50">Main</entry>
</importance>
</settings> </settings>
<content count="6"> <content count="6">
<item handle="73475cb40a568" order="None" parent="None"> <item handle="73475cb40a568" order="None" parent="None">
<name>Novel</name> <name>Novel</name>
<type>ROOT</type> <type>ROOT</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="44cb730c42048" order="None" parent="None"> <item handle="44cb730c42048" order="None" parent="None">
<name>Characters</name> <name>Characters</name>
<type>ROOT</type> <type>ROOT</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="71ee45a3c0db9" order="None" parent="None"> <item handle="71ee45a3c0db9" order="None" parent="None">
<name>Plot</name> <name>Plot</name>
<type>ROOT</type> <type>ROOT</type>
<class>PLOT</class> <class>PLOT</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="811786ad1ae74" order="None" parent="None"> <item handle="811786ad1ae74" order="None" parent="None">
<name>World</name> <name>World</name>
<type>ROOT</type> <type>ROOT</type>
<class>WORLD</class> <class>WORLD</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="25fc0e7096fc6" order="None" parent="73475cb40a568"> <item handle="25fc0e7096fc6" order="None" parent="73475cb40a568">
<name>New Chapter</name> <name>New Chapter</name>
<type>FOLDER</type> <type>FOLDER</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="31489056e0916" order="None" parent="25fc0e7096fc6"> <item handle="31489056e0916" order="None" parent="25fc0e7096fc6">
<name>New Scene</name> <name>New Scene</name>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>0</charCount> <charCount>0</charCount>
+23 -11
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.0" fileVersion="1.0" timeStamp="2019-05-12 14:40:19"> <novelWriterXML appVersion="0.1.3" fileVersion="1.0" timeStamp="2019-05-22 20:52:32">
<project> <project>
<name></name> <name></name>
<title></title> <title></title>
@@ -8,48 +8,60 @@
<spellCheck>False</spellCheck> <spellCheck>False</spellCheck>
<lastEdited>None</lastEdited> <lastEdited>None</lastEdited>
<lastViewed>None</lastViewed> <lastViewed>None</lastViewed>
<status>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Note</entry>
<entry blue="0" green="150" red="200">Draft</entry>
<entry blue="0" green="200" red="50">Finished</entry>
</status>
<importance>
<entry blue="100" green="100" red="100">New</entry>
<entry blue="0" green="50" red="200">Minor</entry>
<entry blue="0" green="150" red="200">Major</entry>
<entry blue="0" green="200" red="50">Main</entry>
</importance>
</settings> </settings>
<content count="10"> <content count="10">
<item handle="73475cb40a568" order="None" parent="None"> <item handle="73475cb40a568" order="None" parent="None">
<name>Novel</name> <name>Novel</name>
<type>ROOT</type> <type>ROOT</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="44cb730c42048" order="None" parent="None"> <item handle="44cb730c42048" order="None" parent="None">
<name>Characters</name> <name>Characters</name>
<type>ROOT</type> <type>ROOT</type>
<class>CHARACTER</class> <class>CHARACTER</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="71ee45a3c0db9" order="None" parent="None"> <item handle="71ee45a3c0db9" order="None" parent="None">
<name>Plot</name> <name>Plot</name>
<type>ROOT</type> <type>ROOT</type>
<class>PLOT</class> <class>PLOT</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="811786ad1ae74" order="None" parent="None"> <item handle="811786ad1ae74" order="None" parent="None">
<name>World</name> <name>World</name>
<type>ROOT</type> <type>ROOT</type>
<class>WORLD</class> <class>WORLD</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="25fc0e7096fc6" order="None" parent="73475cb40a568"> <item handle="25fc0e7096fc6" order="None" parent="73475cb40a568">
<name>New Chapter</name> <name>New Chapter</name>
<type>FOLDER</type> <type>FOLDER</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="31489056e0916" order="None" parent="25fc0e7096fc6"> <item handle="31489056e0916" order="None" parent="25fc0e7096fc6">
<name>New Scene</name> <name>New Scene</name>
<type>FILE</type> <type>FILE</type>
<class>NOVEL</class> <class>NOVEL</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>0</charCount> <charCount>0</charCount>
@@ -61,28 +73,28 @@
<name>Timeline</name> <name>Timeline</name>
<type>ROOT</type> <type>ROOT</type>
<class>TIMELINE</class> <class>TIMELINE</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="d029fa3a95e17" order="None" parent="None"> <item handle="d029fa3a95e17" order="None" parent="None">
<name>Object</name> <name>Object</name>
<type>ROOT</type> <type>ROOT</type>
<class>OBJECT</class> <class>OBJECT</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="81b8a03f97e87" order="None" parent="None"> <item handle="81b8a03f97e87" order="None" parent="None">
<name>Custom1</name> <name>Custom1</name>
<type>ROOT</type> <type>ROOT</type>
<class>CUSTOM</class> <class>CUSTOM</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
<item handle="da4ea2a5506f2" order="None" parent="None"> <item handle="da4ea2a5506f2" order="None" parent="None">
<name>Custom2</name> <name>Custom2</name>
<type>ROOT</type> <type>ROOT</type>
<class>CUSTOM</class> <class>CUSTOM</class>
<status>0</status> <status>New</status>
<expanded>False</expanded> <expanded>False</expanded>
</item> </item>
</content> </content>
+29 -12
View File
@@ -99,15 +99,19 @@ def testMainWindows(qtbot, nwTempGUI, nwRef):
qtbot.wait(stepDelay) qtbot.wait(stepDelay)
nwGUI.docEditor.wCounter.run() nwGUI.docEditor.wCounter.run()
qtbot.wait(stepDelay) qtbot.wait(stepDelay)
nwGUI.docEditor._updateCounts()
# Save the document # Save the document
assert nwGUI.docEditor.docChanged assert nwGUI.docEditor.docChanged
assert nwGUI.saveDocument() assert nwGUI.saveDocument()
assert not nwGUI.docEditor.docChanged
qtbot.wait(stepDelay) qtbot.wait(stepDelay)
# Open and view the edited document # Open and view the edited document
assert nwGUI.openDocument("31489056e0916") assert nwGUI.openDocument("31489056e0916")
assert nwGUI.viewDocument("31489056e0916") assert nwGUI.viewDocument("31489056e0916")
qtbot.wait(stepDelay)
assert nwGUI.saveProject()
# Check the files # Check the files
projFile = path.join(nwTempGUI,"nwProject.nwx") projFile = path.join(nwTempGUI,"nwProject.nwx")
@@ -135,27 +139,40 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef):
qtbot.addWidget(projEdit) qtbot.addWidget(projEdit)
for c in "Project Name": for c in "Project Name":
qtbot.keyClick(projEdit.editName, c, delay=keyDelay) qtbot.keyClick(projEdit.tabMain.editName, c, delay=keyDelay)
for c in "Project Title": for c in "Project Title":
qtbot.keyClick(projEdit.editTitle, c, delay=keyDelay) qtbot.keyClick(projEdit.tabMain.editTitle, c, delay=keyDelay)
for c in "Jane Doe": for c in "Jane Doe":
qtbot.keyClick(projEdit.editAuthors, c, delay=keyDelay) qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=keyDelay)
qtbot.keyClick(projEdit.editAuthors, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(projEdit.tabMain.editAuthors, Qt.Key_Return, delay=keyDelay)
for c in "John Doh": for c in "John Doh":
qtbot.keyClick(projEdit.editAuthors, c, delay=keyDelay) qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=keyDelay)
qtbot.mouseClick(projEdit.saveButton, Qt.LeftButton) #Test Status Tab
projEdit.tabWidget.setCurrentWidget(projEdit.tabStatus)
projEdit.tabStatus.listBox.item(2).setSelected(True)
qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton)
qtbot.mouseClick(projEdit.tabStatus.newButton, Qt.LeftButton)
projEdit.tabStatus.listBox.item(3).setSelected(True)
for n in range(8):
qtbot.keyClick(projEdit.tabStatus.editName, Qt.Key_Backspace, delay=keyDelay)
for c in "Final":
qtbot.keyClick(projEdit.tabStatus.editName, c, delay=keyDelay)
qtbot.mouseClick(projEdit.tabStatus.saveButton, Qt.LeftButton)
projEdit._doSave()
# Open again, and check project settings
projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject) projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject)
qtbot.addWidget(projEdit) qtbot.addWidget(projEdit)
assert projEdit.editName.text() == "Project Name" assert projEdit.tabMain.editName.text() == "Project Name"
assert projEdit.editTitle.text() == "Project Title" assert projEdit.tabMain.editTitle.text() == "Project Title"
theAuth = projEdit.editAuthors.toPlainText().strip().splitlines() theAuth = projEdit.tabMain.editAuthors.toPlainText().strip().splitlines()
assert len(theAuth) == 2 assert len(theAuth) == 2
assert theAuth[0] == "Jane Doe" assert theAuth[0] == "Jane Doe"
assert theAuth[1] == "John Doh" assert theAuth[1] == "John Doh"
qtbot.mouseClick(projEdit.closeButton, Qt.LeftButton) projEdit._doClose()
qtbot.wait(stepDelay) qtbot.wait(stepDelay)
assert nwGUI.saveProject() assert nwGUI.saveProject()
@@ -185,7 +202,7 @@ def testItemEditor(qtbot, nwTempGUI, nwRef):
qtbot.addWidget(itemEdit) qtbot.addWidget(itemEdit)
assert itemEdit.editName.text() == "New Scene" assert itemEdit.editName.text() == "New Scene"
assert itemEdit.editStatus.currentData() == 0 assert itemEdit.editStatus.currentData() == "New"
assert itemEdit.editLayout.currentData() == nwItemLayout.SCENE assert itemEdit.editLayout.currentData() == nwItemLayout.SCENE
for c in "Just a Page": for c in "Just a Page":
@@ -199,7 +216,7 @@ def testItemEditor(qtbot, nwTempGUI, nwRef):
itemEdit = GuiItemEditor(nwGUI, nwGUI.theProject, "31489056e0916") itemEdit = GuiItemEditor(nwGUI, nwGUI.theProject, "31489056e0916")
qtbot.addWidget(itemEdit) qtbot.addWidget(itemEdit)
assert itemEdit.editName.text() == "Just a Page" assert itemEdit.editName.text() == "Just a Page"
assert itemEdit.editStatus.currentData() == 1 assert itemEdit.editStatus.currentData() == "Note"
assert itemEdit.editLayout.currentData() == nwItemLayout.PAGE assert itemEdit.editLayout.currentData() == nwItemLayout.PAGE
qtbot.mouseClick(itemEdit.closeButton, Qt.LeftButton) qtbot.mouseClick(itemEdit.closeButton, Qt.LeftButton)