#include "MainWindow.h" #include #include #include #include #include #include #include "AboutDialog.h" #include "filetree/FileTreePanel.h" #include "editor/EditorPanel.h" // --------------------------------------------------------------------------- // Konstruktor // --------------------------------------------------------------------------- MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , m_projectManager(std::make_unique()) , m_settings(std::make_unique()) , m_themeManager(std::make_unique()) { setWindowTitle("BareCode"); setMinimumSize(900, 600); setupUi(); setupMenuBar(); setupStatusBar(); connectSignals(); restoreWindowState(); applyInitialTheme(); // Letztes Projekt wieder öffnen const QString lastPath = m_settings->lastProjectPath(); if (!lastPath.isEmpty()) { m_projectManager->openProject(lastPath); } // Letzte Session wiederherstellen (geöffnete Dateien + aktiver Tab) m_editor->restoreSession( m_settings->lastOpenFiles(), m_settings->lastActiveFile() ); } MainWindow::~MainWindow() = default; // --------------------------------------------------------------------------- // Datei(en) von der Kommandozeile öffnen // --------------------------------------------------------------------------- void MainWindow::openFilesFromArguments(const QStringList &filePaths) { for (const QString &path : filePaths) { const QFileInfo info(path); if (info.exists() && info.isFile()) { m_editor->openFile(info.absoluteFilePath()); } } } // --------------------------------------------------------------------------- // UI aufbauen // --------------------------------------------------------------------------- void MainWindow::setupUi() { m_splitter = new QSplitter(Qt::Horizontal, this); setCentralWidget(m_splitter); m_fileTree = new FileTreePanel(m_splitter); m_editor = new EditorPanel(m_settings.get(), m_splitter); m_splitter->addWidget(m_fileTree); m_splitter->addWidget(m_editor); const int treeWidth = m_settings->fileTreeWidth(); m_splitter->setSizes({treeWidth, width() - treeWidth}); m_splitter->setStretchFactor(0, 0); m_splitter->setStretchFactor(1, 1); } // --------------------------------------------------------------------------- // Menüleiste // --------------------------------------------------------------------------- void MainWindow::setupMenuBar() { // ---- Datei ---- QMenu *mDatei = menuBar()->addMenu(tr("&Datei")); m_actNewFile = mDatei->addAction(tr("&Neue Datei…"), this, &MainWindow::onNewFile); m_actNewFile->setShortcut(QKeySequence::New); mDatei->addSeparator(); m_actOpenFile = mDatei->addAction(tr("Datei &öffnen…"), this, &MainWindow::onOpenFile); m_actOpenFile->setShortcut(QKeySequence::Open); m_actOpenProject = mDatei->addAction(tr("&Projekt öffnen…"), this, &MainWindow::onOpenProject); m_actOpenProject->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_O); m_actClose = mDatei->addAction(tr("Projekt &schließen"), this, &MainWindow::onCloseProject); mDatei->addSeparator(); m_actSave = mDatei->addAction(tr("&Speichern"), this, &MainWindow::onSave); m_actSave->setShortcut(QKeySequence::Save); m_actSaveAs = mDatei->addAction(tr("Speichern &unter…"), this, &MainWindow::onSaveAs); m_actSaveAs->setShortcut(QKeySequence::SaveAs); m_actSaveAll = mDatei->addAction(tr("&Alles speichern"), this, &MainWindow::onSaveAll); m_actSaveAll->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_S); mDatei->addSeparator(); m_actQuit = mDatei->addAction(tr("&Beenden"), qApp, &QApplication::quit); m_actQuit->setShortcut(QKeySequence::Quit); // ---- Bearbeiten ---- QMenu *mBearbeiten = menuBar()->addMenu(tr("&Bearbeiten")); m_actUndo = mBearbeiten->addAction(tr("&Rückgängig"), this, &MainWindow::onUndo); m_actUndo->setShortcut(QKeySequence::Undo); m_actRedo = mBearbeiten->addAction(tr("&Wiederholen"), this, &MainWindow::onRedo); m_actRedo->setShortcut(QKeySequence::Redo); mBearbeiten->addSeparator(); m_actSearch = mBearbeiten->addAction(tr("&Suchen / Ersetzen…"), this, &MainWindow::onShowSearch); m_actSearch->setShortcut(QKeySequence::Find); m_actFileSearch = mBearbeiten->addAction(tr("In &Dateien suchen…"), this, &MainWindow::onShowFileSearch); m_actFileSearch->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_F); mBearbeiten->addSeparator(); m_actFuncList = mBearbeiten->addAction(tr("&Projektfunktionen…"), this, &MainWindow::onShowFunctionList); m_actFuncList->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_P); m_actDeadCode = mBearbeiten->addAction(tr("&Tote Funktionen suchen…"), this, &MainWindow::onShowDeadCode); m_actDeadCode->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_T); // ---- Ansicht ---- QMenu *mAnsicht = menuBar()->addMenu(tr("&Ansicht")); m_actDarkMode = mAnsicht->addAction(tr("&Dark Mode")); m_actDarkMode->setCheckable(true); m_actDarkMode->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_D); connect(m_actDarkMode, &QAction::toggled, this, &MainWindow::onToggleDarkMode); mAnsicht->addSeparator(); // Sprachauswahl QMenu *mSprache = mAnsicht->addMenu(tr("Sprache")); m_langGroup = new QActionGroup(this); m_langGroup->setExclusive(true); const QSettings langSettings(QSettings::IniFormat, QSettings::UserScope, "BareCode", "BareCode"); const QString currentLocale = langSettings.value("language/locale", QLocale::system().name()).toString(); struct LangEntry { QString locale; QString label; }; const QList languages = { { "de", "Deutsch" }, { "en", "English" }, }; for (const LangEntry &lang : languages) { QAction *act = mSprache->addAction(lang.label); act->setCheckable(true); act->setData(lang.locale); act->setChecked(currentLocale.startsWith(lang.locale)); m_langGroup->addAction(act); connect(act, &QAction::triggered, this, [this, lang]() { onLanguageChanged(lang.locale); }); } // ---- Hilfe ---- QMenu *mHilfe = menuBar()->addMenu(tr("&Hilfe")); m_actAbout = mHilfe->addAction(tr("&Über BareCode…"), this, &MainWindow::onAbout); } void MainWindow::setupStatusBar() { statusBar()->showMessage(tr("Bereit")); } // --------------------------------------------------------------------------- // Signale verbinden // --------------------------------------------------------------------------- void MainWindow::connectSignals() { connect(m_projectManager.get(), &ProjectManager::projectOpened, this, &MainWindow::onProjectOpened); connect(m_projectManager.get(), &ProjectManager::projectClosed, this, &MainWindow::onProjectClosed); // Dateibaum → Editor connect(m_fileTree, &FileTreePanel::fileActivated, m_editor, &EditorPanel::openFile); connect(m_fileTree, &FileTreePanel::fileCreated, m_editor, &EditorPanel::openFile); // Gespeichert → Statusleiste connect(m_editor, &EditorPanel::currentFileSaved, this, [this](const QString &path) { statusBar()->showMessage(tr("Gespeichert: %1").arg(path), 3000); }); // Splitter-Breite merken connect(m_splitter, &QSplitter::splitterMoved, this, [this](int pos, int) { m_settings->setFileTreeWidth(pos); }); } // --------------------------------------------------------------------------- // Theme beim Start // --------------------------------------------------------------------------- void MainWindow::applyInitialTheme() { const bool dark = m_settings->darkMode(); // Block damit toggled-Signal nicht doppelt feuert m_actDarkMode->blockSignals(true); m_actDarkMode->setChecked(dark); m_actDarkMode->blockSignals(false); m_themeManager->applyTheme(dark ? ThemeManager::Theme::Dark : ThemeManager::Theme::Light); } // --------------------------------------------------------------------------- // Slots – Datei // --------------------------------------------------------------------------- void MainWindow::onNewFile() { m_fileTree->triggerNewFile(); } void MainWindow::onOpenFile() { const QString path = QFileDialog::getOpenFileName( this, tr("Datei öffnen"), m_settings->lastProjectPath() ); if (!path.isEmpty()) { m_editor->openFile(path); } } void MainWindow::onOpenProject() { const QString path = QFileDialog::getExistingDirectory( this, tr("Projektverzeichnis öffnen"), m_settings->lastProjectPath() ); if (!path.isEmpty()) { m_projectManager->openProject(path); m_settings->setLastProjectPath(path); } } void MainWindow::onCloseProject() { m_projectManager->closeProject(); } void MainWindow::onSave() { m_editor->saveCurrentFile(); } void MainWindow::onSaveAs() { m_editor->saveCurrentFileAs(); } void MainWindow::onSaveAll() { m_editor->saveAllFiles(); statusBar()->showMessage(tr("Alle Dateien gespeichert"), 3000); } // --------------------------------------------------------------------------- // Slots – Bearbeiten // --------------------------------------------------------------------------- void MainWindow::onUndo() { m_editor->undo(); } void MainWindow::onRedo() { m_editor->redo(); } void MainWindow::onShowSearch() { m_editor->showSearchPanel(); } // --------------------------------------------------------------------------- // Slots – Ansicht // --------------------------------------------------------------------------- void MainWindow::onToggleDarkMode(bool checked) { m_themeManager->applyTheme(checked ? ThemeManager::Theme::Dark : ThemeManager::Theme::Light); m_settings->setDarkMode(checked); } void MainWindow::onLanguageChanged(const QString &locale) { QSettings s(QSettings::IniFormat, QSettings::UserScope, "BareCode", "BareCode"); s.setValue("language/locale", locale); QMessageBox::information(this, tr("Sprache geändert"), tr("Die Sprache wird beim nächsten Start von BareCode aktiv.") ); } // --------------------------------------------------------------------------- // Slots – Hilfe // --------------------------------------------------------------------------- void MainWindow::onAbout() { AboutDialog dlg(this); dlg.exec(); } // --------------------------------------------------------------------------- // Slots – Projekt // --------------------------------------------------------------------------- void MainWindow::onShowDeadCode() { m_editor->showDeadCode(); } void MainWindow::onShowFunctionList() { m_editor->showFunctionList(); } void MainWindow::onShowFileSearch() { m_editor->showFileSearchPanel(); } void MainWindow::onProjectOpened(const QString &path) { setWindowTitle(QString("BareCode – %1").arg(path)); m_fileTree->setRootPath(path); m_editor->setSearchRoot(path); statusBar()->showMessage(tr("Projekt geöffnet: %1").arg(path), 4000); } void MainWindow::onProjectClosed() { setWindowTitle("BareCode"); m_fileTree->clearRoot(); m_editor->setSearchRoot(QString()); statusBar()->showMessage(tr("Projekt geschlossen"), 3000); } // --------------------------------------------------------------------------- // Fenster-Zustand // --------------------------------------------------------------------------- void MainWindow::saveWindowState() { QSettings s(QSettings::IniFormat, QSettings::UserScope, "BareCode", "BareCode"); s.setValue("window/geometry", saveGeometry()); s.setValue("window/state", saveState()); // Session speichern m_settings->setLastOpenFiles(m_editor->openFilePaths()); m_settings->setLastActiveFile(m_editor->activeFilePath()); } void MainWindow::restoreWindowState() { QSettings s(QSettings::IniFormat, QSettings::UserScope, "BareCode", "BareCode"); if (s.contains("window/geometry")) { restoreGeometry(s.value("window/geometry").toByteArray()); } if (s.contains("window/state")) { restoreState(s.value("window/state").toByteArray()); } } void MainWindow::closeEvent(QCloseEvent *event) { saveWindowState(); event->accept(); }