class ModifIndex(QDialog, Ui_ModifIndex): """ This class is used to graphically configures indexation : * its content * its behaviour and the type of data which musts be indexed It is composed of three tabs : Index, Advanced and Attributes. The `Index` tab us composed of two main widgets : * a NodeLinkTreeView, called `selectIndexItems`, connected to an instance of a TreeModel (see api.gui.model.vfsitemmodel, class TreeModel and api.gui.widget.nodeview, class NodeLinkTreeView). It displays the tree view of the VFS' nodes, with checkboxes used to select nodes the user wants to add in the index. * a QTableWidget, called `indexedItems`, used to summarize the list of already indexed nodes. By checking / unchecking a nodes in the NodeLinkTreeView, it adds / removes elements in the `indexedItems` view. If an element is unchecked and the `OK` button clicked, the element will be removed from the index. On the contrary, if an element is checked in the NodeLinkTreeView and the `OK` button clicked, it will add it in the index ONLY if it was not already indexed. Changed are applied when the `OK` button is clicked. """ def __init__(self, parent, model): """ Constructor. Initialize parent, gui and translation. Connect signals. """ super(QDialog, self).__init__() self.parent = parent self.setupUi(self) self.translation() self.initTableWidget() self.initMimeTypes() self.indexed_items = {} self.tmp_indexed_items = {} self.un_index = {} self.indexedItems.setColumnCount(2) self.indexedItems.setRowCount(self.load_items()) self.model = TreeModel(self) self.model.root_item = model.root_item self.model.setCh(True) self.selectIndexItems = NodeLinkTreeView(None, True) self.selectIndexItems.setModel(self.model) vbox = QVBoxLayout() vbox.addWidget(self.selectIndexItems) self.groupBox_5.setLayout(vbox) self.connect(self.selectIndexItems, SIGNAL("nodeTreeClicked"), self.nodeTreeClicked) self.connect(self.selectIndexItems.model(), SIGNAL("stateChanged"), self.selectNodeChanged) self.connect(self.indexedItems, SIGNAL("itemChanged(QTableWidgetItem *)"), \ self.IAmBabarTheElephantKing) self.connect(self.indexedItems, SIGNAL("itemClicked"), self.IAmBabarTheElephantKing) def initTableWidget(self): """ Initialize the QTableWidget `indexedItems`. Set the headers. """ self.indexedItems.setColumnCount(2) # set the headers' titles and stretch the last section head1 = QTableWidgetItem(self.headIndexedItemTr) head2 = QTableWidgetItem(self.headRecursivelyTr) self.indexedItems.setHorizontalHeaderItem(0, head1) self.indexedItems.setHorizontalHeaderItem(1, head2) self.indexedItems.horizontalHeader().setStretchLastSection(True) # hide vertical header and grid, remove editable mode self.indexedItems.verticalHeader().hide() self.indexedItems.setEditTriggers(QAbstractItemView.NoEditTriggers) self.indexedItems.setShowGrid(False) self.indexedItems.setAlternatingRowColors(True) self.indexedItems.setSelectionBehavior(QAbstractItemView.SelectRows) def load_items(self): """ Load items from the indexed_items list and add them in the self.indexedItems QTableWidget. """ count = 0 # get the list of already indexed stuff and add them in the qtablewidget # with a not-editable check box indicating if it has been indexed # recursively or not for i in self.indexed_items: node = VFS.Get().getNodeFromPointer(long(i)) if node == None: continue recurse = self.indexed_items[i] new_item = QTableWidgetItem(QIcon(":/folder.png"), node.name()) self.indexedItems.setRowCount(count + 1) new_item.setData(Qt.UserRole + 1, QVariant(long(node.this))) self.indexedItems.setItem(count, 0, new_item) new_item2 = QTableWidgetItem() new_item2.setFlags(Qt.ItemIsUserCheckable) if recurse: new_item2.setCheckState(Qt.Checked) else: new_item2.setCheckState(Qt.Unchecked) self.indexedItems.setItem(count, 1, new_item2) count += 1 return count def initMimeTypes(self): self.typesTree = MimeTypesTree(self.mimeTypeList) self.mimeTypeList.setHeaderLabels([self.mimeTypeTr]) def selectNodeChanged(self, index): """ This slot is called when a node is checked / unchecked. Then, the method `addNodeInIndexList` or `removeNodeFromIndexList` is called (of course depending if it was checked of unchcked). """ if not index.isValid(): return d = self.selectIndexItems.model().data(index, Qt.CheckStateRole) if d == Qt.Checked: self.addNodeInIndexList(index) else: self.removeNodeFromIndexList(index) def addNodeInIndexList(self, index): """ Add the node wich pointer is index.data(QT.UserRole + 1) in the indexedItems list. """ # get the node from the index node_ptr = self.selectIndexItems.model().data(index, Qt.UserRole + 1) if not node_ptr.isValid(): return added_node = VFS.Get().getNodeFromPointer(node_ptr.toULongLong()[0]) # add the node.this into the selected items list new_item = QTableWidgetItem(QIcon(":/folder.png"), added_node.name()) new_item.setData(Qt.UserRole + 1, QVariant(long(added_node.this))) self.tmp_indexed_items[long(added_node.this)] = False new_checkbox = QTableWidgetItem(1); new_checkbox.data(Qt.CheckStateRole); new_checkbox.setCheckState(Qt.Unchecked); self.indexedItems.insertRow(0) self.indexedItems.setItem(0, 0, new_item) self.indexedItems.setItem(0, 1, new_checkbox) def IAmBabarTheElephantKing(self, item): if item.column() == 0: return row = item.row() item_check = self.indexedItems.itemAt(row, 0) data = item_check.data(Qt.UserRole + 1) if not data.isValid(): return ptr = data.toULongLong()[0] try: self.tmp_indexed_items[long(ptr)] = not self.tmp_indexed_items[long(ptr)] except KeyError: pass def removeNodeFromIndexList(self, index): """ Remove the node wich pointer is index.data(QT.UserRole + 1) from the indexedItems list. """ # get the node from the index (if one of them is invalid, returns) if not index.isValid(): return node_ptr = self.selectIndexItems.model().data(index, Qt.UserRole + 1) if not node_ptr.isValid(): return # get the ptr of the node and search for the it in the indexedItems list ptr = node_ptr.toULongLong()[0] # for each items in the indexed_list, check if the value is equal to # `ptr`. If yes, remove the item from the QTableWidget self.indexedItems. found = False for i in range(0, len(self.indexed_items)): item = self.indexedItems.item(i, 0) if item != None: value = item.data(Qt.UserRole + 1) if value.isValid(): if value.toULongLong()[0] == ptr: self.indexedItems.removeRow(i) self.un_index[ptr] = self.indexed_items[ptr] found = True break if not found: for i in range(0, len(self.tmp_indexed_items)): item = self.indexedItems.item(i, 0) if item != None: value = item.data(Qt.UserRole + 1) if value.isValid(): if value.toULongLong()[0] == ptr: self.indexedItems.removeRow(i) break # finally pop the item from the indexed_items or tmp_indexed_items map try: if not found: self.tmp_indexed_items.pop(ptr) except KeyError: pass def nodeTreeClicked(self, mouseButton, node, index = None): """ This slot is called when a node from the NodeLinkTreeView is clicked. """ self.selectIndexItems.model().setRootPath(node) def translation(self): """ Used for the dynamic translations. """ self.headIndexedItemTr = self.tr("Indexed items") self.headRecursivelyTr = self.tr("Recursively") self.mimeTypeTr = self.tr("Mime types")
class DialogNodeBrowser(QDialog): def __init__(self, parent=None): QDialog.__init__(self, parent) self.title = QLabel("Select a node in the Virtual File System :") self.vfs = vfs.vfs() self.VFS = VFS.Get() self.createLayout() self.createModels() self.createViews() self.createButtons() def createLayout(self): self.navBar = NavigationBar(self) self.baseLayout = QVBoxLayout(self) self.baseLayout.setMargin(0) self.baseLayout.setSpacing(0) self.splitterLayout = QSplitter(self) self.splitterLayout.setMinimumWidth(640) self.baseLayout.addWidget(self.navBar, 1) self.baseLayout.addWidget(self.splitterLayout, 50) self.setLayout(self.baseLayout) def createModels(self): self.treeModel = TreeModel(self) # self.treeModel.coord = True self.tableModel = VFSItemModel(self) self.treeModel.setRootPath(self.vfs.getnode("/")) self.tableModel.setRootPath(self.vfs.getnode("/")) self.tableModel.connect(self.navBar, SIGNAL("pathChanged"), self.tableModel.setRootPath) def createViews(self): self.treeView = NodeLinkTreeView(self) self.treeView.setModel(self.treeModel) self.connect(self.treeView, SIGNAL("nodeTreeClicked"), self.nodeTreeClicked) self.splitterLayout.addWidget(self.treeView) self.tableView = NodeTableView(self) self.tableView.setModel(self.tableModel) self.connect(self.tableView, SIGNAL("nodeDoubleClicked"), self.nodeDoubleClicked) self.splitterLayout.addWidget(self.tableView) def nodeTreeClicked(self, mouseButton, node, index = None): self.treeView.model().setRootPath(node) self.tableView.model().setRootPath(node) def nodeDoubleClicked(self, mouseButton, node, index = None): if node == None: return if node.hasChildren() or node.isDir(): self.tableView.model().setRootPath(node) self.navBar.updateCurrentPath(node) def createButtons(self): self.buttonBox = QDialogButtonBox() self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.connect(self.buttonBox, SIGNAL("accepted()"),self.accept) self.connect(self.buttonBox, SIGNAL("rejected()"),self.reject) self.baseLayout.addWidget(self.buttonBox) def getSelectedNodes(self): indexes = self.tableView.selectionModel().selectedRows() nodes = [] for index in indexes: if index.isValid(): nodes.append(self.VFS.getNodeFromPointer(index.internalId())) return nodes def getSelectedNode(self): index = self.tableView.selectionModel().currentIndex() node = None if index.isValid(): node = self.VFS.getNodeFromPointer(index.internalId()) return node def setSelectionMode(self, mode): self.tableView.setSelectionMode(mode) def changeEvent(self, event): """ Search for a language change event This event have to call retranslateUi to change interface language on the fly. """ if event.type() == QEvent.LanguageChange: self.model.translation() else: QWidget.changeEvent(self, event)
class NodeBrowser(QWidget, EventHandler, Ui_NodeBrowser): def __init__(self, parent): super(QWidget, self).__init__() EventHandler.__init__(self) self.setupUi(self) self.mainwindow = parent self.getWindowGeometry() self.name = self.windowTitle() self.type = "filebrowser" self.setObjectName(self.name) self.vfs = vfs.vfs() self.VFS = VFS.Get() self.VFS.connection(self) self.loader = loader.loader() self.lmodules = self.loader.modules self.taskmanager = TaskManager() self.parent = parent self.icon = None self.createSubMenu() self.createLayout() self.addModel("/") self.addNodeLinkTreeView() self.addNodeView() self.addOptionsView() def Event(self, e): self.model.emit(SIGNAL("layoutAboutToBeChanged()")) self.model.emit(SIGNAL("layoutChanged()")) self.treeModel.emit(SIGNAL("layoutAboutToBeChanged()")) self.treeModel.emit(SIGNAL("layoutChanged()")) def getWindowGeometry(self): self.winWidth = self.mainwindow.width() def createLayout(self): self.baseLayout = QVBoxLayout(self) self.baseLayout.setMargin(0) self.baseLayout.setSpacing(0) self.browserLayout = QSplitter(self) self.baseLayout.insertWidget(0, self.browserLayout) self.baseLayout.setStretchFactor(self.browserLayout, 1) def addOptionsView(self): self.nodeViewBox = NodeViewBox(self) self.nodeFilterBox = NodeFilterBox(self, self.treeModel) self.nodeFilterBox.vfs_item_model(self.model) self.baseLayout.insertWidget(0,self.nodeFilterBox) self.baseLayout.insertWidget(0, self.nodeViewBox) self.nodeFilterBox.setVisible(False) def addModel(self, path): self.model = VFSItemModel(self, True, True) self.model.setRootPath(self.vfs.getnode(path)) ###### View searhing ##### def addSearchView(self): self.search_model = VfsSearchItemModel(self, True) self.treeModel.setRootPath(self.vfs.getnode("/")) def addNodeLinkTreeView(self): self.treeModel = TreeModel(self, True) self.treeModel.setRootPath(self.vfs.getnode("/")) self.treeProxyModel = self.treeModel self.treeView = NodeLinkTreeView(self) self.treeView.setModel(self.treeProxyModel) self.browserLayout.addWidget(self.treeView) self.browserLayout.setStretchFactor(self.browserLayout.indexOf(self.treeView), 0) # self.connect(self.treeView, SIGNAL("nodeTreeClicked"), self.nodeTreeDoubleClicked) self.connect(self.treeView, SIGNAL("nodeTreeClicked"), self.nodeTreeDoubleClicked) self.connect(self.treeView, SIGNAL("nodeTreeClicked"), self.treeModel.nodeClicked) def addNodeView(self): self.addTableView() self.addThumbsView() def addTableView(self): self.tableView = NodeTableView(self) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.setModel(self.model) self.tableView.setColumnWidth(0, 200) self.tableView.setSortingEnabled(True) self.tableView.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)) self.browserLayout.addWidget(self.tableView) self.browserLayout.setStretchFactor(self.browserLayout.indexOf(self.tableView), 1) self.connect(self.tableView, SIGNAL("nodePressed"), self.nodePressed) self.connect(self.tableView, SIGNAL("nodeClicked"), self.nodeClicked) self.connect(self.tableView, SIGNAL("nodeDoubleClicked"), self.nodeDoubleClicked) self.connect(self.tableView, SIGNAL(""), self.selectAttr) def selectAttr(self): pass def addThumbsView(self): self.thumbsView = NodeThumbsView(self) self.thumbsView.setModel(self.model) self.thumbsView.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)) self.browserLayout.addWidget(self.thumbsView) self.browserLayout.setStretchFactor(self.browserLayout.indexOf(self.thumbsView), 1) self.connect(self.thumbsView, SIGNAL("nodePressed"), self.nodePressed) self.connect(self.thumbsView, SIGNAL("nodeClicked"), self.nodeClicked) self.connect(self.thumbsView, SIGNAL("nodeDoubleClicked"), self.nodeDoubleClicked) def currentProxyModel(self): if self.thumbsView.isVisible(): return self.thumbsView.model() elif self.tableView.isVisible(): return self.tableView.model() def currentModel(self): if self.thumbsView.isVisible(): return self.thumbsView.model() elif self.tableView.isVisible(): return self.tableView.model() def currentView(self): if self.thumbsView.isVisible(): return self.thumbsView elif self.tableView.isVisible(): return self.tableView def currentNodes(self): indexList = self.currentView().selectionModel().selectedRows() nodeList = [] for index in indexList: if index.isValid(): nodeList.append(self.VFS.getNodeFromPointer(index.internalId())) return nodeList def currentNode(self): index = self.currentView().selectionModel().currentIndex() if index.isValid(): return self.VFS.getNodeFromPointer(index.internalId()) def nodePressed(self, key, node, index = None): if key in [Qt.Key_Up, Qt.Key_Down, Qt.Key_PageUp, Qt.Key_PageDown]: if self.nodeViewBox.propertyTable.isVisible(): self.nodeViewBox.propertyTable.fill(node) self.mainwindow.emit(SIGNAL("previewUpdate"), node) if key == Qt.Key_Return: if self.currentView().enterInDirectory: if node.hasChildren() or node.isDir(): self.currentModel().setRootPath(node) else: self.openDefault(node) else: self.openDefault(node) if key == Qt.Key_Backspace: self.currentModel().setRootPath(node.parent().parent()) def nodeClicked(self, mouseButton, node, index = None): if mouseButton == Qt.LeftButton: if self.nodeViewBox.propertyTable.isVisible(): self.nodeViewBox.propertyTable.fill(node) self.mainwindow.emit(SIGNAL("previewUpdate"), node) if mouseButton == Qt.RightButton: self.menuRelevant = MenuRelevant(self, self.parent, node) if node.hasChildren() or node.isDir(): self.actionOpen_in_new_tab.setEnabled(True) else: self.actionOpen_in_new_tab.setEnabled(False) self.submenuFile.popup(QCursor.pos()) self.submenuFile.show() def nodeTreeDoubleClicked(self, mouseButton, node, index = None): if node == None: return if self.currentView().enterInDirectory: if node.hasChildren() or node.isDir(): self.currentModel().setRootPath(node) def nodeDoubleClicked(self, mouseButton, node, index = None): if node == None: return if self.currentView().enterInDirectory: if node.hasChildren() or node.isDir(): self.currentModel().setRootPath(node) else: self.openDefault(node) else: self.openDefault(node) def sizeChanged(self, string): if self.nodeViewBox.thumbSize.currentIndex() == 0: self.thumbsView.setIconGridSize(64, 64) elif self.nodeViewBox.thumbSize.currentIndex() == 1: self.thumbsView.setIconGridSize(96, 96) elif self.nodeViewBox.thumbSize.currentIndex() == 2: self.thumbsView.setIconGridSize(128, 128) def openDefault(self, node = None): if not node: node = self.currentNode() if not node: return mods = node.compatibleModules() mods.reverse() if len(mods): for mod in mods: if "Viewers" in self.lmodules[mod].tags: break try: priority = modulePriority[mod] except KeyError: modulePriority[mod] = 0 priority = 0 if not priority: mbox = QMessageBox(QMessageBox.Question, self.tr("Apply module"), self.tr("Do you want to apply module ") + str(mod) + self.tr(" on this node ?"), QMessageBox.Yes | QMessageBox.No, self) mbox.addButton(self.tr("Always"), QMessageBox.AcceptRole) reply = mbox.exec_() if reply == QMessageBox.No: return elif reply == QMessageBox.AcceptRole: modulePriority[mod] = 1 if self.lmodules[mod]: conf = self.lmodules[mod].conf arguments = conf.arguments() marg = {} for argument in arguments: if argument.type() == typeId.Node: marg[argument.name()] = node args = conf.generate(marg) self.taskmanager.add(mod, args, ["thread", "gui"]) return else: errnodes = "" if node.size(): conf = self.lmodules["hexadecimal"].conf try: arg = conf.generate({"file": node}) self.taskmanager.add("hexadecimal", arg, ["thread", "gui"]) except RuntimeError: errnodes += node.absolute() + "\n" else: errnodes += node.absolute() + "\n" if len(errnodes): msg = QMessageBox(self) msg.setWindowTitle(self.tr("Empty files")) msg.setText(self.tr("the following nodes could not be opened with Hex viewer because they are either empty or folders\n")) msg.setIcon(QMessageBox.Warning) msg.setDetailedText(errnodes) msg.setStandardButtons(QMessageBox.Ok) ret = msg.exec_() def createSubMenu(self): self.extractor = Extractor(self.parent) self.connect(self.extractor, SIGNAL("filled"), self.launchExtract) self.submenuFile = QMenu() self.submenuFile.addAction(self.actionOpen) self.connect(self.actionOpen, SIGNAL("triggered()"), self.openDefault) self.submenuFile.addAction(self.actionOpen_in_new_tab) self.connect(self.actionOpen_in_new_tab, SIGNAL("triggered()"), self.openAsNewTab) self.submenuRelevant = self.submenuFile.addMenu(self.actionRelevant_module.icon(), self.actionRelevant_module.text()) self.menu = {} self.menuModule = self.submenuFile.addMenu(self.actionOpen_with.icon(), self.actionOpen_with.text()) self.menuTags = MenuTags(self, self.parent, self.currentNodes) self.submenuFile.addSeparator() self.submenuFile.addAction(self.actionHex_viewer) self.connect(self.actionHex_viewer, SIGNAL("triggered()"), self.launchHexedit) self.submenuFile.addAction(self.actionExtract) self.connect(self.actionExtract, SIGNAL("triggered()"), self.extractNodes) self.submenuFile.addSeparator() def openAsNewTab(self): node = self.currentNode() self.mainwindow.addNodeBrowser(node) def launchHexedit(self): nodes = self.currentNodes() conf = self.loader.get_conf("hexadecimal") errnodes = "" for node in nodes: if node.size(): try: arg = conf.generate({"file": node}) self.taskmanager.add("hexadecimal", arg, ["thread", "gui"]) except RuntimeError: errnodes += node.absolute() + "\n" else: errnodes += node.absolute() + "\n" if len(errnodes): msg = QMessageBox(self) msg.setWindowTitle(self.tr("Empty files")) msg.setText(self.tr("the following nodes could not be opened with Hex viewer because they are either empty or folders\n")) msg.setIcon(QMessageBox.Warning) msg.setDetailedText(errnodes) msg.setStandardButtons(QMessageBox.Ok) ret = msg.exec_() def extractNodes(self): self.extractor.launch(self.currentNodes()) def launchExtract(self): res = self.extractor.getArgs() args = {} args["files"] = res["nodes"] args["syspath"] = str(res["path"]) args["recursive"] = res["recurse"] conf = self.loader.get_conf("extract") try: margs = conf.generate(args) self.taskmanager.add("extract", margs, ["thread", "gui"]) except RuntimeError: pass def changeEvent(self, event): """ Search for a language change event This event have to call retranslateUi to change interface language on the fly. """ if event.type() == QEvent.LanguageChange: self.retranslateUi(self) self.menuModule.setTitle(self.actionOpen_with.text()) self.submenuRelevant.setTitle(self.actionRelevant_module.text()) self.model.translation() self.treeModel.translation() else: QWidget.changeEvent(self, event)