diff --git a/manuskript/models/outlineModel.py b/manuskript/models/outlineModel.py index 4b26084b..4acc034a 100644 --- a/manuskript/models/outlineModel.py +++ b/manuskript/models/outlineModel.py @@ -253,23 +253,65 @@ class outlineModel(QAbstractItemModel): return Qt.CopyAction | Qt.MoveAction - # def canDropMimeData(self, data, action, row, column, parent): - # if not data.hasFormat("application/xml"): - # return False + def canDropMimeData(self, data, action, row, column, parent): + """Ensures that we are not droping an item into itself.""" - # if column > 0: - # return False + if not data.hasFormat("application/xml"): + return False - # return True + if column > 0: + return False + + # # Gets encoded mime data to retrieve the item + items = self.decodeMimeData(data) + if items is None: + return False + + # Get the parent item + if not parent.isValid(): + parentItem = self.rootItem + else: + parentItem = parent.internalPointer() + + for item in items: + # Get parentItem's parents IDs in a list + path = parentItem.pathID() # path to item in the form [(ID, title), ...] + path = [ID for ID, title in path] + # Is item in the path? It would mean that it tries to get dropped + # as a children of himself. + if item.ID() in path: + return False + + return True + + def decodeMimeData(self, data): + if not data.hasFormat("application/xml"): + return None + encodedData = bytes(data.data("application/xml")).decode() + root = ET.XML(encodedData) + if root is None: + return None + + if root.tag != "outlineItems": + return None + + items = [] + for child in root: + if child.tag == "outlineItem": + item = outlineItem(xml=ET.tostring(child)) + items.append(item) + + return items def dropMimeData(self, data, action, row, column, parent): if action == Qt.IgnoreAction: return True # What is that? - if not data.hasFormat("application/xml"): + items = self.decodeMimeData(data) + if items is None: return False - + if column > 0: column = 0 @@ -280,19 +322,6 @@ class outlineModel(QAbstractItemModel): else: beginRow = self.rowCount() + 1 - encodedData = bytes(data.data("application/xml")).decode() - - root = ET.XML(encodedData) - - if root.tag != "outlineItems": - return False - - items = [] - for child in root: - if child.tag == "outlineItem": - item = outlineItem(xml=ET.tostring(child)) - items.append(item) - if not items: return False @@ -705,7 +734,7 @@ class outlineItem(): def pathID(self): "Returns path to item as list of (ID, title)." - if self.parent().parent(): + if self.parent() and self.parent().parent(): return self.parent().pathID() + [(self.ID(), self.title())] else: return [(self.ID(), self.title())] diff --git a/manuskript/ui/editors/editorWidget.py b/manuskript/ui/editors/editorWidget.py index 4b188976..1a367e49 100644 --- a/manuskript/ui/editors/editorWidget.py +++ b/manuskript/ui/editors/editorWidget.py @@ -196,7 +196,6 @@ class editorWidget(QWidget, Ui_editorWidget_ui): self.mw.mdlOutline.dataChanged.connect(self.modelDataChanged, AUC) self.mw.mdlOutline.rowsInserted.connect(self.updateIndexFromID, AUC) self.mw.mdlOutline.rowsRemoved.connect(self.updateIndexFromID, AUC) - self.mw.mdlOutline.rowsAboutToBeRemoved.connect(self.rowsAboutToBeRemoved, AUC) except TypeError: pass @@ -226,13 +225,6 @@ class editorWidget(QWidget, Ui_editorWidget_ui): if topLeft.row() <= self.currentIndex.row() <= bottomRight.row(): self.updateStatusBar() - def rowsAboutToBeRemoved(self, parent, first, last): - if self.currentIndex: - if self.currentIndex.parent() == parent and \ - first <= self.currentIndex.row() <= last: - # Item deleted, close tab - self.mw.mainEditor.tab.removeTab(self.mw.mainEditor.tab.indexOf(self)) - def updateStatusBar(self): # Update progress # if self.currentIndex and self.currentIndex.isValid():