"""Aggregator tab for combining markdown files.""" import os from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QProgressBar, QFileDialog, QMessageBox ) from PyQt6.QtCore import Qt, QCoreApplication from core.aggregator import Aggregator from core.exceptions import ObsidianToolException class AggregatorTab(QWidget): """Tab for aggregating multiple markdown files.""" def __init__(self): """Initialize the aggregator tab.""" super().__init__() self.aggregator = Aggregator() self.init_ui() def init_ui(self): """Initialize the user interface.""" layout = QVBoxLayout(self) layout.setSpacing(15) layout.setContentsMargins(20, 20, 20, 20) # Source Directory section layout.addWidget(QLabel("Source Directory:")) source_layout = QHBoxLayout() self.source_edit = QLineEdit() self.source_edit.setReadOnly(True) self.source_edit.setPlaceholderText("Select a directory containing .md files...") source_layout.addWidget(self.source_edit) self.source_btn = QPushButton("Browse...") self.source_btn.setMaximumWidth(100) self.source_btn.clicked.connect(self.browse_source) source_layout.addWidget(self.source_btn) layout.addLayout(source_layout) # Output File section layout.addWidget(QLabel("Output File:")) output_layout = QHBoxLayout() self.output_edit = QLineEdit() self.output_edit.setReadOnly(True) self.output_edit.setPlaceholderText("Select output file location...") output_layout.addWidget(self.output_edit) self.output_btn = QPushButton("Browse...") self.output_btn.setMaximumWidth(100) self.output_btn.clicked.connect(self.browse_output) output_layout.addWidget(self.output_btn) layout.addLayout(output_layout) # Spacer layout.addSpacing(20) # Action button self.aggregate_btn = QPushButton("Aggregate Files") self.aggregate_btn.setMinimumHeight(40) self.aggregate_btn.clicked.connect(self.aggregate_files) layout.addWidget(self.aggregate_btn) # Progress bar self.progress_bar = QProgressBar() self.progress_bar.setValue(0) layout.addWidget(self.progress_bar) # Status label self.status_label = QLabel("Ready") self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.status_label.setStyleSheet("color: #666; font-style: italic;") layout.addWidget(self.status_label) # Add stretch to push everything to the top layout.addStretch() def browse_source(self): """Open dialog to select source directory.""" directory = QFileDialog.getExistingDirectory( self, "Select Source Directory", os.path.expanduser("~") ) if directory: self.source_edit.setText(directory) self.status_label.setText("Source directory selected") def browse_output(self): """Open dialog to select output file.""" file_path, _ = QFileDialog.getSaveFileName( self, "Select Output File", os.path.expanduser("~/aggregated.md"), "Markdown Files (*.md);;All Files (*)" ) if file_path: # Ensure .md extension if not file_path.endswith('.md'): file_path += '.md' self.output_edit.setText(file_path) self.status_label.setText("Output file selected") def aggregate_files(self): """Perform the aggregation operation.""" source_dir = self.source_edit.text() output_file = self.output_edit.text() # Validate inputs if not source_dir: QMessageBox.warning( self, "Input Required", "Please select a source directory." ) return if not output_file: QMessageBox.warning( self, "Input Required", "Please select an output file." ) return # Disable UI during operation self.set_ui_enabled(False) self.progress_bar.setValue(0) self.status_label.setText("Aggregating files...") try: # Progress callback def update_progress(percentage, message): self.progress_bar.setValue(percentage) self.status_label.setText(message) QCoreApplication.processEvents() # Keep UI responsive # Perform aggregation result = self.aggregator.aggregate( source_dir, output_file, update_progress ) # Show success message QMessageBox.information( self, "Success", f"Aggregation complete!\n\n" f"Files processed: {result['files_processed']}\n" f"Output file: {result['output_file']}" ) self.status_label.setText("Aggregation completed successfully") except ObsidianToolException as e: QMessageBox.critical( self, "Error", f"Aggregation failed:\n\n{str(e)}" ) self.status_label.setText("Aggregation failed") self.progress_bar.setValue(0) except Exception as e: QMessageBox.critical( self, "Unexpected Error", f"An unexpected error occurred:\n\n{str(e)}" ) self.status_label.setText("Aggregation failed") self.progress_bar.setValue(0) finally: # Re-enable UI self.set_ui_enabled(True) def set_ui_enabled(self, enabled: bool): """Enable or disable UI elements during operation.""" self.source_btn.setEnabled(enabled) self.output_btn.setEnabled(enabled) self.aggregate_btn.setEnabled(enabled)