class TriageFilePicker(QWidget): def __init__(self, context): super(TriageFilePicker, self).__init__() self.context = context self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.contextMenu = Menu() self.contextMenuManager = ContextMenuManager(self) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.model = QFileSystemModel() self.model.setRootPath("") self.model.setFilter(QDir.AllEntries | QDir.Hidden | QDir.System) self.tree = QTreeView(self) self.tree.setModel(self.model) self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tree.setColumnWidth(0, 500) layout.addWidget(self.tree, 1) self.setLayout(layout) self.tree.doubleClicked.connect(self.onDoubleClick) recentFile = QSettings().value("triage/recentFile", os.path.expanduser("~")) while len(recentFile) > 0: f = self.model.index(recentFile) if f.isValid(): self.tree.scrollTo(f) self.tree.setExpanded(f, True) break parentDir = os.path.dirname(recentFile) if parentDir == recentFile: break recentFile = parentDir self.actionHandler.bindAction("Open Selected Files", UIAction( lambda context: self.openSelectedFiles(), lambda context: self.areFilesSelected())) self.contextMenu.addAction("Open Selected Files", "Open") def contextMenuEvent(self, event): self.contextMenuManager.show(self.contextMenu, self.actionHandler) def onDoubleClick(self, index): self.openSelectedFiles() def openSelectedFiles(self): failedToOpen = [] files = set() for index in self.tree.selectionModel().selectedIndexes(): if self.model.fileInfo(index).isFile(): files.add(self.model.fileInfo(index).absoluteFilePath()) for filename in files: QSettings().setValue("triage/recentFile", filename) f = FileContext.openFilename(filename) if not f: failedToOpen.append(filename) continue f.createBinaryViews() for data in f.getAllDataViews(): Settings().set_string("analysis.mode", Settings().get_string("triage.analysisMode"), data) Settings().set_bool("triage.preferSummaryView", True, data) if data.view_type != "Raw": linearSweepMode = Settings().get_string("triage.linearSweep") if linearSweepMode == "none": Settings().set_bool("analysis.linearSweep.autorun", False, data) elif linearSweepMode == "partial": Settings().set_bool("analysis.linearSweep.autorun", True, data) Settings().set_bool("analysis.linearSweep.controlFlowGraph", False, data) elif linearSweepMode == "full": Settings().set_bool("analysis.linearSweep.autorun", True, data) Settings().set_bool("analysis.linearSweep.controlFlowGraph", True, data) self.context.openFileContext(f) if len(failedToOpen) > 0: QMessageBox.critical(self, "Error", "Unable to open:\n" + "\n".join(failedToOpen)) def areFilesSelected(self): return self.tree.selectionModel().hasSelection()
class BrowserWidget(QWidget): """ This class puts together a TabCompletionLineEdit and a list view of teh FolderListModel in one single widget. """ activated = Signal(str) # emitted when the user selects a file def __init__(self, parent=None): super().__init__(parent) self._recursiveActivated = False self._model = FolderListModel(self) self._completer = QCompleter(self._model, self) self._completer.setCompletionColumn(3) self._lineedit = TabCompletionLineEdit(self._completer, self) self._view = QTreeView(self) self._view.setModel(self._model) self._model.folderChanged.connect(self._lineedit.setText) self._model.setFolder(".") self._view.header().setSectionResizeMode(0, QHeaderView.Interactive) self._view.header().setSectionResizeMode(1, QHeaderView.ResizeToContents) self._view.header().setSectionResizeMode(2, QHeaderView.ResizeToContents) self._view.header().resizeSection(0, 500) self._view.header().setSectionHidden(3, True) layout = QVBoxLayout(self) layout.addWidget(self._lineedit) layout.addWidget(self._view) self.setLayout(layout) self._view.activated.connect(self._activated) self.activated.connect(self._lineedit.setText) self._lineedit.returnPressed.connect(self._leActivated, Qt.QueuedConnection) self._lineedit.textEdited.connect(self._leTextEdited) def setActive(self, activeFile): """ set the activated file :param activeFile: a string or Path instance :return: """ activeFile = Path(activeFile) assert activeFile.is_file() self._model.setFolder(activeFile.parent) idx = self._model.fileToIndex(activeFile) self._view.setCurrentIndex(idx) self._view.scrollTo(idx) self.activated.emit(str(activeFile)) def active(self): """ The currently activated file :return: a string instance """ cidx = self._view.currentIndex() c = self._model.data(cidx, Qt.UserRole) return str(c) if c is not None else None def current(self): """ A synonym for active() :return: a string instance """ return self.active() def setFilter(self, flt): """ Set the name filter of the file browser :param flt: a string instance or a list of strings :return: """ self._model.setFilter(flt) def scrollTo(self, item): """ Scrolls to the given item. :param item: a string instance :return: """ cidx = self._model.fileToIndex(item) self._view.scrollTo(cidx) def folder(self): """ Returns the current folder :return: a Path instance """ return self._model.folder() def setFolder(self, folder): """ Sets the current folder :param folder: a string or a Path instance :return: """ self._model.setFolder(folder) def _leActivated(self): idx = self._model.fileToIndex(self._lineedit.text()) self._activated(idx) def _leTextEdited(self, text): p = Path(text) if p.is_dir() and len(text) > 0 and text[-1] in ["/", "\\"]: self.setFolder(p) def _activated(self, idx): c = self._model.data(idx, Qt.UserRole) if c is None: return logger.debug("activate %s", c) if c.is_file(): self.activated.emit(str(c)) else: self._model.setFolder(c)