Merge pull request #106 from vkbo/trash_folder

Trash folder fixes and Notice Bar
This commit is contained in:
Veronica K. Berglyd Olsen
2019-10-31 14:54:28 +01:00
committed by GitHub
20 changed files with 201 additions and 79 deletions
@@ -13,18 +13,20 @@
import logging
import nw
from time import time
from time import time
from PyQt5.QtCore import Qt, QTimer, QSizeF
from PyQt5.QtWidgets import qApp, QTextEdit, QAction, QMenu, QShortcut
from PyQt5.QtGui import QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, QPalette, QTextDocument
from PyQt5.QtCore import Qt, QTimer, QSizeF
from PyQt5.QtWidgets import qApp, QTextEdit, QAction, QMenu, QShortcut
from PyQt5.QtGui import (
QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, QPalette, QTextDocument
)
from nw.project.document import NWDoc
from nw.gui.dochighlight import GuiDocHighlighter
from nw.gui.wordcounter import WordCounter
from nw.tools.spellcheck import NWSpellCheck
from nw.constants import nwFiles, nwUnicode
from nw.enum import nwDocAction, nwAlert
from nw.project.document import NWDoc
from nw.gui.tools.dochighlight import GuiDocHighlighter
from nw.gui.tools.wordcounter import WordCounter
from nw.tools.spellcheck import NWSpellCheck
from nw.constants import nwFiles, nwUnicode
from nw.enum import nwDocAction, nwAlert
logger = logging.getLogger(__name__)
@@ -114,6 +116,7 @@ class GuiDocEditor(QTextEdit):
self.hasSelection = False
self.setDocumentChanged(False)
self.theParent.noticeBar.hideNote()
return True
@@ -161,12 +164,16 @@ class GuiDocEditor(QTextEdit):
# Initialise the syntax highlighter
self.hLight.initHighlighter()
# If we have a document open, we should reload it in case the font changed
# If we have a document open, we should reload it in case the font changed, otherwise
# we just clear the editor entirely, which makes it read only.
if self.theHandle is not None:
# We must save the current handle as clearEditor() sets it to None
tHandle = self.theHandle
self.clearEditor()
self.loadText(tHandle)
self.changeWidth()
else:
self.clearEditor()
return True
@@ -191,9 +198,13 @@ class GuiDocEditor(QTextEdit):
self._runCounter()
self.wcTimer.start()
self.setDocumentChanged(False)
self.setReadOnly(False)
self.theHandle = tHandle
if self.nwDocument.docEditable:
self.setReadOnly(False)
else:
self.theParent.noticeBar.showNote("This document is read only.")
return True
def saveText(self):
@@ -236,9 +247,10 @@ class GuiDocEditor(QTextEdit):
return theText
def setCursorPosition(self, thePosition):
theCursor = self.textCursor()
theCursor.setPosition(thePosition)
self.setTextCursor(theCursor)
if thePosition > 0:
theCursor = self.textCursor()
theCursor.setPosition(thePosition)
self.setTextCursor(theCursor)
return True
def getCursorPosition(self):
@@ -41,8 +41,8 @@ class GuiDocTree(QTreeWidget):
self.theProject = theProject
# Tree Settings
self.theMap = None
self.orphRoot = None
self.theMap = None
self.orphRoot = None
self.clearTree()
@@ -97,15 +97,23 @@ class GuiDocTree(QTreeWidget):
return False
if itemClass is None and pHandle is not None:
itemClass = self.theProject.getItem(pHandle).itemClass
pItem = self.theProject.getItem(pHandle)
if pItem is not None:
itemClass = pItem.itemClass
if itemClass is None:
if itemType is not None:
if itemType == nwItemType.FILE:
self.makeAlert("Please select a location in the tree to add a document.", nwAlert.ERROR)
self.makeAlert(
"Please select a valid 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)
self.makeAlert(
"Please select a valid location in the tree to add a folder.",
nwAlert.ERROR
)
return False
self.makeAlert("Failed to add new item.", nwAlert.BUG)
return False
@@ -134,10 +142,14 @@ class GuiDocTree(QTreeWidget):
# If we again has no home, give up
if pHandle is None:
logger.error("Did not find anywhere to add the item!")
self.makeAlert("Did not find anywhere to add the file or folder!", nwAlert.ERROR)
return False
# If we're still here, add the file
if pHandle == self.theProject.trashRoot:
self.makeAlert("Cannot add new files or folders to the trash folder.", nwAlert.ERROR)
return False
# If we're still here, add the file or folder
if itemType == nwItemType.FILE:
tHandle = self.theProject.newFile("New File", itemClass, pHandle)
elif itemType == nwItemType.FOLDER:
+65
View File
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
"""novelWriter GUI Main Window Notice Bar
novelWriter GUI Main Window Notice Bar
==========================================
Class holding the main window notice bar for the doc editor
File History:
Created: 2019-10-31 [0.3.2]
"""
import logging
import nw
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette, QColor
from PyQt5.QtWidgets import QFrame, QHBoxLayout, QLabel, QPushButton
logger = logging.getLogger(__name__)
class GuiNoticeBar(QFrame):
def __init__(self, theParent):
QFrame.__init__(self, theParent)
logger.debug("Initialising NoticeBar ...")
self.mainConf = nw.CONFIG
self.theParent = theParent
self.theTheme = theParent.theTheme
self.setContentsMargins(0,0,0,0)
self.setFrameShape(QFrame.Box)
self.mainBox = QHBoxLayout(self)
self.mainBox.setContentsMargins(8,2,2,2)
self.noteLabel = QLabel("Hi there!")
self.closeButton = QPushButton(self.theTheme.getIcon("close"),"")
self.closeButton.clicked.connect(self.hideNote)
self.mainBox.addWidget(self.noteLabel)
self.mainBox.addWidget(self.closeButton)
self.mainBox.setStretch(0, 1)
self.setLayout(self.mainBox)
self.hideNote()
logger.debug("NoticeBar initialisation complete")
return
def showNote(self, theNote):
self.noteLabel.setText("<b>Note:</b> %s" % theNote)
self.setVisible(True)
return
def hideNote(self):
self.noteLabel.setText("")
self.setVisible(False)
return
# END Class GuiNoticeBar
@@ -26,7 +26,7 @@ class GuiSearchBar(QFrame):
def __init__(self, theParent):
QFrame.__init__(self, theParent)
logger.debug("Initialising GuiSearchBar ...")
logger.debug("Initialising SearchBar ...")
self.mainConf = nw.CONFIG
self.theParent = theParent
@@ -73,7 +73,7 @@ class GuiSearchBar(QFrame):
self._replaceVisible(False)
logger.debug("GuiSearchBar initialisation complete")
logger.debug("SearchBar initialisation complete")
return
+32 -26
View File
@@ -14,36 +14,38 @@ import logging
import time
import nw
from os import path
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QIcon, QPixmap, QColor
from PyQt5.QtWidgets import (
from os import path
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QIcon, QPixmap, QColor
from PyQt5.QtWidgets import (
qApp, QWidget, QMainWindow, QVBoxLayout, QFrame, QSplitter, QFileDialog,
QShortcut, QMessageBox, QProgressDialog, QDialog
)
from nw.gui.doctree import GuiDocTree
from nw.gui.doceditor import GuiDocEditor
from nw.gui.docviewer import GuiDocViewer
from nw.gui.docdetails import GuiDocDetails
from nw.gui.searchbar import GuiSearchBar
from nw.gui.mainmenu import GuiMainMenu
from nw.gui.configeditor import GuiConfigEditor
from nw.gui.projecteditor import GuiProjectEditor
from nw.gui.export import GuiExport
from nw.gui.itemeditor import GuiItemEditor
from nw.gui.statusbar import GuiMainStatus
from nw.gui.timelineview import GuiTimeLineView
from nw.gui.sessionlog import GuiSessionLogView
from nw.project.project import NWProject
from nw.project.document import NWDoc
from nw.project.item import NWItem
from nw.project.index import NWIndex
from nw.project.backup import NWBackup
from nw.tools.wordcount import countWords
from nw.theme import Theme
from nw.enum import nwItemType, nwAlert
from nw.constants import nwFiles
from nw.gui.mainmenu import GuiMainMenu
from nw.gui.statusbar import GuiMainStatus
from nw.gui.elements.doctree import GuiDocTree
from nw.gui.elements.doceditor import GuiDocEditor
from nw.gui.elements.docviewer import GuiDocViewer
from nw.gui.elements.docdetails import GuiDocDetails
from nw.gui.elements.searchbar import GuiSearchBar
from nw.gui.elements.noticebar import GuiNoticeBar
from nw.gui.dialogs.configeditor import GuiConfigEditor
from nw.gui.dialogs.projecteditor import GuiProjectEditor
from nw.gui.dialogs.export import GuiExport
from nw.gui.dialogs.itemeditor import GuiItemEditor
from nw.gui.dialogs.timelineview import GuiTimeLineView
from nw.gui.dialogs.sessionlog import GuiSessionLogView
from nw.project.project import NWProject
from nw.project.document import NWDoc
from nw.project.item import NWItem
from nw.project.index import NWIndex
from nw.project.backup import NWBackup
from nw.tools.wordcount import countWords
from nw.theme import Theme
from nw.enum import nwItemType, nwAlert
from nw.constants import nwFiles
logger = logging.getLogger(__name__)
@@ -71,6 +73,7 @@ class GuiMain(QMainWindow):
# Main GUI Elements
self.statusBar = GuiMainStatus(self)
self.noticeBar = GuiNoticeBar(self)
self.docEditor = GuiDocEditor(self, self.theProject)
self.docViewer = GuiDocViewer(self, self.theProject)
self.docDetails = GuiDocDetails(self, self.theProject)
@@ -85,6 +88,7 @@ class GuiMain(QMainWindow):
# Assemble Main Window
self.treePane = QFrame()
self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0,0,0,0)
self.treeBox.addWidget(self.treeView)
self.treeBox.addWidget(self.docDetails)
self.treePane.setLayout(self.treeBox)
@@ -93,6 +97,7 @@ class GuiMain(QMainWindow):
self.docView = QVBoxLayout()
self.docView.setContentsMargins(0,0,0,0)
self.docView.addWidget(self.searchBar)
self.docView.addWidget(self.noticeBar)
self.docView.addWidget(self.docEditor)
self.docPane.setLayout(self.docView)
@@ -102,6 +107,7 @@ class GuiMain(QMainWindow):
self.splitView.splitterMoved.connect(self._splitViewMove)
self.splitMain = QSplitter(Qt.Horizontal)
self.splitMain.setContentsMargins(4,4,4,4)
self.splitMain.addWidget(self.treePane)
self.splitMain.addWidget(self.splitView)
self.splitMain.setSizes(self.mainConf.mainPanePos)
+19 -8
View File
@@ -25,11 +25,12 @@ class NWDoc():
def __init__(self, theProject, theParent):
self.mainConf = nw.CONFIG
self.theProject = theProject
self.theParent = theParent
self.theItem = None
self.docHandle = None
self.mainConf = nw.CONFIG
self.theProject = theProject
self.theParent = theParent
self.theItem = None
self.docHandle = None
self.docEditable = False
# Internal Mapping
self.makeAlert = self.theParent.makeAlert
@@ -37,8 +38,9 @@ class NWDoc():
return
def clearDocument(self):
self.theItem = None
self.docHandle = None
self.theItem = None
self.docHandle = None
self.docEditable = False
return
def openDocument(self, tHandle, showStatus=True):
@@ -46,6 +48,15 @@ class NWDoc():
self.docHandle = tHandle
self.theItem = self.theProject.getItem(tHandle)
if self.theItem is None:
self.clearDocument()
return None
# By default, the document is editable. Except for files in the trash folder.
self.docEditable = True
if self.theItem.parHandle == self.theProject.trashRoot:
self.docEditable = False
docDir, docFile = self._assemblePath(self.FILE_MN)
logger.debug("Opening document %s" % path.join(docDir,docFile))
dataDir = path.join(self.theProject.projPath, docDir)
@@ -75,7 +86,7 @@ class NWDoc():
def saveDocument(self, docText):
if self.docHandle is None:
if self.docHandle is None or not self.docEditable:
return False
docDir, docFile = self._assemblePath(self.FILE_MN)
+13
View File
@@ -478,6 +478,19 @@ class NWProject():
logger.error("No tree item with handle %s" % str(tHandle))
return None
def getRootItem(self, tHandle):
"""Iterate upwards in the tree until we find the item with parent None, the root item.
We do this with a for loop with a maximum depth of 200 to make infinite loops impossible.
"""
tItem = self.getItem(tHandle)
if tItem is not None:
for i in range(200):
tHandle = tItem.parHandle
tItem = self.getItem(tHandle)
if tItem is None:
return tHandle
return None
def getProjectItems(self):
"""This function is called from the tree view when building the tree. Each item in the
project is returned in the order saved in the project file, but first it checks that it has
@@ -1 +1,3 @@
# Very Deep File
# Very Deep File
This file is still editable.
+16 -16
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.3.2" fileVersion="1.0" timeStamp="2019-10-31 11:33:41">
<novelWriterXML appVersion="0.3.2" fileVersion="1.0" timeStamp="2019-10-31 13:54:16">
<project>
<name>Sample Project</name>
<title>Sample Project</title>
@@ -11,7 +11,7 @@
<spellCheck>True</spellCheck>
<lastEdited>b8136a5a774a0</lastEdited>
<lastViewed>ba8a28a246524</lastViewed>
<lastWordCount>879</lastWordCount>
<lastWordCount>884</lastWordCount>
<autoReplace>
<A>B</A>
<B>E</B>
@@ -142,7 +142,7 @@
<charCount>567</charCount>
<wordCount>112</wordCount>
<paraCount>6</paraCount>
<cursorPos>634</cursorPos>
<cursorPos>326</cursorPos>
</item>
<item handle="f6622b4617424" order="1" parent="None">
<name>Characters</name>
@@ -220,19 +220,7 @@
<status>None</status>
<expanded>True</expanded>
</item>
<item handle="4cd0bd12b087d" order="0" parent="98acd8c76c93a">
<name>Orphaned File 2</name>
<type>FILE</type>
<class>NO_CLASS</class>
<status>None</status>
<expanded>False</expanded>
<layout>NO_LAYOUT</layout>
<charCount>14</charCount>
<wordCount>3</wordCount>
<paraCount>0</paraCount>
<cursorPos>1</cursorPos>
</item>
<item handle="b8136a5a774a0" order="1" parent="98acd8c76c93a">
<item handle="b8136a5a774a0" order="0" parent="98acd8c76c93a">
<name>Delete Me!</name>
<type>FILE</type>
<class>NOVEL</class>
@@ -244,5 +232,17 @@
<paraCount>1</paraCount>
<cursorPos>36</cursorPos>
</item>
<item handle="4cd0bd12b087d" order="1" parent="98acd8c76c93a">
<name>Orphaned File 1</name>
<type>FILE</type>
<class>NO_CLASS</class>
<status>None</status>
<expanded>False</expanded>
<layout>NO_LAYOUT</layout>
<charCount>42</charCount>
<wordCount>8</wordCount>
<paraCount>1</paraCount>
<cursorPos>47</cursorPos>
</item>
</content>
</novelWriterXML>
+5 -4
View File
@@ -8,10 +8,11 @@ from nwtools import *
from os import path, unlink
from PyQt5.QtCore import Qt
from nw.gui.projecteditor import GuiProjectEditor
from nw.gui.timelineview import GuiTimeLineView
from nw.gui.itemeditor import GuiItemEditor
from nw.enum import *
from nw.gui.dialogs.projecteditor import GuiProjectEditor
from nw.gui.dialogs.timelineview import GuiTimeLineView
from nw.gui.dialogs.itemeditor import GuiItemEditor
from nw.enum import *
keyDelay = 10
stepDelay = 50