Fix: Gelöschte Dateien verschwinden sofort aus der Liste
- Gelöschte Einträge werden direkt aus dem Model entfernt statt Verzeichnis neu zu laden - Verzeichnis-Cache wird vor dem Einlesen invalidiert (os.listdir statt os.scandir) - Selektion wird beim Refresh/Löschen zurückgesetzt - PDF Preview: Darkmode Toggle hinzugefügt Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
1f43e234d3
commit
044e9a848d
3 changed files with 99 additions and 13 deletions
|
|
@ -386,6 +386,7 @@ class MainWindow(QMainWindow):
|
|||
self.file_list.folder_entered.connect(self._navigate_to)
|
||||
self.file_list.file_rename_requested.connect(self._rename_file)
|
||||
self.file_list.file_delete_requested.connect(self._delete_file)
|
||||
self.file_list.files_delete_requested.connect(self._delete_files)
|
||||
self.file_list.file_move_requested.connect(self._move_file)
|
||||
self.file_list.files_dropped.connect(self._handle_files_dropped)
|
||||
|
||||
|
|
@ -648,16 +649,22 @@ class MainWindow(QMainWindow):
|
|||
dialog = DeleteDialog(paths, self)
|
||||
if dialog.exec():
|
||||
errors = []
|
||||
deleted_paths = []
|
||||
for path in paths:
|
||||
try:
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
os.remove(path)
|
||||
deleted_paths.append(path)
|
||||
except Exception as e:
|
||||
errors.append(f"{os.path.basename(path)}: {e}")
|
||||
|
||||
self._refresh()
|
||||
# Gelöschte Einträge direkt aus der Liste entfernen
|
||||
if deleted_paths:
|
||||
self.file_list.remove_paths(deleted_paths)
|
||||
self.folder_tree.refresh()
|
||||
self._update_count()
|
||||
|
||||
if errors:
|
||||
QMessageBox.warning(
|
||||
|
|
|
|||
|
|
@ -116,25 +116,33 @@ class FileListModel(QAbstractTableModel):
|
|||
return
|
||||
|
||||
try:
|
||||
entries = os.scandir(path)
|
||||
# Verzeichnis-Cache invalidieren
|
||||
try:
|
||||
fd = os.open(path, os.O_RDONLY | os.O_DIRECTORY)
|
||||
os.close(fd)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
folders = []
|
||||
files = []
|
||||
|
||||
for entry in entries:
|
||||
for name in os.listdir(path):
|
||||
entry_path = os.path.join(path, name)
|
||||
try:
|
||||
stat = entry.stat()
|
||||
stat = os.stat(entry_path)
|
||||
is_dir = os.path.isdir(entry_path)
|
||||
item = FileItem(
|
||||
name=entry.name,
|
||||
path=entry.path,
|
||||
is_dir=entry.is_dir(),
|
||||
size=stat.st_size if entry.is_file() else 0,
|
||||
name=name,
|
||||
path=entry_path,
|
||||
is_dir=is_dir,
|
||||
size=stat.st_size if not is_dir else 0,
|
||||
modified=datetime.fromtimestamp(stat.st_mtime)
|
||||
)
|
||||
if entry.is_dir():
|
||||
if is_dir:
|
||||
folders.append(item)
|
||||
else:
|
||||
files.append(item)
|
||||
except (PermissionError, OSError):
|
||||
except (PermissionError, OSError, FileNotFoundError):
|
||||
continue
|
||||
|
||||
# Natürliche Sortierung
|
||||
|
|
@ -159,6 +167,18 @@ class FileListModel(QAbstractTableModel):
|
|||
if self.current_path:
|
||||
self.set_path(self.current_path)
|
||||
|
||||
def remove_paths(self, paths: list[str]):
|
||||
"""Entfernt Einträge mit den angegebenen Pfaden aus dem Model."""
|
||||
paths_set = set(paths)
|
||||
# Finde Indizes der zu löschenden Items (von hinten nach vorne)
|
||||
indices_to_remove = [i for i, item in enumerate(self.items) if item.path in paths_set]
|
||||
indices_to_remove.sort(reverse=True)
|
||||
|
||||
for idx in indices_to_remove:
|
||||
self.beginRemoveRows(QModelIndex(), idx, idx)
|
||||
del self.items[idx]
|
||||
self.endRemoveRows()
|
||||
|
||||
|
||||
class FileListWidget(QTableView):
|
||||
"""Dateiliste mit Kontextmenü und Drag & Drop."""
|
||||
|
|
@ -167,7 +187,8 @@ class FileListWidget(QTableView):
|
|||
file_double_clicked = pyqtSignal(str) # path
|
||||
folder_entered = pyqtSignal(str) # path
|
||||
file_rename_requested = pyqtSignal(str) # path
|
||||
file_delete_requested = pyqtSignal(str) # path
|
||||
file_delete_requested = pyqtSignal(str) # path (einzelne Datei)
|
||||
files_delete_requested = pyqtSignal(object) # paths (mehrere Dateien)
|
||||
file_move_requested = pyqtSignal(str) # path
|
||||
files_dropped = pyqtSignal(list, str) # source_paths, target_folder
|
||||
|
||||
|
|
@ -433,6 +454,14 @@ class FileListWidget(QTableView):
|
|||
props_action.triggered.connect(lambda: self.properties_requested.emit([item.path]))
|
||||
menu.addAction(props_action)
|
||||
|
||||
menu.addSeparator()
|
||||
|
||||
# Aktualisieren
|
||||
refresh_action = QAction("🔄 Aktualisieren", self)
|
||||
refresh_action.setShortcut("F5")
|
||||
refresh_action.triggered.connect(self.refresh_requested.emit)
|
||||
menu.addAction(refresh_action)
|
||||
|
||||
def _build_multi_item_context_menu(self, menu: QMenu, items: list[FileItem]):
|
||||
"""Erstellt Kontextmenü für mehrere Elemente."""
|
||||
paths = [item.path for item in items]
|
||||
|
|
@ -470,6 +499,14 @@ class FileListWidget(QTableView):
|
|||
props_action.triggered.connect(lambda: self.properties_requested.emit(paths))
|
||||
menu.addAction(props_action)
|
||||
|
||||
menu.addSeparator()
|
||||
|
||||
# Aktualisieren
|
||||
refresh_action = QAction("🔄 Aktualisieren", self)
|
||||
refresh_action.setShortcut("F5")
|
||||
refresh_action.triggered.connect(self.refresh_requested.emit)
|
||||
menu.addAction(refresh_action)
|
||||
|
||||
def _open_external(self, path: str):
|
||||
"""Öffnet eine Datei mit der Standard-Anwendung."""
|
||||
try:
|
||||
|
|
@ -522,8 +559,8 @@ class FileListWidget(QTableView):
|
|||
|
||||
def _delete_items(self, items: list):
|
||||
"""Löscht mehrere Elemente."""
|
||||
for item in items:
|
||||
self.file_delete_requested.emit(item.path)
|
||||
paths = [item.path for item in items]
|
||||
self.files_delete_requested.emit(paths)
|
||||
|
||||
def get_selected_items(self) -> list[FileItem]:
|
||||
"""Gibt die ausgewählten Elemente zurück."""
|
||||
|
|
@ -542,8 +579,14 @@ class FileListWidget(QTableView):
|
|||
|
||||
def refresh(self):
|
||||
"""Aktualisiert die Dateiliste."""
|
||||
self.clearSelection()
|
||||
self.list_model.refresh()
|
||||
|
||||
def remove_paths(self, paths: list[str]):
|
||||
"""Entfernt Einträge mit den angegebenen Pfaden aus der Liste."""
|
||||
self.clearSelection()
|
||||
self.list_model.remove_paths(paths)
|
||||
|
||||
# Drag & Drop
|
||||
def startDrag(self, supportedActions):
|
||||
"""Startet einen Drag-Vorgang."""
|
||||
|
|
|
|||
|
|
@ -532,6 +532,16 @@ class PdfPreview(QWidget):
|
|||
self.draw_btn.clicked.connect(self._open_in_draw)
|
||||
toolbar_layout.addWidget(self.draw_btn)
|
||||
|
||||
toolbar_layout.addSpacing(8)
|
||||
|
||||
# Darkmode Toggle
|
||||
self.darkmode_btn = QPushButton("🌙")
|
||||
self.darkmode_btn.setToolTip("Darkmode umschalten")
|
||||
self.darkmode_btn.setFixedSize(32, 28)
|
||||
self.darkmode_btn.setCheckable(True)
|
||||
self.darkmode_btn.clicked.connect(self._toggle_darkmode)
|
||||
toolbar_layout.addWidget(self.darkmode_btn)
|
||||
|
||||
layout.addWidget(toolbar)
|
||||
|
||||
# PDF Document und View
|
||||
|
|
@ -564,9 +574,14 @@ class PdfPreview(QWidget):
|
|||
self.page_combo.setCurrentIndex(i)
|
||||
break
|
||||
|
||||
# Darkmode
|
||||
darkmode = self.settings.value('pdf_darkmode', False, type=bool)
|
||||
self.darkmode_btn.setChecked(darkmode)
|
||||
|
||||
# Einstellungen anwenden
|
||||
self._apply_zoom_mode()
|
||||
self._apply_page_mode()
|
||||
self._apply_darkmode(darkmode)
|
||||
|
||||
def _save_settings(self):
|
||||
"""Speichert PDF-Einstellungen."""
|
||||
|
|
@ -614,6 +629,27 @@ class PdfPreview(QWidget):
|
|||
self.pdf_view.setPageMode(mode)
|
||||
break
|
||||
|
||||
def _toggle_darkmode(self):
|
||||
"""Schaltet den Darkmode um."""
|
||||
is_dark = self.darkmode_btn.isChecked()
|
||||
self._apply_darkmode(is_dark)
|
||||
self.settings.setValue('pdf_darkmode', is_dark)
|
||||
|
||||
def _apply_darkmode(self, enabled: bool):
|
||||
"""Wendet den Darkmode an."""
|
||||
if enabled:
|
||||
self.darkmode_btn.setText("☀️")
|
||||
self.darkmode_btn.setToolTip("Lightmode umschalten")
|
||||
self.pdf_view.setStyleSheet("""
|
||||
QPdfView {
|
||||
background-color: #2d2d2d;
|
||||
}
|
||||
""")
|
||||
else:
|
||||
self.darkmode_btn.setText("🌙")
|
||||
self.darkmode_btn.setToolTip("Darkmode umschalten")
|
||||
self.pdf_view.setStyleSheet("")
|
||||
|
||||
def load_pdf(self, path: str) -> bool:
|
||||
"""Lädt eine PDF-Datei."""
|
||||
self._current_path = path
|
||||
|
|
|
|||
Loading…
Reference in a new issue