Implement configuration management, drag-and-drop functionality, and logging utilities for WebDrop Bridge
This commit is contained in:
parent
04ef84cf9a
commit
6bef2f6119
9 changed files with 1154 additions and 0 deletions
158
src/webdrop_bridge/ui/main_window.py
Normal file
158
src/webdrop_bridge/ui/main_window.py
Normal 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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue