@@ -47,6 +47,7 @@ class Config:
|
||||
self.confPath = None
|
||||
self.confFile = None
|
||||
self.homePath = None
|
||||
self.lastPath = None
|
||||
self.appPath = None
|
||||
self.appRoot = None
|
||||
self.appIcon = None
|
||||
@@ -129,6 +130,7 @@ class Config:
|
||||
|
||||
self.confFile = self.appHandle+".conf"
|
||||
self.homePath = path.expanduser("~")
|
||||
self.lastPath = self.homePath
|
||||
self.appPath = path.dirname(__file__)
|
||||
self.appRoot = path.join(self.appPath,path.pardir)
|
||||
self.helpPath = path.join(self.appRoot,"help","en_GB")
|
||||
@@ -212,6 +214,7 @@ class Config:
|
||||
|
||||
## Path
|
||||
cnfSec = "Path"
|
||||
self.lastPath = self._parseLine(cnfParse, cnfSec, "lastpath", self.CNF_STR, self.lastPath)
|
||||
for i in range(10):
|
||||
self.recentList[i] = self._parseLine(cnfParse, cnfSec, "recent%d" % i,self.CNF_STR, self.recentList[i])
|
||||
|
||||
@@ -278,6 +281,7 @@ class Config:
|
||||
## Path
|
||||
cnfSec = "Path"
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec,"lastpath", str(self.lastPath))
|
||||
for i in range(10):
|
||||
cnfParse.set(cnfSec,"recent%d" % i, str(self.recentList[i]))
|
||||
|
||||
@@ -312,6 +316,13 @@ class Config:
|
||||
self.confFile = path.basename(newPath)
|
||||
return True
|
||||
|
||||
def setLastPath(self, lastPath):
|
||||
if lastPath is None or lastPath == "":
|
||||
self.lastPath = ""
|
||||
else:
|
||||
self.lastPath = path.dirname(lastPath)
|
||||
return True
|
||||
|
||||
def setWinSize(self, newWidth, newHeight):
|
||||
if abs(self.winGeometry[0] - newWidth) > 5:
|
||||
self.winGeometry[0] = newWidth
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ class nwLabels():
|
||||
nwItemLayout.BOOK : "Book",
|
||||
nwItemLayout.PAGE : "Plain Page",
|
||||
nwItemLayout.PARTITION : "Partition",
|
||||
nwItemLayout.UNNUMBERED : "Un-Numbered",
|
||||
nwItemLayout.UNNUMBERED : "Unnumbered",
|
||||
nwItemLayout.CHAPTER : "Chapter",
|
||||
nwItemLayout.SCENE : "Scene",
|
||||
nwItemLayout.NOTE : "Note",
|
||||
|
||||
@@ -289,6 +289,9 @@ class GuiDocEditor(QTextEdit):
|
||||
return False
|
||||
return True
|
||||
|
||||
def isEmpty(self):
|
||||
return self.qDocument.isEmpty()
|
||||
|
||||
##
|
||||
# Document Events and Maintenance
|
||||
##
|
||||
|
||||
+13
-4
@@ -98,8 +98,16 @@ class GuiDocTree(QTreeWidget):
|
||||
|
||||
if itemClass is None and pHandle is not None:
|
||||
itemClass = self.theProject.getItem(pHandle).itemClass
|
||||
|
||||
if itemClass is None:
|
||||
self.makeAlert("Failed to find an appropriate item class for item %s" % pHandle, nwAlert.BUG)
|
||||
if itemType is not None:
|
||||
if itemType == nwItemType.FILE:
|
||||
self.makeAlert("Please select a location in the tree to add a document.", nwAlert.ERROR)
|
||||
return False
|
||||
elif itemType == nwItemType.FOLDER:
|
||||
self.makeAlert("Please select a location in the tree to add a folder.", nwAlert.ERROR)
|
||||
return False
|
||||
self.makeAlert("Failed to add new item.", nwAlert.BUG)
|
||||
return False
|
||||
|
||||
logger.verbose("Adding new item of type %s and class %s to handle %s" % (
|
||||
@@ -418,9 +426,10 @@ class GuiDocTree(QTreeWidget):
|
||||
return
|
||||
|
||||
def _cleanOrphanedRoot(self):
|
||||
if self.orphRoot.childCount() == 0:
|
||||
self.takeTopLevelItem(self.indexOfTopLevelItem(self.orphRoot))
|
||||
self.orphRoot = None
|
||||
if self.orphRoot is not None:
|
||||
if self.orphRoot.childCount() == 0:
|
||||
self.takeTopLevelItem(self.indexOfTopLevelItem(self.orphRoot))
|
||||
self.orphRoot = None
|
||||
return
|
||||
|
||||
def _updateItemParent(self, tHandle):
|
||||
|
||||
@@ -87,7 +87,7 @@ class GuiItemEditor(QDialog):
|
||||
if itemLayout in self.validLayouts:
|
||||
self.editLayout.addItem(nwLabels.LAYOUT_NAME[itemLayout],itemLayout)
|
||||
|
||||
self.mainForm.addRow("Name", self.editName)
|
||||
self.mainForm.addRow("Label", self.editName)
|
||||
self.mainForm.addRow("Status", self.editStatus)
|
||||
self.mainForm.addRow("Layout", self.editLayout)
|
||||
|
||||
|
||||
+9
-2
@@ -312,8 +312,15 @@ class GuiMainMenu(QMenuBar):
|
||||
menuItem.triggered.connect(self.theParent.closeDocViewer)
|
||||
self.docuMenu.addAction(menuItem)
|
||||
|
||||
# # Document > Separator
|
||||
# self.docuMenu.addSeparator()
|
||||
# Document > Separator
|
||||
self.docuMenu.addSeparator()
|
||||
|
||||
# Document > Close Preview
|
||||
menuItem = QAction("Import from File", self)
|
||||
menuItem.setStatusTip("Import document from a text or markdown file")
|
||||
menuItem.setShortcut("Ctrl+Shift+I")
|
||||
menuItem.triggered.connect(self.theParent.importDocument)
|
||||
self.docuMenu.addAction(menuItem)
|
||||
|
||||
# # Document > Split
|
||||
# menuItem = QAction("Split Document", self)
|
||||
|
||||
@@ -366,6 +366,54 @@ class GuiMain(QMainWindow):
|
||||
|
||||
return True
|
||||
|
||||
def importDocument(self):
|
||||
|
||||
lastPath = self.mainConf.lastPath
|
||||
|
||||
extFilter = [
|
||||
"Text files (*.txt)",
|
||||
"Markdown files (*.md)",
|
||||
"All files (*.*)",
|
||||
]
|
||||
dlgOpt = QFileDialog.Options()
|
||||
dlgOpt |= QFileDialog.DontUseNativeDialog
|
||||
inPath = QFileDialog.getOpenFileName(
|
||||
self,"Import File",lastPath,options=dlgOpt,filter=";;".join(extFilter)
|
||||
)
|
||||
if inPath:
|
||||
loadFile = inPath[0]
|
||||
self.mainConf.setLastPath(loadFile)
|
||||
else:
|
||||
return False
|
||||
|
||||
theText = None
|
||||
try:
|
||||
with open(loadFile,mode="rt") as inFile:
|
||||
theText = inFile.read()
|
||||
except Exception as e:
|
||||
self.makeAlert(["Could not read file. The file cannot be a binary file.",str(e)], nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
if self.docEditor.theHandle is None:
|
||||
self.makeAlert(["Please open a document to import the text file into."], nwAlert.ERROR)
|
||||
return False
|
||||
|
||||
if not self.docEditor.isEmpty():
|
||||
if self.mainConf.showGUI:
|
||||
msgBox = QMessageBox()
|
||||
msgRes = msgBox.question(
|
||||
self, "Import Document",
|
||||
"Importing the file will overwrite the current content of the document. Do you want to proceed?"
|
||||
)
|
||||
if msgRes != QMessageBox.Yes:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
self.docEditor.setText(theText)
|
||||
|
||||
return True
|
||||
|
||||
##
|
||||
# Tree Item Actions
|
||||
##
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
## Interlude
|
||||
|
||||
I am the very model of a modern Major-General
|
||||
I've information vegetable, animal, and mineral
|
||||
I know the kings of England, and I quote the fights historical
|
||||
From Marathon to Waterloo, in order categorical
|
||||
|
||||
I'm very well acquainted, too, with matters mathematical
|
||||
I understand equations, both the simple and quadratical
|
||||
About binomial theorem I'm teeming with a lot o’ news
|
||||
With many cheerful facts about the square of the hypotenuse
|
||||
|
||||
With many cheerful facts about the square of the hypotenuse
|
||||
With many cheerful facts about the square of the hypotenuse
|
||||
With many cheerful facts about the square of the hypotepotenuse
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="0.3.1" fileVersion="1.0" timeStamp="2019-10-21 20:54:53">
|
||||
<novelWriterXML appVersion="0.3.1" fileVersion="1.0" timeStamp="2019-10-23 21:21:02">
|
||||
<project>
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
@@ -9,9 +9,9 @@
|
||||
</project>
|
||||
<settings>
|
||||
<spellCheck>True</spellCheck>
|
||||
<lastEdited>636b6aa9b697b</lastEdited>
|
||||
<lastEdited>ba8a28a246524</lastEdited>
|
||||
<lastViewed>636b6aa9b697b</lastViewed>
|
||||
<lastWordCount>758</lastWordCount>
|
||||
<lastWordCount>859</lastWordCount>
|
||||
<autoReplace>
|
||||
<A>B</A>
|
||||
<B>E</B>
|
||||
@@ -33,7 +33,7 @@
|
||||
<entry blue="175" green="0" red="117">Main</entry>
|
||||
</importance>
|
||||
</settings>
|
||||
<content count="18">
|
||||
<content count="19">
|
||||
<item handle="7031beac91f75" order="0" parent="None">
|
||||
<name>Novel</name>
|
||||
<type>ROOT</type>
|
||||
@@ -96,7 +96,19 @@
|
||||
<paraCount>2</paraCount>
|
||||
<cursorPos>448</cursorPos>
|
||||
</item>
|
||||
<item handle="96b68994dfa3d" order="3" parent="e7ded148d6e4a">
|
||||
<item handle="ba8a28a246524" order="3" parent="e7ded148d6e4a">
|
||||
<name>Interlude</name>
|
||||
<type>FILE</type>
|
||||
<class>NOVEL</class>
|
||||
<status>Finished</status>
|
||||
<expanded>False</expanded>
|
||||
<layout>UNNUMBERED</layout>
|
||||
<charCount>614</charCount>
|
||||
<wordCount>101</wordCount>
|
||||
<paraCount>3</paraCount>
|
||||
<cursorPos>633</cursorPos>
|
||||
</item>
|
||||
<item handle="96b68994dfa3d" order="4" parent="e7ded148d6e4a">
|
||||
<name>A Note on Ipsums</name>
|
||||
<type>FILE</type>
|
||||
<class>NOVEL</class>
|
||||
@@ -108,7 +120,7 @@
|
||||
<paraCount>5</paraCount>
|
||||
<cursorPos>0</cursorPos>
|
||||
</item>
|
||||
<item handle="88706ddc78b1b" order="4" parent="e7ded148d6e4a">
|
||||
<item handle="88706ddc78b1b" order="5" parent="e7ded148d6e4a">
|
||||
<name>Chapter Two</name>
|
||||
<type>FILE</type>
|
||||
<class>NOVEL</class>
|
||||
@@ -120,7 +132,7 @@
|
||||
<paraCount>0</paraCount>
|
||||
<cursorPos>76</cursorPos>
|
||||
</item>
|
||||
<item handle="ae7339df26ded" order="5" parent="e7ded148d6e4a">
|
||||
<item handle="ae7339df26ded" order="6" parent="e7ded148d6e4a">
|
||||
<name>We Found John!</name>
|
||||
<type>FILE</type>
|
||||
<class>NOVEL</class>
|
||||
|
||||
@@ -37,6 +37,7 @@ backuponclose = False
|
||||
askbeforebackup = True
|
||||
|
||||
[Path]
|
||||
lastpath =
|
||||
recent0 =
|
||||
recent1 =
|
||||
recent2 =
|
||||
|
||||
@@ -14,6 +14,8 @@ def testConfigInit(nwTemp,nwRef):
|
||||
tmpConf = path.join(nwTemp,"novelwriter.conf")
|
||||
refConf = path.join(nwRef, "novelwriter.conf")
|
||||
assert theConf.initConfig(nwTemp)
|
||||
assert theConf.setLastPath("")
|
||||
assert theConf.saveConfig()
|
||||
assert cmpFiles(tmpConf, refConf, [2])
|
||||
assert not theConf.confChanged
|
||||
|
||||
|
||||
Reference in New Issue
Block a user