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:
Eduard Wisch 2026-02-12 17:12:24 +01:00
parent 1f43e234d3
commit 044e9a848d
3 changed files with 99 additions and 13 deletions

View file

@ -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(

View file

@ -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."""

View file

@ -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