Open probonopd opened 4 months ago
POC:
#!/usr/bin/env python3 import sys import os from PyQt6.QtWidgets import ( QApplication, QMainWindow, QHBoxLayout, QListView, QWidget, QAbstractItemView, QMenuBar, QMenu, QToolBar, QMessageBox ) from PyQt6.QtCore import QModelIndex, QSettings, QByteArray, Qt from PyQt6.QtGui import QFileSystemModel, QIcon, QAction class MillerColumns(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Miller Columns File Manager") self.resize(800, 600) # Default size self.central_widget = QWidget() self.setCentralWidget(self.central_widget) self.layout = QHBoxLayout(self.central_widget) self.columns = [] self.file_model = QFileSystemModel() self.file_model.setRootPath('') self.file_model.setOption(QFileSystemModel.Option.DontUseCustomDirectoryIcons, False) # Enable color icons home_dir = os.path.expanduser('~') self.add_column(self.file_model.index(home_dir)) self.create_menus() self.create_toolbar() self.read_settings() def create_menus(self): # Create a menubar menubar = self.menuBar() # File menu file_menu = menubar.addMenu("File") close_action = QAction("Close", self) close_action.triggered.connect(self.close) quit_action = QAction("Quit", self) quit_action.triggered.connect(QApplication.instance().quit) file_menu.addAction(close_action) file_menu.addSeparator() file_menu.addAction(quit_action) # Edit menu edit_menu = menubar.addMenu("Edit") undo_action = QAction("Undo", self) cut_action = QAction("Cut", self) copy_action = QAction("Copy", self) paste_action = QAction("Paste", self) delete_action = QAction("Delete", self) empty_trash_action = QAction("Empty Trash", self) edit_menu.addAction(undo_action) edit_menu.addSeparator() edit_menu.addAction(cut_action) edit_menu.addAction(copy_action) edit_menu.addAction(paste_action) edit_menu.addSeparator() edit_menu.addAction(delete_action) edit_menu.addSeparator() edit_menu.addAction(empty_trash_action) # Help menu help_menu = menubar.addMenu("Help") about_action = QAction("About", self) about_action.triggered.connect(self.show_about) help_menu.addAction(about_action) def create_toolbar(self): # Create a toolbar toolbar = QToolBar("Navigation") self.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) up_action = QAction(QIcon.fromTheme("go-up"), "Up", self) up_action.triggered.connect(self.go_up) toolbar.addAction(up_action) def show_about(self): QMessageBox.about(self, "About", "Miller Columns File Manager\nVersion 1.0") def go_up(self): if self.columns: # Always target the first column first_view = self.columns[0] current_index = first_view.rootIndex() if current_index.isValid(): parent_index = current_index.parent() if parent_index.isValid(): # Clear all columns to the right of the first column for column_view in self.columns[1:]: self.layout.removeWidget(column_view) column_view.deleteLater() self.columns = self.columns[:1] # Keep only the first column # Update the root index of the first column first_view.setRootIndex(parent_index) def add_column(self, parent_index=None): column_view = QListView() column_view.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) column_view.setUniformItemSizes(True) column_view.setAlternatingRowColors(True) # Enable alternating row colors column_view.setModel(self.file_model) if parent_index: column_view.setRootIndex(parent_index) self.layout.addWidget(column_view) self.columns.append(column_view) column_view.selectionModel().currentChanged.connect(self.on_selection_changed) column_view.doubleClicked.connect(self.on_double_clicked) def on_selection_changed(self, current: QModelIndex, previous: QModelIndex): column_index = self.get_column_index(current) if column_index is not None: # Remove all columns to the right of the current column while len(self.columns) > column_index + 1: column_to_remove = self.columns.pop() self.layout.removeWidget(column_to_remove) column_to_remove.deleteLater() # Add a new column if the selected item is a directory if self.file_model.isDir(current): self.add_column(current) def on_double_clicked(self, index: QModelIndex): if not self.file_model.isDir(index): file_path = self.file_model.filePath(index) os.startfile(file_path) def get_column_index(self, index: QModelIndex): for i, column in enumerate(self.columns): if column.selectionModel() == self.sender(): return i return None def closeEvent(self, event): self.write_settings() super().closeEvent(event) def read_settings(self): settings = QSettings("MyCompany", "MillerColumnsFileManager") geometry = settings.value("geometry", QByteArray()) if geometry: self.restoreGeometry(geometry) def write_settings(self): settings = QSettings("MyCompany", "MillerColumnsFileManager") settings.setValue("geometry", self.saveGeometry()) if __name__ == '__main__': app = QApplication(sys.argv) window = MillerColumns() window.show() sys.exit(app.exec())
This turned into https://github.com/probonopd/Miller, which currently already can run halfway decently on Windows 11...
POC: