Improve the way the project tree is managed and elements deleted.
This commit is contained in:
@@ -82,6 +82,18 @@ def checkBool(checkValue, defaultValue, allowNone=False):
|
|||||||
return defaultValue
|
return defaultValue
|
||||||
return defaultValue
|
return defaultValue
|
||||||
|
|
||||||
|
def checkHandle(checkValue, defaultValue, allowNone=False):
|
||||||
|
"""Check if a value is a handle.
|
||||||
|
"""
|
||||||
|
if allowNone:
|
||||||
|
if checkValue is None:
|
||||||
|
return None
|
||||||
|
if checkValue == "None":
|
||||||
|
return None
|
||||||
|
if isHandle(checkValue):
|
||||||
|
return str(checkValue)
|
||||||
|
return defaultValue
|
||||||
|
|
||||||
def isHandle(theString):
|
def isHandle(theString):
|
||||||
"""Check if a string is a valid novelWriter handle.
|
"""Check if a string is a valid novelWriter handle.
|
||||||
Note: This is case sensitive. Must be lower case!
|
Note: This is case sensitive. Must be lower case!
|
||||||
|
|||||||
+20
-21
@@ -34,7 +34,7 @@ from hashlib import sha256
|
|||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from nw.core.item import NWItem
|
from nw.core.item import NWItem
|
||||||
from nw.common import checkString
|
from nw.common import checkHandle
|
||||||
from nw.constants import nwFiles, nwItemType, nwItemClass, nwItemLayout, nwConst
|
from nw.constants import nwFiles, nwItemType, nwItemClass, nwItemLayout, nwConst
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -49,7 +49,6 @@ class NWTree():
|
|||||||
self._treeOrder = [] # The order of the tree items on the tree view
|
self._treeOrder = [] # The order of the tree items on the tree view
|
||||||
self._treeRoots = [] # The root items of the tree
|
self._treeRoots = [] # The root items of the tree
|
||||||
self._trashRoot = None # The handle of the trash root folder
|
self._trashRoot = None # The handle of the trash root folder
|
||||||
self._theLength = 0 # Always the length of _treeOrder
|
|
||||||
self._theIndex = 0 # The current iterator index
|
self._theIndex = 0 # The current iterator index
|
||||||
self._treeChanged = False # True if tree structure has changed
|
self._treeChanged = False # True if tree structure has changed
|
||||||
self._handleSeed = None # Used for generating handles for testing
|
self._handleSeed = None # Used for generating handles for testing
|
||||||
@@ -68,7 +67,6 @@ class NWTree():
|
|||||||
self._treeRoots = []
|
self._treeRoots = []
|
||||||
self._trashRoot = None
|
self._trashRoot = None
|
||||||
self._archRoot = None
|
self._archRoot = None
|
||||||
self._theLength = 0
|
|
||||||
self._theIndex = 0
|
self._theIndex = 0
|
||||||
self._treeChanged = False
|
self._treeChanged = False
|
||||||
return
|
return
|
||||||
@@ -81,8 +79,8 @@ class NWTree():
|
|||||||
def append(self, tHandle, pHandle, nwItem):
|
def append(self, tHandle, pHandle, nwItem):
|
||||||
"""Add a new item to the end of the tree.
|
"""Add a new item to the end of the tree.
|
||||||
"""
|
"""
|
||||||
tHandle = checkString(tHandle, None, True)
|
tHandle = checkHandle(tHandle, None, True)
|
||||||
pHandle = checkString(pHandle, None, True)
|
pHandle = checkHandle(pHandle, None, True)
|
||||||
if tHandle is None:
|
if tHandle is None:
|
||||||
tHandle = self._makeHandle()
|
tHandle = self._makeHandle()
|
||||||
|
|
||||||
@@ -108,16 +106,16 @@ class NWTree():
|
|||||||
else:
|
else:
|
||||||
logger.error("Only one trash folder allowed")
|
logger.error("Only one trash folder allowed")
|
||||||
|
|
||||||
self._theLength = len(self._treeOrder)
|
|
||||||
self._setTreeChanged(True)
|
self._setTreeChanged(True)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def packXML(self, xParent):
|
def packXML(self, xParent):
|
||||||
"""Pack the content of the tree into an XML object.
|
"""Pack the content of the tree into the provided XML object. In
|
||||||
|
the order defined by the _treeOrder list.
|
||||||
"""
|
"""
|
||||||
xContent = etree.SubElement(xParent, "content", attrib={
|
xContent = etree.SubElement(xParent, "content", attrib={
|
||||||
"count": str(self._theLength)}
|
"count": str(len(self._treeOrder))}
|
||||||
)
|
)
|
||||||
for tHandle in self._treeOrder:
|
for tHandle in self._treeOrder:
|
||||||
tItem = self.__getitem__(tHandle)
|
tItem = self.__getitem__(tHandle)
|
||||||
@@ -309,7 +307,6 @@ class NWTree():
|
|||||||
|
|
||||||
# Save the temp list
|
# Save the temp list
|
||||||
self._treeOrder = tmpOrder
|
self._treeOrder = tmpOrder
|
||||||
self._theLength = len(self._treeOrder)
|
|
||||||
self._setTreeChanged(True)
|
self._setTreeChanged(True)
|
||||||
logger.verbose("Project tree order updated")
|
logger.verbose("Project tree order updated")
|
||||||
|
|
||||||
@@ -330,7 +327,7 @@ class NWTree():
|
|||||||
if tItem is None:
|
if tItem is None:
|
||||||
return False
|
return False
|
||||||
if tItem.itemType != nwItemType.FILE:
|
if tItem.itemType != nwItemType.FILE:
|
||||||
logger.error("Item '%s' is not a file" % tHandle)
|
logger.error("Item %s is not a file" % tHandle)
|
||||||
return False
|
return False
|
||||||
if not isinstance(itemLayout, nwItemLayout):
|
if not isinstance(itemLayout, nwItemLayout):
|
||||||
return False
|
return False
|
||||||
@@ -370,12 +367,12 @@ class NWTree():
|
|||||||
def __len__(self):
|
def __len__(self):
|
||||||
"""Return the length counter. Does not check that it is correct!
|
"""Return the length counter. Does not check that it is correct!
|
||||||
"""
|
"""
|
||||||
return self._theLength
|
return len(self._treeOrder)
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
"""Returns True if the tree has any entries.
|
"""Returns True if the tree has any entries.
|
||||||
"""
|
"""
|
||||||
return self._theLength > 0
|
return len(self._treeOrder) > 0
|
||||||
|
|
||||||
##
|
##
|
||||||
# Item Access Methods
|
# Item Access Methods
|
||||||
@@ -391,19 +388,21 @@ class NWTree():
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def __delitem__(self, tHandle):
|
def __delitem__(self, tHandle):
|
||||||
"""This only removes the item from the order list, but not from
|
"""Remove an item from the internal lists and dictionaries.
|
||||||
the project tree.
|
|
||||||
"""
|
"""
|
||||||
if tHandle not in self._treeOrder:
|
if tHandle in self._treeOrder and tHandle in self._projTree:
|
||||||
logger.warning(
|
self._treeOrder.remove(tHandle)
|
||||||
"Could not remove item %s from project tree as it does not exist" % tHandle
|
del self._projTree[tHandle]
|
||||||
)
|
else:
|
||||||
|
logger.warning("Failed to delete item %s: item not found" % tHandle)
|
||||||
return False
|
return False
|
||||||
self._treeOrder.remove(tHandle)
|
|
||||||
self._theLength = len(self._treeOrder)
|
|
||||||
|
|
||||||
if tHandle in self._treeRoots:
|
if tHandle in self._treeRoots:
|
||||||
self._treeRoots.remove(tHandle)
|
self._treeRoots.remove(tHandle)
|
||||||
|
if tHandle == self._trashRoot:
|
||||||
|
self._trashRoot = None
|
||||||
|
if tHandle == self._archRoot:
|
||||||
|
self._archRoot = None
|
||||||
|
|
||||||
self._setTreeChanged(True)
|
self._setTreeChanged(True)
|
||||||
|
|
||||||
@@ -427,7 +426,7 @@ class NWTree():
|
|||||||
def __next__(self):
|
def __next__(self):
|
||||||
"""Returns the item from the next entry in the _treeOrder list.
|
"""Returns the item from the next entry in the _treeOrder list.
|
||||||
"""
|
"""
|
||||||
if self._theIndex < self._theLength:
|
if self._theIndex < len(self._treeOrder):
|
||||||
theItem = self.__getitem__(self._treeOrder[self._theIndex])
|
theItem = self.__getitem__(self._treeOrder[self._theIndex])
|
||||||
self._theIndex += 1
|
self._theIndex += 1
|
||||||
return theItem
|
return theItem
|
||||||
|
|||||||
+5
-5
@@ -378,11 +378,11 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def deleteItem(self, tHandle=None, alreadyAsked=False, askForTrash=False):
|
def deleteItem(self, tHandle=None, alreadyAsked=False, askForTrash=False):
|
||||||
"""Delete items from the tree. Note that this does not delete
|
"""Delete an item from the project tree. As a first step, files are
|
||||||
the item from the item tree in the project object. However,
|
moved to the Trash folder. Permanent deletion is a second step. This
|
||||||
since this is only meta data, there isn't really a need to do
|
second step also deletes the item from the project object as well as
|
||||||
that to save memory. Items not in the tree are not saved to the
|
delete the files on disk. Folders are deleted if they're empty only,
|
||||||
project file, so a loaded project will be clean anyway.
|
and the deletion is always permanent.
|
||||||
"""
|
"""
|
||||||
if tHandle is None:
|
if tHandle is None:
|
||||||
tHandle = self.getSelectedHandle()
|
tHandle = self.getSelectedHandle()
|
||||||
|
|||||||
+10
-1
@@ -5,7 +5,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from nw.common import (
|
from nw.common import (
|
||||||
checkString, checkBool, checkInt, colRange, formatInt, transferCase,
|
checkString, checkBool, checkInt, colRange, formatInt, transferCase,
|
||||||
fuzzyTime
|
fuzzyTime, checkHandle
|
||||||
)
|
)
|
||||||
from nwtools import cmpList
|
from nwtools import cmpList
|
||||||
|
|
||||||
@@ -42,6 +42,15 @@ def testCheckBool():
|
|||||||
assert checkBool(1.0, None, False) is None
|
assert checkBool(1.0, None, False) is None
|
||||||
assert checkBool(2.0, None, False) is None
|
assert checkBool(2.0, None, False) is None
|
||||||
|
|
||||||
|
@pytest.mark.core
|
||||||
|
def testCheckHandle():
|
||||||
|
assert checkHandle("None", 1, True) is None
|
||||||
|
assert checkHandle("None", 1, False) == 1
|
||||||
|
assert checkHandle(None, 1, True) is None
|
||||||
|
assert checkHandle(None, 1, False) == 1
|
||||||
|
assert checkHandle("47666c91c7ccf", None, False) == "47666c91c7ccf"
|
||||||
|
assert checkHandle("h7666c91c7ccf", None, False) is None
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testColRange():
|
def testColRange():
|
||||||
assert colRange([0, 0], [0, 0], 0) is None
|
assert colRange([0, 0], [0, 0], 0) is None
|
||||||
|
|||||||
Reference in New Issue
Block a user