Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -219,5 +219,7 @@ __marimo__/
logs/
app.log

# Development/test scripts
run_refactored_ui.py
# Backup files
*.backup
*.bak
*~
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ A modern Python utility to merge multiple PowerPoint (.pptx) files into a single
- **Modern package structure** for easy installation and development
- **Command-line interface** for easy execution

## New Refactored GUI (PySide6)
## Modern GUI (PySide6)

The application now includes a modern, refactored GUI built with PySide6, featuring:
The application features a modern GUI built with PySide6, offering an intuitive two-column layout:

### Two-Column Layout
- **Left Column (3:1 ratio)**: Main interaction area with smart state management
Expand All @@ -40,19 +40,27 @@ The application now includes a modern, refactored GUI built with PySide6, featur
- **Settings Persistence**: Remembers last save location between sessions
- **Internationalization Ready**: All UI strings centralized for easy translation

### Using the Refactored GUI
### Using the GUI Programmatically

The GUI can be embedded in your own applications. Usage example:

```python
from merge_powerpoint.gui_refactored import MainUI
from merge_powerpoint.gui import MainUI
from merge_powerpoint.powerpoint_core import PowerPointMerger
from PySide6.QtWidgets import QApplication
from PySide6.QtWidgets import QApplication, QMainWindow
import sys

app = QApplication(sys.argv)
merger = PowerPointMerger()
window = MainUI(merger=merger)
window.resize(1000, 600)
window.show()

# MainUI is a QWidget, so embed it in a QMainWindow
main_window = QMainWindow()
ui = MainUI(merger=merger)
main_window.setCentralWidget(ui)
main_window.setWindowTitle("PowerPoint Presentation Merger")
main_window.resize(1000, 600)
main_window.show()

sys.exit(app.exec())
```

Expand Down
42 changes: 25 additions & 17 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ main.py
└── merge_powerpoint package
├── app.py (AppController)
│ └── powerpoint_core.py (PowerPointMerger)
├── gui.py (MainWindow)
├── gui.py (MainUI)
│ ├── PySide6.QtWidgets
│ └── powerpoint_core.py (PowerPointMerger)
└── app_logger.py (setup_logging)
Expand Down Expand Up @@ -147,24 +147,30 @@ run_with_logging.py

#### `gui.py` - User Interface

- **Purpose**: PySide6-based graphical user interface
- **Purpose**: PySide6-based graphical user interface with modern two-column layout
- **Framework**: PySide6 (Qt for Python)
- **Key Class**: `MainWindow`
- **Key Class**: `MainUI` (QWidget)
- **Architecture**: Signal-based with threaded operations
- **Features**:
- File list management
- Add/Remove/Clear operations
- File reordering (Move Up/Down)
- Merge with progress tracking
- Input validation
- Two-column layout with 3:1 ratio
- Drag-and-drop file support
- Smart state management (drop zone ↔ file list)
- Background merge operations (QThread)
- Real-time progress tracking
- Settings persistence (QSettings)
- Input validation and duplicate prevention
- **Components**:
- QListWidget for file display
- QPushButtons for actions
- QProgressBar for merge progress
- QFileDialog for file selection
- File dialog integration
- Move Up/Down file reordering
- Keyboard shortcuts (Enter key support)
- Visual feedback and styling
- `FileListModel`: Manages file list data
- `FileItemDelegate`: Custom rendering for file items
- `DropZoneWidget`: Drag-and-drop zone with visual feedback
- `MergeWorker`: QThread for asynchronous merging
- `MainUI`: Main widget with signal/slot architecture
- **Key Signals**:
- `files_added`: When files are added
- `file_removed`: When a file is removed
- `order_changed`: When file order changes
- `clear_requested`: When clear all is requested
- `merge_requested`: When merge is initiated

### 4. Business Logic Layer

Expand Down Expand Up @@ -210,7 +216,9 @@ run_with_logging.py
├── Launch via CLI (merge-powerpoint) or script (python main.py)
├── Initialize logging
├── Create QApplication
└── Show MainWindow
├── Create MainUI widget
├── Embed MainUI in QMainWindow
└── Show window

2. File Management
├── User clicks "Add Files"
Expand Down
4 changes: 2 additions & 2 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ from gui import MainWindow
```python
# New way (recommended)
from merge_powerpoint.powerpoint_core import PowerPointMerger
from merge_powerpoint.gui import MainWindow
from merge_powerpoint.gui import MainUI

# Old way (still works via compatibility shims)
from powerpoint_core import PowerPointMerger
from gui import MainWindow
from gui import MainUI
```

## For Developers
Expand Down
18 changes: 12 additions & 6 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
if str(src_path) not in sys.path:
sys.path.insert(0, str(src_path))

from PySide6.QtWidgets import QApplication # noqa: E402
from PySide6.QtWidgets import QApplication, QMainWindow # noqa: E402

from merge_powerpoint.app import AppController # noqa: E402
from merge_powerpoint.app_logger import setup_logging # noqa: E402
from merge_powerpoint.gui import MainWindow # noqa: E402
from merge_powerpoint.gui import MainUI # noqa: E402


def main():
Expand All @@ -27,9 +26,16 @@ def main():
"""
setup_logging()
app = QApplication(sys.argv)
controller = AppController()
window = MainWindow()
window.show()
app.setApplicationName("PowerPoint Merger")
app.setOrganizationName("MergePowerPoint")

# MainUI is a QWidget, so embed it in a QMainWindow
main_window = QMainWindow()
ui = MainUI()
main_window.setCentralWidget(ui)
main_window.setWindowTitle("PowerPoint Presentation Merger")
main_window.resize(1000, 600)
main_window.show()
return app.exec()


Expand Down
10 changes: 6 additions & 4 deletions new_gui/main_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
application window from the `gui` module and runs it. The key functionality
is modifying `sys.path` to allow imports from the parent directory.
"""
import sys
import os
import logging
import os
import sys

# --- FIX FOR ModuleNotFoundError ---
# Get the absolute path of the directory containing this script (new_gui).
Expand All @@ -19,9 +19,11 @@
# ---------------------------------

# Now that the project root is on the path, these imports will succeed.
from gui import MainApplication
from logger import setup_logging

from gui import MainApplication


def main():
"""
Initializes logging and runs the GUI application for testing.
Expand All @@ -32,7 +34,7 @@ def main():
app = MainApplication()
app.mainloop()
logging.info("GUI application closed normally.")
except Exception as e:
except Exception:
logging.critical("The GUI application encountered a fatal error.", exc_info=True)
# In a real-world scenario, you might show an error dialog here.

Expand Down
16 changes: 12 additions & 4 deletions src/merge_powerpoint/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

import sys

from PySide6.QtWidgets import QApplication
from PySide6.QtWidgets import QApplication, QMainWindow

from merge_powerpoint.app_logger import setup_logging
from merge_powerpoint.gui import MainWindow
from merge_powerpoint.gui import MainUI


def main():
Expand All @@ -23,8 +23,16 @@ def main():
"""
setup_logging()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.setApplicationName("PowerPoint Merger")
app.setOrganizationName("MergePowerPoint")

# MainUI is a QWidget, so embed it in a QMainWindow
main_window = QMainWindow()
ui = MainUI()
main_window.setCentralWidget(ui)
main_window.setWindowTitle("PowerPoint Presentation Merger")
main_window.resize(1000, 600)
main_window.show()
return app.exec()


Expand Down
Loading
Loading