Files
BareCode/src/core/MainWindow.cpp
2026-08-25 14:28:39 +02:00

397 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "MainWindow.h"
#include <QApplication>
#include <QFileDialog>
#include <QMessageBox>
#include <QCloseEvent>
#include <QSettings>
#include "AboutDialog.h"
#include "filetree/FileTreePanel.h"
#include "editor/EditorPanel.h"
// ---------------------------------------------------------------------------
// Konstruktor
// ---------------------------------------------------------------------------
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, m_projectManager(std::make_unique<ProjectManager>())
, m_settings(std::make_unique<Settings>())
, m_themeManager(std::make_unique<ThemeManager>())
{
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;
// ---------------------------------------------------------------------------
// 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<LangEntry> 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();
}