def removeElements(self, parent, rows): """Reimplements LevelTreeModel.removeElements so that elements that have been removed from the tree are also removed from editor level (unless they still appear in some EditorModel). """ stack.beginMacro(self.tr("Remove elements")) # All elements from toCheck that are nowhere present in the editor will be removed. if isinstance(parent, Element): toCheck = [parent.contents[i] for i in rows] else: toCheck = [parent.contents[i].element.id for i in rows] super().removeElements(parent, rows) checked = set() elementsToRemove = [] rootIds = [w.element.id for editorModel in EditorModel.instances for w in editorModel.root.contents] i = 0 while i < len(toCheck): elid = toCheck[i] i += 1 if elid in checked or elid not in self.level: continue element = self.level[elid] if not any(id in rootIds for id in self._getAncestorsInEditorLevel(element)): elementsToRemove.append(element) if element.isContainer(): toCheck.extend(element.contents) # check contents recursively checked.add(elid) if len(elementsToRemove) > 0: empty = elements.ContentList() contentsDict = {element: empty for element in elementsToRemove if element.isContainer()} self.level.changeContents(contentsDict) self.level.removeElements(elementsToRemove) stack.endMacro()
def doAction(self): model = self.parent().model() byParent = {} wrappers = self.parent().selection.wrappers() for wrapper in wrappers: if any(p in wrappers for p in wrapper.getParents()): continue parent = wrapper.parent if parent not in byParent: byParent[parent] = [] byParent[parent].append(parent.contents.index(wrapper)) for parent, indexes in byParent.items(): byParent[parent] = sorted(set(indexes)) stack.beginMacro('remove') from maestro.widgets import browser if isinstance(model, leveltreemodel.LevelTreeModel): for parent, indexes in byParent.items(): model.removeElements(parent, indexes) elif isinstance(model, browser.model.BrowserModel): for parent, indexes in byParent.items(): self.level().removeContentsAuto(parent.element, indexes=indexes) else: raise NotImplementedError() stack.endMacro()
def removeElements(self, parent, rows): """Undoably remove elements in *rows* under *parent* (a wrapper, an element or the root node). This convenience function either alters the RootNode, if parent is self.root, or updates the level. """ stack.beginMacro(self.tr('remove elements')) if parent is self.root: stack.push(RemoveFromRootCommand(self, rows)) else: element = parent if isinstance(parent, elements.Element) else parent.element self.level.removeContentsAuto(element, indexes=rows) stack.endMacro()
def removeElements(self, parent, rows): """Undoably remove elements in *rows* under *parent* (a wrapper, an element or the root node). This convenience function either alters the RootNode, if parent is self.root, or updates the level. """ stack.beginMacro(self.tr('remove elements')) if parent is self.root: stack.push(RemoveFromRootCommand(self, rows)) else: element = parent if isinstance( parent, elements.Element) else parent.element self.level.removeContentsAuto(element, indexes=rows) stack.endMacro()
def accept(self): stack.beginMacro(self.tr("Hide values"), transaction=True) from maestro.core import tagcommands for i in range(self.treeWidget.topLevelItemCount()): tagItem = self.treeWidget.topLevelItem(i) tag = tagItem.data(0, Qt.UserRole) vids = [] if tagItem.checkState(0) != Qt.Unchecked: for j in range(tagItem.childCount()): valueItem = tagItem.child(j) if valueItem.checkState(0) == Qt.Checked: vids.append(valueItem.data(0, Qt.UserRole)) if len(vids) > 0: stack.push(tagcommands.HiddenAttributeCommand(tag, vids, True)) stack.endMacro() self.close()
def doAction(self): stack = self.level().stack stack.beginMacro(self.tr('flatten container(s)')) wrappers = self.parent().selection.wrappers() elements = [wrapper.element for wrapper in wrappers] positions = [wrapper.position for wrapper in wrappers] parent = wrappers[0].parent.element indices = sorted([parent.contents.positions.index(pos) for pos in positions], reverse=True) for i, index in enumerate(indices, start=1): element = self.level().collect(parent.contents.ids[index]) pos = parent.contents.positions[index] children = list(element.getContents()) self.level().removeContents(parent, [pos]) self.level().removeContents(element, element.contents.positions) if element not in elements[:-i]: self.level().removeElements([element]) self.level().insertContentsAuto(parent, index, children) stack.endMacro()
def deleteElements(self, elements, fromDisk=False): elements = tuple(elements) stack.beginMacro("delete elements") # 1st step: isolate the elements (remove contents & parents) for element in elements: if element.isContainer() and len(element.contents) > 0: self.removeContents(element, element.contents.positions) if len(element.parents) > 0: for parentId in element.parents: parent = self.collect(parentId) self.removeContents(parent, parent.contents.positionsOf(id=element.id)) self.removeFromDb([element for element in elements if element.isInDb()]) stack.endMacro() if fromDisk: for element in elements: if element.isFile(): element.url.backendFile().delete() stack.clear()
def dropMimeData(self, mimeData, action, row, column, parentIndex): """Drop stuff into a leveltreemodel. Handles Maestro mime and text/uri-list. If URLs are dropped, they are loaded into the level. If there is an album guesser specified, it is run on the URLs before they are inserted. Elements dropped on the top layer are just inserted under the RootNode. Otherwise, the level is modified accordingly. """ if action == Qt.IgnoreAction: return True # Compute drop position parent = self.data(parentIndex, Qt.EditRole) if parent.isFile(): # Drop onto a file => drop behind it row = parent.parent.index(parent) + 1 parent = parent.parent elif row == -1: # no specific position: insert at the beginning or end if self.dndTarget is not None and self.dndTarget.isExpanded( parentIndex): row = 0 else: row = parent.getContentsCount() stack.beginMacro(self.tr("drop")) # Get elements to insert if mimeData.hasFormat(config.options.gui.mime): ids = [node.element.id for node in mimeData.wrappers()] elements = self.level.collect(ids) else: # text/uri-list try: elements = self.prepareURLs(mimeData.urls(), parent) except CancelledByUser: stack.abortMacro() return False if len(elements) > 0: self.insertElements(parent, row, elements) self.rowsDropped.emit(self.getIndex(parent), row, row + len(elements) - 1) stack.endMacro() return len(elements) != 0
def dropMimeData(self, mimeData, action, row, column, parentIndex): """Drop stuff into a leveltreemodel. Handles Maestro mime and text/uri-list. If URLs are dropped, they are loaded into the level. If there is an album guesser specified, it is run on the URLs before they are inserted. Elements dropped on the top layer are just inserted under the RootNode. Otherwise, the level is modified accordingly. """ if action == Qt.IgnoreAction: return True # Compute drop position parent = self.data(parentIndex, Qt.EditRole) if parent.isFile(): # Drop onto a file => drop behind it row = parent.parent.index(parent) + 1 parent = parent.parent elif row == -1: # no specific position: insert at the beginning or end if self.dndTarget is not None and self.dndTarget.isExpanded(parentIndex): row = 0 else: row = parent.getContentsCount() stack.beginMacro(self.tr("drop")) # Get elements to insert if mimeData.hasFormat(config.options.gui.mime): ids = [node.element.id for node in mimeData.wrappers()] elements = self.level.collect(ids) else: # text/uri-list try: elements = self.prepareURLs(mimeData.urls(), parent) except CancelledByUser: stack.abortMacro() return False if len(elements) > 0: self.insertElements(parent, row, elements) self.rowsDropped.emit(self.getIndex(parent), row, row + len(elements) - 1) stack.endMacro() return len(elements) != 0
def deleteElements(self, elements, fromDisk=False): elements = tuple(elements) stack.beginMacro("delete elements") # 1st step: isolate the elements (remove contents & parents) for element in elements: if element.isContainer() and len(element.contents) > 0: self.removeContents(element, element.contents.positions) if len(element.parents) > 0: for parentId in element.parents: parent = self.collect(parentId) self.removeContents( parent, parent.contents.positionsOf(id=element.id)) self.removeFromDb( [element for element in elements if element.isInDb()]) stack.endMacro() if fromDisk: for element in elements: if element.isFile(): element.url.backendFile().delete() stack.clear()
def clear(self): """Remove everything below the root node.""" stack.beginMacro(self.tr('clear')) self.removeElements(self.root, range(len(self.root.contents))) stack.endMacro()