Implement configuration management, drag-and-drop functionality, and logging utilities for WebDrop Bridge

This commit is contained in:
claudi 2026-01-28 11:21:11 +01:00
parent 04ef84cf9a
commit 6bef2f6119
9 changed files with 1154 additions and 0 deletions

View file

@ -0,0 +1,158 @@
"""Main application window with web engine integration."""
from pathlib import Path
from typing import Optional
from PySide6.QtCore import Qt, QUrl
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWidgets import QMainWindow, QVBoxLayout, QWidget
from webdrop_bridge.config import Config
from webdrop_bridge.core.drag_interceptor import DragInterceptor
from webdrop_bridge.core.validator import PathValidator
class MainWindow(QMainWindow):
"""Main application window for WebDrop Bridge.
Displays web content in a QWebEngineView and provides drag-and-drop
integration with the native filesystem.
"""
def __init__(
self,
config: Config,
parent: Optional[QWidget] = None,
):
"""Initialize the main window.
Args:
config: Application configuration
parent: Parent widget
"""
super().__init__(parent)
self.config = config
# Set window properties
self.setWindowTitle(f"{config.app_name} v{config.app_version}")
self.setGeometry(
100,
100,
config.window_width,
config.window_height,
)
# Create web engine view
self.web_view = QWebEngineView()
# Create drag interceptor
self.drag_interceptor = DragInterceptor()
# Set up path validator
validator = PathValidator(config.allowed_roots)
self.drag_interceptor.set_validator(validator)
# Connect drag interceptor signals
self.drag_interceptor.drag_started.connect(self._on_drag_started)
self.drag_interceptor.drag_failed.connect(self._on_drag_failed)
# Set up central widget with layout
central_widget = QWidget()
layout = QVBoxLayout()
layout.addWidget(self.web_view)
layout.setContentsMargins(0, 0, 0, 0)
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
# Load web application
self._load_webapp()
# Apply styling if available
self._apply_stylesheet()
def _load_webapp(self) -> None:
"""Load the web application.
Loads HTML from the configured webapp URL or from local file.
"""
webapp_url = self.config.webapp_url
if webapp_url.startswith("http://") or webapp_url.startswith("https://"):
# Remote URL
self.web_view.load(QUrl(webapp_url))
else:
# Local file path
try:
file_path = Path(webapp_url).resolve()
if not file_path.exists():
self.web_view.setHtml(
f"<html><body><h1>Error</h1>"
f"<p>Web application file not found: {file_path}</p>"
f"</body></html>"
)
return
# Load local file as file:// URL
file_url = file_path.as_uri()
self.web_view.load(QUrl(file_url))
except (OSError, ValueError) as e:
self.web_view.setHtml(
f"<html><body><h1>Error</h1>"
f"<p>Failed to load web application: {e}</p>"
f"</body></html>"
)
def _apply_stylesheet(self) -> None:
"""Apply application stylesheet if available."""
stylesheet_path = Path(__file__).parent.parent.parent.parent / \
"resources" / "stylesheets" / "default.qss"
if stylesheet_path.exists():
try:
with open(stylesheet_path, "r") as f:
stylesheet = f.read()
self.setStyleSheet(stylesheet)
except (OSError, IOError):
# Silently fail if stylesheet can't be read
pass
def _on_drag_started(self, paths: list) -> None:
"""Handle successful drag initiation.
Args:
paths: List of paths that were dragged
"""
# Can be extended with logging or status bar updates
pass
def _on_drag_failed(self, error: str) -> None:
"""Handle drag operation failure.
Args:
error: Error message
"""
# Can be extended with logging or user notification
pass
def closeEvent(self, event) -> None:
"""Handle window close event.
Args:
event: Close event
"""
# Can be extended with save operations or cleanup
event.accept()
def initiate_drag(self, file_paths: list) -> bool:
"""Initiate a drag operation for the given files.
Called from web content via JavaScript bridge.
Args:
file_paths: List of file paths to drag
Returns:
True if drag was initiated successfully
"""
return self.drag_interceptor.initiate_drag(file_paths)