def __init__(self): QDockWidget.__init__(self, "File Menager") self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) model = QFileSystemModel() model.setRootPath(QDir.currentPath()) tree = QTreeView() tree.setModel(model) self.setWidget(tree)
def init_file_system_tree(self): model = QFileSystemModel(nameFilterDisables=False) model.setRootPath("Desktop") model.setNameFilters(["*.txt", "*.csv"]) self.ui.browserTreeView.setModel(model) self.ui.browserTreeView.setRootIndex(model.index("Desktop")) self.ui.browserTreeView.hideColumn(1) self.ui.browserTreeView.hideColumn(2) self.ui.browserTreeView.hideColumn(3) self.ui.browserTreeView.doubleClicked.connect(self.onClicked)
def open_directory(self, dir): model = QFileSystemModel(self.ui.fileTreeView) model.setNameFilters(["*.jpg", "*.JPG"]) model.setRootPath(dir) self.ui.fileTreeView.setModel(model) self.ui.fileTreeView.setRootIndex(model.index(dir)) self.ui.fileTreeView.header().setStretchLastSection(False) self.ui.fileTreeView.header().setSectionResizeMode(0, QHeaderView.Stretch) self.ui.fileTreeView.selectionModel().selectionChanged.connect(self.current_file_changed) self.ui.fileTreeView.hideColumn(1) self.ui.fileTreeView.hideColumn(2) self.ui.fileTreeView.hideColumn(3) self.ui.fileTreeView.hideColumn(4)
class App(QWidget): '''The FolderMaker base class''' def __init__(self, root_path, conf): super().__init__() self.title = 'FolderMaker' self.root_path = root_path self.conf = conf self.init_ui() def on_btn(self): '''Creates buttons on click''' basedir = ROOT_PATH try: create_dirs( self.conf, basedir, range(int(self.start_box.text()), int(self.stop_box.text()))) except ValueError: msg = QMessageBox() msg.setText('Error! Invalid numbers in text boxes!') msg.exec() except FileExistsError as file_ex: msg = QMessageBox() msg.setText( f'Error! Directory already exists! Exception: {str(file_ex)}') msg.exec() def init_ui(self): '''Initializes the UI''' self.setWindowTitle(self.title) self.model = QFileSystemModel() self.model.setRootPath(ROOT_PATH) self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(self.root_path)) self.start_box = QLineEdit() self.stop_box = QLineEdit() self.start_box.setValidator(QIntValidator()) self.stop_box.setValidator(QIntValidator()) self.make_btn = QPushButton("Create Project Folders") self.make_btn.clicked.connect(self.on_btn) layout = QVBoxLayout() layout.addWidget(self.tree) subgrid = QGridLayout() subgrid.addWidget(self.start_box, 0, 1) subgrid.addWidget(self.stop_box, 1, 1) subgrid.addWidget(QLabel('From (inc.): '), 0, 0) subgrid.addWidget(QLabel('To (not inc.): '), 1, 0) layout.addLayout(subgrid) layout.addWidget(self.make_btn) self.setLayout(layout) self.show()
class FSLineEdit(QLineEdit): """ A line edit with auto completion for file system folders. """ def __init__(self, parent=None): QLineEdit.__init__(self, parent) self.fsmodel = QFileSystemModel() self.fsmodel.setRootPath("") self.completer = QCompleter() self.completer.setModel(self.fsmodel) self.setCompleter(self.completer) self.fsmodel.setFilter(QDir.Drives | QDir.AllDirs | QDir.Hidden | QDir.NoDotAndDotDot) def setPath(self, path): self.setText(path) self.fsmodel.setRootPath(path)
class FileSystemView(QWidget): def __init__(self, dir_path): super().__init__() # appWidth = 800 # appHeight = 300 self.setWindowTitle('File System Viewer') # self.setGeometry(300, 300, appWidth, appHeight) self.model = QFileSystemModel() self.model.setRootPath(dir_path) self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(dir_path)) self.tree.setColumnWidth(0, 250) self.tree.setAlternatingRowColors(True) layout = QVBoxLayout() layout.addWidget(self.tree) self.setLayout(layout)
def sd_path(self, startup, width): """Allows the user to specify the path to their SD card via their OS file explorer dialog. Note, nothing is done to ensure that the location selected is actually an SD card. Currently triggered via a menu action. startup: True if this is being called during startup, False otherwise. width: The width of the main window. """ if not startup: input_dir = QFileDialog.getExistingDirectory( None, "Select an SD Card:", expanduser("~")) if input_dir != "" and os.path.isdir(input_dir): if "/" in input_dir and platform.system().lower() == "windows": # THIS IS NEEDED FOR WINDOWS. # This comes from a bug with QFileDialog returning the # wrong path separator on Windows for some odd reason. input_dir = input_dir.split("/")[0] elif "/" in input_dir: # OSX case. pass else: input_dir = input_dir.split(os.path.sep)[0] self.sd_root = str(input_dir) self.export_dir = os.path.join(self.sd_root, "to_zoia") self.ui.tab_sd.setEnabled(True) else: self.ui.tab_sd.setEnabled(False) self.ui.tabs.setCurrentIndex(1) # Setup the SD card tree view for the SD Card tab. self.ui.statusbar.showMessage("SD card location successfully set.", timeout=5000) model = QFileSystemModel() model.setRootPath(self.sd_root) self.ui.sd_tree.setModel(model) self.ui.sd_tree.setRootIndex(model.setRootPath(self.sd_root)) self.ui.sd_tree.setColumnWidth(0, width // 2) for i in range(1, 4): self.ui.sd_tree.setColumnHidden(i, True)
def model_view(): app = QApplication() splitter = QSplitter() model = QFileSystemModel() model.setRootPath(QDir.currentPath()) parentIndex = model.index(QDir.currentPath()) tree = QTreeView(splitter) tree.setModel(model) tree.setRootIndex(parentIndex) list = QListView(splitter) list.setModel(model) list.setRootIndex(parentIndex) table = QTableView(splitter) table.setModel(model) table.setRootIndex(parentIndex) splitter.setWindowTitle("Two views onto the same file system model") splitter.show() app.exec_()
def __init__(self): QMainWindow.__init__(self) self.setupUi(self) # Viewing the filesystem tree treeModel = QFileSystemModel() treeModel.setRootPath(QDir.currentPath()) # We only show the name/path view = self.treeview_os_directories view.setModel(treeModel) view.model().sort(1, order=Qt.DescendingOrder) view.hideColumn(1) view.hideColumn(2) view.hideColumn(3) view.setColumnWidth(0, 10) view.setColumnWidth(1, 1) view.setColumnWidth(2, 1) # Setting a contextual menu self.treeview_os_directories.customContextMenuRequested.connect( self.openMenuDirectories) # Adding actions self.actionSortie.triggered.connect(self.close) # The selected directories/files (search list) will be stored in a global list global dir_list for dir in dir_list: self.listWidget_selected_directories.addItem(QListWidgetItem(dir))
class TreeView(QWidget): def __init__(self, path=None): super(TreeView, self).__init__() self.model = QFileSystemModel() if path: self.selectedPath = path self.model.setRootPath(self.selectedPath) else: self.selectedPath = QDir.currentPath() self.model.setRootPath(self.selectedPath) mainLayout = QVBoxLayout() mainLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(mainLayout) self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(self.selectedPath)) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) self.tree.setColumnHidden(3, True) mainLayout.addWidget(self.tree) def changePath(self, path): self.selectedPath = path self.tree.setModel(None) self.model.setRootPath(self.selectedPath) self.model.setNameFilters( ["*.png", "*.jpg", "*.bmp", "*.svg", "*.tiff", "*.gif"]) self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(self.selectedPath)) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) self.tree.setColumnHidden(3, True) self.repaint()
def __initFilesSystemModel__(self): model = QFileSystemModel() model.setRootPath(r'C:') model.setReadOnly(True) return model
class MainWindow(QMainWindow): def __init__(self): super().__init__() # SET => App Icon self.icon = QIcon("img/iconXLNK.png") # End self.tree_view = None self.file_system_model = None # SET => Window Icon self.setWindowIcon(self.icon) # End # WSET => Window Title self.setWindowTitle("XLNK | Data Manager") # End # Menus self.menu = self.menuBar() self.file_menu = self.menu.addMenu("&File") self.edit_menu = self.menu.addMenu("&Edit") self.view_menu = self.menu.addMenu("&View") self.help_menu = self.menu.addMenu("&Help") # End # =================== # Menu Button Actions # Exit QAction exit_action = QAction("Exit", self) exit_action.setShortcut(QKeySequence.Quit) exit_action.triggered.connect(self.close) self.file_menu.addAction(exit_action) # End # End # Tool Bar toolbar = QToolBar(self) self.addToolBar(toolbar) # delete action on toolbar delete_action_tb = QAction("DELETE TABLE ROW", self) delete_action_tb.setStatusTip("Obrisi Red U Tabeli") delete_action_tb.triggered.connect(self.delete_table_row_tb) toolbar.addAction(delete_action_tb) # Dock Widget dock_widget = QDockWidget("EXPLORER", self) # File System Model self.file_system_model = QFileSystemModel() self.file_system_model.setRootPath(QDir.currentPath()) # SET => Tree View MOdel self.tree_view = QTreeView() self.tree_view.setModel(self.file_system_model) self.tree_view.setRootIndex( self.file_system_model.index(QDir.currentPath() + "/data")) self.tree_view.clicked.connect(self.file_clicked_handler) dock_widget.setWidget(self.tree_view) dock_widget.setFloating(False) self.addDockWidget(Qt.LeftDockWidgetArea, dock_widget) # QLabel qlabel = QLabel(self) qlabel.setText("Welcome to XLNK.") # Central Widget self.clicked_file = None self.setCentralWidget(qlabel) self.showMaximized() # ToolBar Functions # TODO def delete_table_row_tb(self): print("Ugraditi funkciju za brisanje reda iz tabele.") def file_clicked_handler(self, index): index = self.tree_view.currentIndex() file_clicked_param = os.path.basename( self.file_system_model.filePath(index)) self.clicked_file = file_clicked_param self.status_bar = QStatusBar(self) self.status_bar.showMessage( "File Selected: {}".format(file_clicked_param), 3000) self.setStatusBar(self.status_bar) self.workspace_widget = WorkSpaceWidget(self, self.clicked_file) self.setCentralWidget(self.workspace_widget)
class DownloadDirTreeWidget(QWidget): def __init__(self, root_path) -> None: QWidget.__init__(self) # self.index stores the index of the latest item which is clicked # self.root_path is the path to the folder currently showing self.index = None self.root_path = os.path.abspath(root_path) self.dir_view = QTreeView() self.model = QFileSystemModel(self.dir_view) self.model.setRootPath(self.root_path) self.dir_view.clicked.connect(self.onFileItemClicked) self.dir_view.doubleClicked.connect(self.onFileItemDoubleClicked) self.dir_view.setModel(self.model) self.dir_view.setRootIndex(self.model.index(self.root_path)) open_button = QPushButton("Open") open_button.clicked.connect(self.openFile) open_in_file_explorer_button = QPushButton("Open in File Explorer") open_in_file_explorer_button.clicked.connect(self.openInFileExplorer) self.root_path_line_edit = QLineEdit(self.root_path) self.root_path_line_edit.returnPressed.connect( self.onChangeLineEditReturned) self.root_path_line_edit.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.root_path_line_edit.adjustSize() change_path_button = QPushButton('Change Directory') change_path_button.clicked.connect(self.onChangeButtonClicked) addressCompleter = QCompleter() addressCompleter.setModel(self.model) self.root_path_line_edit.setCompleter(addressCompleter) # Set layout layout = QGridLayout() layout.addWidget(self.root_path_line_edit, 0, 0, 1, 1) layout.addWidget(change_path_button, 0, 1, 1, 1) layout.addWidget(self.dir_view, 1, 0, 1, 2) layout.addWidget(open_button, 2, 0, 1, 1) layout.addWidget(open_in_file_explorer_button, 2, 1, 1, 1) layout.setMargin(0) self.setLayout(layout) def setRootPath(self, root_path): self.root_path = os.path.abspath(root_path) def openFile(self): if self.index is not None: file_path = self.model.filePath(self.index).replace('/', '\\') is_dir = self.model.isDir(self.index) # If is file, open with default program # If is directory, open with file explorer if is_dir is False: os.startfile(file_path, 'open') else: subprocess.run(['explorer', file_path]) def openInFileExplorer(self): if self.index is None: file_path = self.model.filePath(self.index).replace('/', '\\') subprocess.run(['explorer', '/select,', file_path]) def onFileItemClicked(self, index): # When clicked, resize and update self.index self.dir_view.resizeColumnToContents(0) self.index = index def onFileItemDoubleClicked(self, index): # When double clicked, update self.index and open the file directly self.index = index if self.sender().model().isDir(index) is False: self.openFile() def onChangeButtonClicked(self): new_path = QFileDialog.getExistingDirectory(self, 'Change Directory', self.root_path) self.changeRootPath(new_path) def onChangeLineEditReturned(self): new_path = self.root_path_line_edit.text() if os.path.isdir(new_path): self.changeRootPath(new_path) else: subprocess.run(['explorer', new_path]) self.root_path_line_edit.setText(self.root_path) def changeRootPath(self, new_path: str): if os.path.exists(new_path): self.root_path = os.path.abspath(new_path) self.dir_view.setRootIndex(self.model.index(self.root_path)) self.root_path_line_edit.setText(self.root_path)
def init_ui(self): self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) # layout root of application main_layout = QVBoxLayout(self) self.setLayout(main_layout) # to set the model of tree model = QFileSystemModel() model.setRootPath("/home/denison/Downloads/music") model.setNameFilters(['*.mp3', '*.m4a', '*.flac']) model.setNameFilterDisables(False) self.tree = QTreeView() self.tree.setModel(model) self.tree.setAnimated(True) self.tree.setColumnWidth(0, 500) file_layout = QHBoxLayout() label_file = QLabel('file/directory') text_file = QLineEdit() btn_load = QPushButton('load') file_layout.addWidget(label_file) file_layout.addWidget(text_file) file_layout.addWidget(btn_load) grid_info_layout = QGridLayout() # strings to labels self.labels = [ 'ARTIST', 'ALBUMARTIST', 'ALBUM', 'TITLE', 'GENRE', 'DATE' ] # line edits to tags self.text_artist = QLineEdit('ARTIST') self.text_album = QLineEdit('ALBUM') self.text_album_artist = QLineEdit('ALBUMARTIST') self.text_title = QLineEdit('TITLE') self.text_genre = QLineEdit('GENRE') self.text_date = QLineEdit('DATE') self.text_tags = [ self.text_artist, self.text_album_artist, self.text_album, self.text_title, self.text_genre, self.text_date ] for text in self.text_tags: text.setEnabled(False) #text.textChanged.connect(self.enable_save) # labels for label, i in zip(self.labels, range(6)): grid_info_layout.addWidget(QLabel(label), i, 0) # cb_artist = QCheckBox() # cb_album_artist = QCheckBox() # cb_album = QCheckBox() # cb_title = QCheckBox() # cb_genre = QCheckBox() # cb_date = QCheckBox() # self.checkboxes = [ # cb_artist, cb_album_artist, cb_album, # cb_title, cb_genre, cb_date # ] # for cb in self.checkboxes: # cb.setText('editar') # cb_artist.stateChanged.connect(lambda: self.enable_tag_edit(self.text_artist)) # cb_album_artist.stateChanged.connect(lambda: self.enable_tag_edit(self.text_album_artist)) # cb_album.stateChanged.connect(lambda: self.enable_tag_edit(self.text_album)) # cb_title.stateChanged.connect(lambda: self.enable_tag_edit(self.text_title)) # cb_genre.stateChanged.connect(lambda: self.enable_tag_edit(self.text_genre)) # cb_date.stateChanged.connect(lambda: self.enable_tag_edit(self.text_date)) for i, text in zip(range(6), self.text_tags): grid_info_layout.addWidget(text, i, 1) # for cb, i in zip(self.checkboxes, range(6)) : # grid_info_layout.addWidget(cb, i, 2) action_layout = QHBoxLayout() btn_exit = QPushButton('Exit') self.btn_save = QPushButton('save changes') self.btn_save.setDisabled(True) action_layout.addWidget(btn_exit) action_layout.addWidget(self.btn_save) #main_layout.addLayout(file_layout) main_layout.addWidget(self.tree) main_layout.addLayout(grid_info_layout) main_layout.addLayout(action_layout) btn_load.clicked.connect(self.open_file) btn_exit.clicked.connect(self.close_application) self.btn_save.clicked.connect(self.edit_tags) self.tree.doubleClicked.connect(self.get_selected_file) self.show()
class Dock(QDockWidget): def __init__(self, title, central_widget, parent=None): super().__init__(title, parent=parent) self.central_widget = central_widget self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) self.tree = QTreeView() self.tree.pressed.connect(self.setIndex) self.index_ = None self.db_tree = QTreeView() self.db_tree.setAnimated(True) self.db_model = QStandardItemModel() self.db_model.setHorizontalHeaderLabels(["Database"]) self.db_root = self.db_model.invisibleRootItem() self.dbs = [] def contextMenuEvent(self, event): contextMenu = QMenu(self) deleteFile = contextMenu.addAction("Delete File") action = contextMenu.exec_(self.mapToGlobal(event.pos())) if action == deleteFile: alert = QMessageBox() alert.setWindowTitle("Action Dialog") alert.setText("Are you sure you want to delete this file?") alert.setStandardButtons(QMessageBox.No | QMessageBox.Yes) alert.setDefaultButton(QMessageBox.No) response = alert.exec_() if response == QMessageBox.No: contextMenu.close() else: file_name = self.model.filePath( self.index_).split("storage/")[1] os.remove(self.model.filePath(self.index_)) os.remove( self.model.filePath(self.index_).split("/storage")[0] + "/meta/" + file_name + "_metadata.json") contextMenu.close() def setIndex(self, index): self.index_ = index def tree_init(self): self.tree.setModel(self.model) self.tree.setRootIndex( self.model.index(QDir.currentPath() + "/model/storage")) self.tree.clicked.connect(self.file_clicked) self.setWidget(self.tree) def init_db_tree(self): self.clear_tree() self.db_tree.setModel(self.db_model) self.db_tree.clicked.connect(self.table_clicked) self.setWidget(self.db_tree) self.connected_dbs() def file_clicked(self, index): file_path = self.model.filePath(index) workspace = Workspace(file_path, self.central_widget) self.central_widget.add_tab( workspace, QIcon("view/images/dark/baseline_notes_black_48dp.png"), file_path.split("storage/")[1], ) def connected_dbs(self): if os.path.exists("model/session/connected_dbs") and os.path.getsize( "model/session/connected_dbs") > 0: self.clear_tree() self.dbs = [] with open("model/session/connected_dbs", "rb") as sessions: db_sessions = pickle.load(sessions) for db in db_sessions: connection = mysql.connect( host=db["host"], user=db["user"], password=db["password"], db=db["db"], charset="utf8mb4", cursorclass=mysql.cursors.DictCursor) temp_db = StandardItem(db["db"], 10, is_bold=True) self.dbs.append(db["db"]) try: with connection.cursor() as cursor: cursor.execute("SHOW TABLES") db_tables = cursor.fetchall() for table in db_tables: for key in table.keys(): temp_table = StandardItem(table[key], 9) temp_db.appendRow(temp_table) finally: connection.close() self.db_root.appendRow(temp_db) else: self.clear_tree() self.dbs = [] no_db = StandardItem("No Connected Databases", 10, is_bold=True) self.db_root.appendRow(no_db) def table_clicked(self, val): self.is_db = False if os.path.exists("model/session/connected_dbs") and len( self.dbs) != 0: for db in self.dbs: if db == val.data(): self.is_db = True remove_choice = QMessageBox.question( self.db_tree, "Disconnect Database", f'Do you want to remove "{val.data()}" from connected databases?', QMessageBox.Yes | QMessageBox.No) if remove_choice == QMessageBox.Yes: with open("model/session/connected_dbs", "rb") as sessions: db_sessions = pickle.load(sessions) db_sessions[:] = [ db for db in db_sessions if db.get('db') != val.data() ] for db in db_sessions: if db["index"] != 1: db["index"] -= 1 self.dbs[:] = [ db for db in self.dbs if db != val.data() ] if len(db_sessions) == 0: os.remove("model/session/connected_dbs") else: with open("model/session/connected_dbs", "wb") as sessions: pickle.dump(db_sessions, sessions) QMessageBox.information( self.db_tree, "(㇏(•̀ᵥᵥ•́)ノ)", f'Database "{val.data()}" successfully disconnected.', QMessageBox.Ok) self.connected_dbs() break if remove_choice == QMessageBox.No: break if not self.is_db: user_reply = QMessageBox.question( self.db_tree, "Answer. Thanks.", f'Do you want to open the "{val.data()}" table?', QMessageBox.Open | QMessageBox.Cancel) if user_reply == QMessageBox.Cancel: pass if user_reply == QMessageBox.Open: workspace = DBWorkspace(val.parent().data(), val.data(), self.central_widget) self.central_widget.add_tab( workspace, QIcon("view/images/menubar/database-connect.png"), val.data(), ) def clear_tree(self): self.db_model.clear() self.db_model.setHorizontalHeaderLabels(["Database"]) self.db_root = self.db_model.invisibleRootItem()
class FileBrowser(QObject): file_selected = Signal(str) file_activated = Signal(str) def __init__(self, app, window): QObject.__init__(self) self.app = app self.view = window.file_tree self.show_hidden_chk = window.show_hidden self.name_filter_combo = window.name_filter self.model = QFileSystemModel(self.view) self.icon_provider = FileIconProvider() if app.args.root: self.model.setRootPath(app.args.root) self.current_path = app.args.root else: self.model.setRootPath("") self.current_path = os.path.realpath(os.curdir) self.model.setIconProvider(self.icon_provider) self.view.setModel(self.model) self.view.sortByColumn(0, Qt.AscendingOrder) self.view.setSortingEnabled(True) index = self.model.index(self.current_path) if app.args.root: self.view.setRootIndex(index) self.view.setExpanded(index, True) self.view.setCurrentIndex(index) self.view.setDragDropMode(QAbstractItemView.DragDropMode.DragOnly) self.view.setSelectionMode(QAbstractItemView.ExtendedSelection) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.add_name_filters() self.apply_show_hidden() self.apply_name_filters() self.model.setNameFilterDisables(False) self.model.directoryLoaded.connect(self.directory_loaded) self.model.dataChanged.connect(self.data_changed) selection_model = self.view.selectionModel() selection_model.selectionChanged.connect(self.selection_changed) self.show_hidden_chk.stateChanged.connect(self.apply_show_hidden) self.name_filter_combo.currentIndexChanged.connect( self.apply_name_filters) self.view.doubleClicked.connect(self.double_clicked) def add_name_filters(self): for name, filters in NAME_FILTERS: label = "{} ({})".format(name, ", ".join(filters)) self.name_filter_combo.addItem(label, filters) self.name_filter_combo.setCurrentIndex(0) @Slot() def apply_show_hidden(self): show = self.show_hidden_chk.checkState() logging.debug("apply_show_hidden(): %r", show) flags = QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot if show: flags |= QDir.Hidden self.model.setFilter(flags) QTimer.singleShot(100, self.scroll_to_current) @Slot() def apply_name_filters(self): filters = self.name_filter_combo.currentData() self.model.setNameFilters(filters) QTimer.singleShot(100, self.scroll_to_current) @Slot(str) def directory_loaded(self, path): logger.debug("directory loaded: %s", path) if path == self.current_path: logger.debug("requesting scrolling") QTimer.singleShot(100, self.scroll_to_current) @Slot() def data_changed(self, *args): logger.debug("Data changed: %r", args) @Slot() def scroll_to_current(self): index = self.model.index(self.current_path) self.view.scrollTo(index) self.view.resizeColumnToContents(0) @Slot(QItemSelection) def selection_changed(self, selection): indexes = selection.indexes() if indexes: index = indexes[0] path = self.model.filePath(index) if os.path.isfile(path): self.file_selected.emit(path) self.current_path = path @Slot(QModelIndex) def double_clicked(self, index): path = self.model.filePath(index) if os.path.isfile(path): self.file_activated.emit(path)
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 FileSystemWidget(QWidget): def __init__(self, parent, *args, **kwargs): super().__init__(*args, **kwargs) self.currentRootPath = '/' self.currentPath = QDir.currentPath() self.mainWindow = parent self.chooseDirAction = QAction(IconFactory.getIcon('folder'), 'Root directory', self, statusTip="Change root directory", triggered=self.chooseRootDir) self.showOFAction = QAction(IconFactory.getIcon('filter_alt'), 'Show only FITS files', self, statusTip="Show only FITS/all files", triggered=self.showOFFiles) self.showOFAction.setCheckable(True) self.showOFAction.toggled.connect(self.showOFFiles) self.chooseDirBtn = QToolButton() self.chooseDirBtn.setDefaultAction(self.chooseDirAction) self.showOFBtn = QToolButton() self.showOFBtn.setDefaultAction(self.showOFAction) iconlayout = QHBoxLayout() iconlayout.setAlignment(Qt.AlignLeft) iconlayout.addWidget(self.chooseDirBtn) iconlayout.addWidget(self.showOFBtn) self.viewsSplitter = QSplitter(Qt.Horizontal) self.viewsSplitter.splitterMoved.connect(self.splitterMoved) self.dirsModel = QFileSystemModel(self) self.dirsModel.setOption(QFileSystemModel.DontWatchForChanges, True) self.dirsModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.dirsModel.setNameFilterDisables(False) self.dirs = QTreeView() self.dirs.setModel(self.dirsModel) self.dirs.hideColumn(1) self.dirs.hideColumn(2) self.dirs.hideColumn(3) self.dirs.clicked.connect(self.onDirsClick) self.dirs.doubleClicked.connect(self.onDirsDoubleClick) self.filesModel = QFileSystemModel(self) self.filesModel.setOption(QFileSystemModel.DontWatchForChanges, True) self.filesModel.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.filesModel.setNameFilterDisables(False) self.files = QListView() self.files.setModel(self.filesModel) self.files.doubleClicked.connect(self.onFilesDoubleClick) self.viewsSplitter.addWidget(self.dirs) self.viewsSplitter.addWidget(self.files) viewslayout = QHBoxLayout() viewslayout.addWidget(self.viewsSplitter) layout = QVBoxLayout() layout.addLayout(iconlayout) layout.addLayout(viewslayout) self.setLayout(layout) self.dirsModel.setRootPath(self.currentRootPath) self.dirs.setRootIndex(self.dirsModel.index(self.currentRootPath)) index = self.dirsModel.index(self.currentPath) self.dirs.setCurrentIndex(index) self.dirs.setExpanded(index, True) self.filesModel.setRootPath(self.currentPath) self.files.setRootIndex(self.filesModel.index(self.currentPath)) def splitterMoved(self, pos, index): if pos == 0: self.filesModel.setFilter(QDir.NoDot | QDir.AllEntries | QDir.DirsFirst | QDir.Type) elif pos == self.viewsSplitter.width( ) - self.viewsSplitter.handleWidth(): self.dirsModel.setFilter(QDir.NoDotAndDotDot | QDir.AllEntries) else: self.dirsModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.filesModel.setFilter(QDir.NoDotAndDotDot | QDir.Files) def onDirsClick(self, item): index = self.dirs.selectedIndexes()[0] info = self.dirsModel.fileInfo(index) if info.isDir(): self.currentPath = info.filePath() self.files.setRootIndex( self.filesModel.setRootPath(info.filePath())) def onDirsDoubleClick(self, item): index = self.dirs.selectedIndexes()[0] info = self.dirsModel.fileInfo(index) if info.isDir(): self.currentPath = info.filePath() self.files.setRootIndex( self.filesModel.setRootPath(info.filePath())) else: self.mainWindow.open_fits(info.filePath()) def onFilesDoubleClick(self, item): index = self.files.selectedIndexes()[0] info = self.filesModel.fileInfo(index) if info.isDir(): self.setPath(info.filePath()) else: try: self.mainWindow.open_fits(info.filePath()) except FileNotFoundError: self.setPath(self.currentPath) # refesh maybe? def setPath(self, path): self.currentPath = path index = self.dirsModel.index(self.currentPath) self.dirs.setCurrentIndex(index) self.dirs.setExpanded(index, True) self.files.setRootIndex(self.filesModel.setRootPath(self.currentPath)) def chooseRootDir(self): dir = QFileDialog.getExistingDirectory(self, 'Select directory') if dir: self.setRootPath(dir) def setRootPath(self, dir): self.currentRootPath = dir self.dirsModel.setRootPath(self.currentRootPath) self.dirs.setRootIndex(self.dirsModel.index(self.currentRootPath)) self.setPath(self.currentRootPath) def showOFFiles(self): if self.showOFAction.isChecked(): self.dirsModel.setNameFilters(["*.FITS", "*.fits"]) self.filesModel.setNameFilters(["*.FITS", "*.fits"]) else: self.dirsModel.setNameFilters(["*"]) self.filesModel.setNameFilters(["*"]) def writeSettings(self, settings): settings.beginGroup("fileWidget") settings.setValue('splitterGeometry', self.viewsSplitter.saveGeometry()) settings.setValue('splitterState', self.viewsSplitter.saveState()) settings.setValue('rootPath', self.currentRootPath) settings.setValue('path', self.currentPath) settings.endGroup() def readSettings(self, settings): settings.beginGroup("fileWidget") self.viewsSplitter.restoreGeometry(settings.value("splitterGeometry")) self.viewsSplitter.restoreState(settings.value("splitterState")) rootPath = settings.value("rootPath") path = settings.value("path") settings.endGroup() if rootPath is None: rootPath = '/' self.setRootPath(rootPath) if path is None: path = QDir.currentPath() self.setPath(path) self.splitterMoved(self.viewsSplitter.handle(1).pos().x(), 0)
class TestController(Window): """Contains code for the window that the user initially sees""" def __init__(self): if not path.exists(algorithm_directory): os.makedirs(algorithm_directory, exist_ok=True) self.fmodel = QFileSystemModel() self.fmodel.setRootPath(algorithm_directory) self.module_list = QTreeView() self.module_list.setModel(self.fmodel) self.module_list.setRootIndex(self.fmodel.index(algorithm_directory)) self.module_button = QPushButton("Change Directory") self.module_button.clicked.connect(self.change_dir) self.start_date = ToggleButton('Start Date') self.end_date = ToggleButton('End Date', 'Default (Present)') self.test_types = ['Profit', 'Accuracy'] self.test_type = QComboBox() self.test_type.addItems(self.test_types) self.test_output = QTextEdit() self.test_output.setDisabled(True) self.run_btn = QPushButton('Run Test') self.profit = QLCDNumber() self.accuracy = QLCDNumber() super().__init__('Jencks Stock Algorithm Tester') def setup_left_column(self): self.left.addWidget(QLabel("Test Files")) self.left.addWidget(self.module_list) self.left.addWidget(self.module_button) def setup_center_column(self): hbox = QHBoxLayout() hbox.addLayout(self.start_date.box) hbox.addLayout(self.end_date.box) self.center.addLayout(hbox) self.center.addWidget(QLabel('Test Type')) self.center.addWidget(self.test_type) self.center.addWidget(QLabel('Test Run Output')) self.center.addWidget(self.test_output) self.center.addWidget(self.run_btn) def setup_right_column(self): self.right.addWidget(QLabel('Test Diagnostics')) self.right.addWidget(QLabel('Profit')) self.right.addWidget(self.profit) self.right.addWidget(QLabel('Accuracy')) self.right.addWidget(self.accuracy) def setup_menus(self): super().setup_menus() self.menu_entries += [(self.edit_menu, 'Preferences', self.open_preferences, 'Ctrl+Alt+P')] @Slot() def open_preferences(self, checked): print('Opening preference menu.') @Slot() def change_dir(self, checked): dialog = QFileDialog() fdir = dialog.getExistingDirectory() self.fmodel.setRootPath(fdir) self.module_list.setRootIndex(self.fmodel.index(fdir))
import sys from PySide2.QtWidgets import QApplication, QSplitter, QFileSystemModel, QTreeView, QListView from PySide2.QtCore import QDir if __name__ == '__main__': app = QApplication(sys.argv) splitter = QSplitter() model = QFileSystemModel() model.setRootPath("/") tree = QTreeView(splitter) tree.setModel(model) tree.setRootIndex(model.index("/")) list = QListView(splitter) list.setModel(model) list.setRootIndex(model.index("/")) splitter.setWindowTitle( "A model with two views or two views with one model") splitter.show() app.exec_()
class Snippets(QDialog): def __init__(self, context, parent=None): super(Snippets, self).__init__(parent) # Create widgets self.setWindowModality(Qt.ApplicationModal) self.title = QLabel(self.tr("Snippet Editor")) self.saveButton = QPushButton(self.tr("&Save")) self.saveButton.setShortcut(QKeySequence(self.tr("Ctrl+S"))) self.runButton = QPushButton(self.tr("&Run")) self.runButton.setShortcut(QKeySequence(self.tr("Ctrl+R"))) self.closeButton = QPushButton(self.tr("Close")) self.clearHotkeyButton = QPushButton(self.tr("Clear Hotkey")) self.setWindowTitle(self.title.text()) #self.newFolderButton = QPushButton("New Folder") self.browseButton = QPushButton("Browse Snippets") self.browseButton.setIcon(QIcon.fromTheme("edit-undo")) self.deleteSnippetButton = QPushButton("Delete") self.newSnippetButton = QPushButton("New Snippet") self.edit = QCodeEditor(HIGHLIGHT_CURRENT_LINE=False, SyntaxHighlighter=PythonHighlighter) self.edit.setPlaceholderText("python code") self.resetting = False self.columns = 3 self.context = context self.keySequenceEdit = QKeySequenceEdit(self) self.currentHotkey = QKeySequence() self.currentHotkeyLabel = QLabel("") self.currentFileLabel = QLabel() self.currentFile = "" self.snippetDescription = QLineEdit() self.snippetDescription.setPlaceholderText("optional description") #Set Editbox Size font = getMonospaceFont(self) self.edit.setFont(font) font = QFontMetrics(font) self.edit.setTabStopWidth(4 * font.width(' ')); #TODO, replace with settings API #Files self.files = QFileSystemModel() self.files.setRootPath(snippetPath) self.files.setNameFilters(["*.py"]) #Tree self.tree = QTreeView() self.tree.setModel(self.files) self.tree.setSortingEnabled(True) self.tree.hideColumn(2) self.tree.sortByColumn(0, Qt.AscendingOrder) self.tree.setRootIndex(self.files.index(snippetPath)) for x in range(self.columns): #self.tree.resizeColumnToContents(x) self.tree.header().setSectionResizeMode(x, QHeaderView.ResizeToContents) treeLayout = QVBoxLayout() treeLayout.addWidget(self.tree) treeButtons = QHBoxLayout() #treeButtons.addWidget(self.newFolderButton) treeButtons.addWidget(self.browseButton) treeButtons.addWidget(self.newSnippetButton) treeButtons.addWidget(self.deleteSnippetButton) treeLayout.addLayout(treeButtons) treeWidget = QWidget() treeWidget.setLayout(treeLayout) # Create layout and add widgets buttons = QHBoxLayout() buttons.addWidget(self.clearHotkeyButton) buttons.addWidget(self.keySequenceEdit) buttons.addWidget(self.currentHotkeyLabel) buttons.addWidget(self.closeButton) buttons.addWidget(self.runButton) buttons.addWidget(self.saveButton) description = QHBoxLayout() description.addWidget(QLabel(self.tr("Description: "))) description.addWidget(self.snippetDescription) vlayoutWidget = QWidget() vlayout = QVBoxLayout() vlayout.addLayout(description) vlayout.addWidget(self.edit) vlayout.addLayout(buttons) vlayoutWidget.setLayout(vlayout) hsplitter = QSplitter() hsplitter.addWidget(treeWidget) hsplitter.addWidget(vlayoutWidget) hlayout = QHBoxLayout() hlayout.addWidget(hsplitter) self.showNormal() #Fixes bug that maximized windows are "stuck" #Because you can't trust QT to do the right thing here if (sys.platform == "darwin"): self.settings = QSettings("Vector35", "Snippet Editor") else: self.settings = QSettings("Vector 35", "Snippet Editor") if self.settings.contains("ui/snippeteditor/geometry"): self.restoreGeometry(self.settings.value("ui/snippeteditor/geometry")) else: self.edit.setMinimumWidth(80 * font.averageCharWidth()) self.edit.setMinimumHeight(30 * font.lineSpacing()) # Set dialog layout self.setLayout(hlayout) # Add signals self.saveButton.clicked.connect(self.save) self.closeButton.clicked.connect(self.close) self.runButton.clicked.connect(self.run) self.clearHotkeyButton.clicked.connect(self.clearHotkey) self.tree.selectionModel().selectionChanged.connect(self.selectFile) self.newSnippetButton.clicked.connect(self.newFileDialog) self.deleteSnippetButton.clicked.connect(self.deleteSnippet) #self.newFolderButton.clicked.connect(self.newFolder) self.browseButton.clicked.connect(self.browseSnippets) if self.settings.contains("ui/snippeteditor/selected"): selectedName = self.settings.value("ui/snippeteditor/selected") self.tree.selectionModel().select(self.files.index(selectedName), QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) if self.tree.selectionModel().hasSelection(): self.selectFile(self.tree.selectionModel().selection(), None) self.edit.setFocus() cursor = self.edit.textCursor() cursor.setPosition(self.edit.document().characterCount()-1) self.edit.setTextCursor(cursor) else: self.readOnly(True) else: self.readOnly(True) @staticmethod def registerAllSnippets(): for action in list(filter(lambda x: x.startswith("Snippets\\"), UIAction.getAllRegisteredActions())): if action == "Snippets\\Snippet Editor...": continue UIActionHandler.globalActions().unbindAction(action) Menu.mainMenu("Tools").removeAction(action) UIAction.unregisterAction(action) for snippet in includeWalk(snippetPath, ".py"): snippetKeys = None (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(snippet) actionText = actionFromSnippet(snippet, snippetDescription) if snippetCode: if snippetKeys == None: UIAction.registerAction(actionText) else: UIAction.registerAction(actionText, snippetKeys) UIActionHandler.globalActions().bindAction(actionText, UIAction(makeSnippetFunction(snippetCode))) Menu.mainMenu("Tools").addAction(actionText, "Snippets") def clearSelection(self): self.keySequenceEdit.clear() self.currentHotkey = QKeySequence() self.currentHotkeyLabel.setText("") self.currentFileLabel.setText("") self.snippetDescription.setText("") self.edit.clear() self.tree.clearSelection() self.currentFile = "" def reject(self): self.settings.setValue("ui/snippeteditor/geometry", self.saveGeometry()) if self.snippetChanged(): question = QMessageBox.question(self, self.tr("Discard"), self.tr("You have unsaved changes, quit anyway?")) if question != QMessageBox.StandardButton.Yes: return self.accept() def browseSnippets(self): url = QUrl.fromLocalFile(snippetPath) QDesktopServices.openUrl(url); def newFolder(self): (folderName, ok) = QInputDialog.getText(self, self.tr("Folder Name"), self.tr("Folder Name: ")) if ok and folderName: index = self.tree.selectionModel().currentIndex() selection = self.files.filePath(index) if QFileInfo(selection).isDir(): QDir(selection).mkdir(folderName) else: QDir(snippetPath).mkdir(folderName) def selectFile(self, new, old): if (self.resetting): self.resetting = False return if len(new.indexes()) == 0: self.clearSelection() self.currentFile = "" self.readOnly(True) return newSelection = self.files.filePath(new.indexes()[0]) self.settings.setValue("ui/snippeteditor/selected", newSelection) if QFileInfo(newSelection).isDir(): self.readOnly(True) self.clearSelection() self.currentFile = "" return if old and old.length() > 0: oldSelection = self.files.filePath(old.indexes()[0]) if not QFileInfo(oldSelection).isDir() and self.snippetChanged(): question = QMessageBox.question(self, self.tr("Discard"), self.tr("Snippet changed. Discard changes?")) if question != QMessageBox.StandardButton.Yes: self.resetting = True self.tree.selectionModel().select(old, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) return False self.currentFile = newSelection self.loadSnippet() def loadSnippet(self): self.currentFileLabel.setText(QFileInfo(self.currentFile).baseName()) (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile) self.snippetDescription.setText(snippetDescription) if snippetDescription else self.snippetDescription.setText("") self.keySequenceEdit.setKeySequence(snippetKeys) if snippetKeys else self.keySequenceEdit.setKeySequence(QKeySequence("")) self.edit.setPlainText(snippetCode) if snippetCode else self.edit.setPlainText("") self.readOnly(False) def newFileDialog(self): (snippetName, ok) = QInputDialog.getText(self, self.tr("Snippet Name"), self.tr("Snippet Name: ")) if ok and snippetName: if not snippetName.endswith(".py"): snippetName += ".py" index = self.tree.selectionModel().currentIndex() selection = self.files.filePath(index) if QFileInfo(selection).isDir(): path = os.path.join(selection, snippetName) else: path = os.path.join(snippetPath, snippetName) self.readOnly(False) open(path, "w").close() self.tree.setCurrentIndex(self.files.index(path)) log_debug("Snippet %s created." % snippetName) def readOnly(self, flag): self.keySequenceEdit.setEnabled(not flag) self.snippetDescription.setReadOnly(flag) self.edit.setReadOnly(flag) if flag: self.snippetDescription.setDisabled(True) self.edit.setDisabled(True) else: self.snippetDescription.setEnabled(True) self.edit.setEnabled(True) def deleteSnippet(self): selection = self.tree.selectedIndexes()[::self.columns][0] #treeview returns each selected element in the row snippetName = self.files.fileName(selection) question = QMessageBox.question(self, self.tr("Confirm"), self.tr("Confirm deletion: ") + snippetName) if (question == QMessageBox.StandardButton.Yes): log_debug("Deleting snippet %s." % snippetName) self.clearSelection() self.files.remove(selection) self.registerAllSnippets() def snippetChanged(self): if (self.currentFile == "" or QFileInfo(self.currentFile).isDir()): return False (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile) if snippetKeys == None and not self.keySequenceEdit.keySequence().isEmpty(): return True if snippetKeys != None and snippetKeys != self.keySequenceEdit.keySequence().toString(): return True return self.edit.toPlainText() != snippetCode or \ self.snippetDescription.text() != snippetDescription def save(self): log_debug("Saving snippet %s" % self.currentFile) outputSnippet = codecs.open(self.currentFile, "w", "utf-8") outputSnippet.write("#" + self.snippetDescription.text() + "\n") outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n") outputSnippet.write(self.edit.toPlainText()) outputSnippet.close() self.registerAllSnippets() def run(self): if self.context == None: log_warn("Cannot run snippets outside of the UI at this time.") return if self.snippetChanged(): question = QMessageBox.question(self, self.tr("Confirm"), self.tr("You have unsaved changes, must save first. Save?")) if (question == QMessageBox.StandardButton.No): return else: self.save() actionText = actionFromSnippet(self.currentFile, self.snippetDescription.text()) UIActionHandler.globalActions().executeAction(actionText, self.context) log_debug("Saving snippet %s" % self.currentFile) outputSnippet = codecs.open(self.currentFile, "w", "utf-8") outputSnippet.write("#" + self.snippetDescription.text() + "\n") outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n") outputSnippet.write(self.edit.toPlainText()) outputSnippet.close() self.registerAllSnippets() def clearHotkey(self): self.keySequenceEdit.clear()
class Snippets(QDialog): def __init__(self, parent=None): super(Snippets, self).__init__(parent) # Create widgets self.setWindowModality(Qt.NonModal) self.title = QLabel(self.tr("Snippet Editor")) self.saveButton = QPushButton(self.tr("Save")) self.revertButton = QPushButton(self.tr("Revert")) self.clearHotkeyButton = QPushButton(self.tr("Clear Hotkey")) self.setWindowTitle(self.title.text()) self.newFolderButton = QPushButton("New Folder") self.deleteSnippetButton = QPushButton("Delete") self.newSnippetButton = QPushButton("New Snippet") self.edit = QPlainTextEdit() self.resetting = False self.columns = 3 self.keySequenceEdit = QKeySequenceEdit(self) self.currentHotkey = QKeySequence() self.currentHotkeyLabel = QLabel("") self.currentFileLabel = QLabel() self.currentFile = "" self.snippetDescription = QLineEdit() self.snippetEditsPending = False self.clearSelection() #Set Editbox Size font = getMonospaceFont(self) self.edit.setFont(font) font = QFontMetrics(font) self.edit.setTabStopWidth(4 * font.width(' ')); #TODO, replace with settings API #Files self.files = QFileSystemModel() self.files.setRootPath(snippetPath) self.files.setNameFilters(["*.py"]) #Tree self.tree = QTreeView() self.tree.setModel(self.files) self.tree.setSortingEnabled(True) self.tree.hideColumn(2) self.tree.sortByColumn(0, Qt.AscendingOrder) self.tree.setRootIndex(self.files.index(snippetPath)) for x in range(self.columns): #self.tree.resizeColumnToContents(x) self.tree.header().setSectionResizeMode(x, QHeaderView.ResizeToContents) treeLayout = QVBoxLayout() treeLayout.addWidget(self.tree) treeButtons = QHBoxLayout() treeButtons.addWidget(self.newFolderButton) treeButtons.addWidget(self.newSnippetButton) treeButtons.addWidget(self.deleteSnippetButton) treeLayout.addLayout(treeButtons) treeWidget = QWidget() treeWidget.setLayout(treeLayout) # Create layout and add widgets buttons = QHBoxLayout() buttons.addWidget(self.clearHotkeyButton) buttons.addWidget(self.keySequenceEdit) buttons.addWidget(self.currentHotkeyLabel) buttons.addWidget(self.revertButton) buttons.addWidget(self.saveButton) description = QHBoxLayout() description.addWidget(QLabel(self.tr("Description: "))) description.addWidget(self.snippetDescription) vlayoutWidget = QWidget() vlayout = QVBoxLayout() vlayout.addWidget(self.currentFileLabel) vlayout.addWidget(self.edit) vlayout.addLayout(description) vlayout.addLayout(buttons) vlayoutWidget.setLayout(vlayout) hsplitter = QSplitter() hsplitter.addWidget(treeWidget) hsplitter.addWidget(vlayoutWidget) hlayout = QHBoxLayout() hlayout.addWidget(hsplitter) self.showNormal() #Fixes bug that maximized windows are "stuck" self.settings = QSettings("Vector 35", "Snippet Editor") if self.settings.contains("ui/snippeteditor/geometry"): self.restoreGeometry(self.settings.value("ui/snippeteditor/geometry")) else: self.edit.setMinimumWidth(80 * font.averageCharWidth()) self.edit.setMinimumHeight(30 * font.lineSpacing()) # Set dialog layout self.setLayout(hlayout) # Add signals self.saveButton.clicked.connect(self.save) self.revertButton.clicked.connect(self.loadSnippet) self.clearHotkeyButton.clicked.connect(self.clearHotkey) self.tree.selectionModel().selectionChanged.connect(self.selectFile) self.newSnippetButton.clicked.connect(self.newFileDialog) self.deleteSnippetButton.clicked.connect(self.deleteSnippet) self.newFolderButton.clicked.connect(self.newFolder) def registerAllSnippets(self): for action in list(filter(lambda x: x.startswith("Snippet\\"), UIAction.getAllRegisteredActions())): UIActionHandler.globalActions().unbindAction(action) UIAction.unregisterAction(action) for snippet in includeWalk(snippetPath, ".py"): (snippetDescription, snippetKey, snippetCode) = loadSnippetFromFile(snippet) if not snippetDescription: actionText = "Snippet\\" + snippet else: actionText = "Snippet\\" + snippetDescription UIAction.registerAction(actionText, snippetKey) UIActionHandler.globalActions().bindAction(actionText, UIAction(makeSnippetFunction(snippetCode))) def clearSelection(self): self.keySequenceEdit.clear() self.currentHotkey = QKeySequence() self.currentHotkeyLabel.setText("") self.currentFileLabel.setText("") self.snippetDescription.setText("") self.edit.setPlainText("") def reject(self): self.settings.setValue("ui/snippeteditor/geometry", self.saveGeometry()) if self.snippetChanged(): question = QMessageBox.question(self, self.tr("Discard"), self.tr("You have unsaved changes, quit anyway?")) if question != QMessageBox.StandardButton.Yes: return self.accept() def newFolder(self): (folderName, ok) = QInputDialog.getText(self, self.tr("Folder Name"), self.tr("Folder Name: ")) if ok and folderName: index = self.tree.selectionModel().currentIndex() selection = self.files.filePath(index) if QFileInfo(selection).isDir(): QDir(selection).mkdir(folderName) else: QDir(snippetPath).mkdir(folderName) def selectFile(self, new, old): if (self.resetting): self.resetting = False return newSelection = self.files.filePath(new.indexes()[0]) if QFileInfo(newSelection).isDir(): self.clearSelection() return if old.length() > 0: oldSelection = self.files.filePath(old.indexes()[0]) if not QFileInfo(oldSelection).isDir() and self.snippetChanged(): question = QMessageBox.question(self, self.tr("Discard"), self.tr("Snippet changed. Discard changes?")) if question != QMessageBox.StandardButton.Yes: self.resetting = True self.tree.selectionModel().select(old, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) return False self.currentFile = newSelection self.loadSnippet() def loadSnippet(self): self.currentFileLabel.setText(QFileInfo(self.currentFile).baseName()) log_debug("Loading %s as a snippet." % self.currentFile) (snippetDescription, snippetKey, snippetCode) = loadSnippetFromFile(self.currentFile) self.snippetDescription.setText(snippetDescription) if snippetDescription else self.snippetDescription.setText("") self.keySequenceEdit.setKeySequence(snippetKey[0]) if len(snippetKey) != 0 else self.keySequenceEdit.setKeySequence(QKeySequence("")) self.edit.setPlainText(snippetCode) if snippetCode else self.edit.setPlainText("") def newFileDialog(self): (snippetName, ok) = QInputDialog.getText(self, self.tr("Snippet Name"), self.tr("Snippet Name: ")) if ok and snippetName: if not snippetName.endswith(".py"): snippetName += ".py" index = self.tree.selectionModel().currentIndex() selection = self.files.filePath(index) if QFileInfo(selection).isDir(): open(os.path.join(selection, snippetName), "w").close() else: open(os.path.join(snippetPath, snippetName), "w").close() log_debug("Snippet %s created." % snippetName) def deleteSnippet(self): selection = self.tree.selectedIndexes()[::self.columns][0] #treeview returns each selected element in the row snippetName = self.files.fileName(selection) question = QMessageBox.question(self, self.tr("Confirm"), self.tr("Confirm deletion: ") + snippetName) if (question == QMessageBox.StandardButton.Yes): log_debug("Deleting snippet %s." % snippetName) self.clearSelection() self.files.remove(selection) def snippetChanged(self): if (self.currentFile == "" or QFileInfo(self.currentFile).isDir()): return False (snippetDescription, snippetKey, snippetCode) = loadSnippetFromFile(self.currentFile) if (not snippetCode): return False if len(snippetKey) == 0 and not self.keySequenceEdit.keySequence().isEmpty(): return True if len(snippetKey) != 0 and snippetKey[0] != self.keySequenceEdit.keySequence(): return True return self.edit.toPlainText() != snippetCode or \ self.snippetDescription.text() != snippetDescription def save(self): log_debug("Saving snippet %s" % self.currentFile) outputSnippet = open(self.currentFile, "w") outputSnippet.write("#" + self.snippetDescription.text() + "\n") outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n") outputSnippet.write(self.edit.toPlainText()) outputSnippet.close() self.registerAllSnippets() def clearHotkey(self): self.keySequenceEdit.clear()
class SVDBrowser(QDialog): def __init__(self, context, parent=None): super(SVDBrowser, self).__init__(parent) QWebEngineProfile.defaultProfile().downloadRequested.connect( self.on_downloadRequested) # Create widgets #self.setWindowModality(Qt.ApplicationModal) self.title = QLabel(self.tr("SVD Browser")) self.closeButton = QPushButton(self.tr("Close")) self.setWindowTitle(self.title.text()) self.browseButton = QPushButton("Browse SVD Folder") self.deleteSvdButton = QPushButton("Delete") self.applySvdButton = QPushButton("Apply SVD") self.view = QWebEngineView() url = "https://developer.arm.com/tools-and-software/embedded/cmsis/cmsis-search" self.view.load(QUrl(url)) self.columns = 3 self.context = context self.currentFileLabel = QLabel() self.currentFile = "" #Files self.files = QFileSystemModel() self.files.setRootPath(svdPath) self.files.setNameFilters(["*.svd", "*.patched"]) #Tree self.tree = QTreeView() self.tree.setModel(self.files) self.tree.setSortingEnabled(True) self.tree.hideColumn(2) self.tree.sortByColumn(0, Qt.AscendingOrder) self.tree.setRootIndex(self.files.index(svdPath)) for x in range(self.columns): #self.tree.resizeColumnToContents(x) self.tree.header().setSectionResizeMode( x, QHeaderView.ResizeToContents) treeLayout = QVBoxLayout() treeLayout.addWidget(self.tree) treeButtons = QHBoxLayout() #treeButtons.addWidget(self.newFolderButton) treeButtons.addWidget(self.browseButton) treeButtons.addWidget(self.applySvdButton) treeButtons.addWidget(self.deleteSvdButton) treeLayout.addLayout(treeButtons) treeWidget = QWidget() treeWidget.setLayout(treeLayout) # Create layout and add widgets buttons = QHBoxLayout() buttons.addWidget(self.closeButton) vlayoutWidget = QWidget() vlayout = QVBoxLayout() vlayout.addWidget(self.view) vlayout.addLayout(buttons) vlayoutWidget.setLayout(vlayout) hsplitter = QSplitter() hsplitter.addWidget(treeWidget) hsplitter.addWidget(vlayoutWidget) hlayout = QHBoxLayout() hlayout.addWidget(hsplitter) self.showMaximized() #Fixes bug that maximized windows are "stuck" #Because you can't trust QT to do the right thing here # Set dialog layout self.setLayout(hlayout) # Add signals self.closeButton.clicked.connect(self.close) self.tree.selectionModel().selectionChanged.connect(self.selectFile) self.applySvdButton.clicked.connect(self.applySvd) self.deleteSvdButton.clicked.connect(self.deleteSvd) self.browseButton.clicked.connect(self.browseSvd) def browseSvd(self): url = QUrl.fromLocalFile(svdPath) QDesktopServices.openUrl(url) def selectFile(self, new, old): if len(new.indexes()) == 0: self.tree.clearSelection() self.currentFile = "" return newSelection = self.files.filePath(new.indexes()[0]) if QFileInfo(newSelection).isDir(): self.tree.clearSelection() self.currentFile = "" return self.currentFile = newSelection def applySvd(self): selection = self.tree.selectedIndexes()[::self.columns][ 0] #treeview returns each selected element in the row svdName = self.files.fileName(selection) if (svdName != ""): question = QMessageBox.question( self, self.tr("Confirm"), self. tr(f"Confirm applying {svdName} to {os.path.basename(self.context.file.filename)} : " )) if (question == QMessageBox.StandardButton.Yes): log_debug("SVD Browser: Applying SVD %s." % svdName) load_svd(self.context, self.currentFile) self.close() def deleteSvd(self): selection = self.tree.selectedIndexes()[::self.columns][ 0] #treeview returns each selected element in the row svdName = self.files.fileName(selection) question = QMessageBox.question( self, self.tr("Confirm"), self.tr("Confirm deletion: ") + svdName) if (question == QMessageBox.StandardButton.Yes): log_debug("SVD Browser: Deleting SVD %s." % svdName) self.files.remove(selection) self.tree.clearSelection() def on_downloadRequested(self, download): old_path = download.url().path() # download.path() suffix = QFileInfo(old_path).suffix() if (suffix.lower() in ["zip", "svd", "pack", "patched"]): log_debug(f"SVD Browser: Downloading {str(download.url())}") if suffix.lower() == "svd" or suffix.lower() == "patched": download.setDownloadDirectory(svdPath) download.accept() else: with TemporaryDirectory() as tempfolder: log_debug( f"SVD Browser: Downloading pack/zip to {tempfolder}") fname = download.url().fileName() r = requests.get(download.url().toString(), allow_redirects=True) dlfile = os.path.join(tempfolder, fname) open(dlfile, "wb").write(r.content) ''' # TODO: See if the original QT Downloader can be fixed since it would # help with situations where the user entered credentials in the browser. download.setDownloadDirectory(tempfolder) download.accept() while not download.finished: import time time.sleep(100) ''' if fname.endswith(".zip") or fname.endswith(".pack"): destFolder = os.path.join(svdPath, os.path.splitext(fname)[0]) log_debug(f"SVD Browser: Creating {destFolder}") if not os.path.exists(destFolder): os.mkdir(destFolder) with ZipFile(dlfile, 'r') as zipp: for ifname in zipp.namelist(): if ifname.endswith(".svd"): info = zipp.getinfo(ifname) info.filename = os.path.basename( info.filename) log_debug( f"SVD Browser: Extracting {info.filename} from {ifname}" ) zipp.extract(info, path=destFolder) else: #Move file into place shutil.move(dlfile, svdPath) else: show_message_box( "Invalid file", "That download does not appear to be a valid SVD/ZIP/PACK file." ) download.cancel()