From 5c244b7383cf9a870ca1ca9fb8c77997da0674f4 Mon Sep 17 00:00:00 2001 From: Remisa Yousefvand Date: Sat, 2 Nov 2024 03:30:36 +0330 Subject: [PATCH] edit menu --- CHANGELOG.md | 14 +- CMakeLists.txt | 11 +- CMakeLists.txt.user | 18 +- README.md | 2 +- src/codeeditor.cpp | 5 + src/codeeditor.h | 1 + src/fileloaderworker.cpp | 2 +- src/fileloaderworker.h | 6 +- src/indentation/indentationdialog.cpp | 89 +++ src/indentation/indentationdialog.h | 33 + src/indentation/indentationdialog.ui | 123 ++++ src/indentation/indentationmanager.cpp | 134 ++++ src/indentation/indentationmanager.h | 36 + src/mainwindow.bak.cpp | 898 ------------------------- src/mainwindow.bak.h | 110 --- src/mainwindow.cpp | 172 +++-- src/mainwindow.h | 34 + src/mainwindow.ui | 4 +- src/mainwindow/formatting.cpp | 226 ++++++- src/mainwindow/formatting.h | 7 + src/mainwindow/helpers.cpp | 9 + src/mainwindow/helpers.h | 5 +- src/mainwindow/recentfiles.cpp | 2 +- src/mainwindow/textoperations.cpp | 2 +- src/{mainwindow => }/settings.cpp | 2 +- src/{mainwindow => }/settings.h | 0 26 files changed, 850 insertions(+), 1095 deletions(-) create mode 100644 src/indentation/indentationdialog.cpp create mode 100644 src/indentation/indentationdialog.h create mode 100644 src/indentation/indentationdialog.ui create mode 100644 src/indentation/indentationmanager.cpp create mode 100644 src/indentation/indentationmanager.h delete mode 100755 src/mainwindow.bak.cpp delete mode 100755 src/mainwindow.bak.h rename src/{mainwindow => }/settings.cpp (95%) rename src/{mainwindow => }/settings.h (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index fefc7df..d71c7b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ # Change Log -## 0.0.40 +## 0.0.41 + +- Implemented: +- Blank Operations -> Trim Trailing Space +- Blank Operations -> Trim Leading Space +- Blank Operations -> Trim Leading and Trailing Space +- Blank Operations -> EOL to Space +- Blank Operations -> Tab to Space +- Indentation -> Default Settings +- Indentation -> Custom + + +0.0.40 - Implemented: - Delete diff --git a/CMakeLists.txt b/CMakeLists.txt index b14481a..b15d62e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,8 +51,8 @@ set(PROJECT_SOURCES src/mainwindow/fileoperations.h src/mainwindow/recentfiles.cpp src/mainwindow/recentfiles.h - src/mainwindow/settings.cpp - src/mainwindow/settings.h + + src/mainwindow/helpers.cpp src/mainwindow/helpers.h src/mainwindow/formatting.cpp @@ -61,12 +61,19 @@ set(PROJECT_SOURCES src/mainwindow/session.h src/mainwindow/textoperations.cpp src/mainwindow/textoperations.h + src/indentation/indentationdialog.ui + src/indentation/indentationdialog.cpp + src/indentation/indentationdialog.h + src/indentation/indentationmanager.cpp + src/indentation/indentationmanager.h ) # Add Qt6 executable qt_add_executable(Notepad-- MANUAL_FINALIZATION ${PROJECT_SOURCES} + src/settings.cpp + src/settings.h ) # Link Qt6 libraries diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user index a9acea6..4250293 100755 --- a/CMakeLists.txt.user +++ b/CMakeLists.txt.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -102,14 +102,14 @@ 2 false - -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} -DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE:STRING=Debug --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake /data/Code/Qt/Notepad-- 0 /data/Code/Qt/Notepad--/build/Desktop-Debug @@ -160,14 +160,14 @@ 2 false - -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} -DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE:STRING=Release --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake /data/Code/Qt/Notepad-- /data/Code/Qt/Notepad--/build/Desktop-Release diff --git a/README.md b/README.md index 85d252b..5f94178 100755 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A simple light text editor. Notepadqq was my choice editor. Unfortunately it doesn't maintain anymore. I tried to help but there was old PRs and plenty of unanswered issues. The project was a mix of C++/Qt/Javascript/HTML,CSS,Python... -It is a while I didn't code in C++ and my knowledge of Qt is a little. All that said this is a **toy** project, at least for a while. The -- (minus minus) indicates that this is a minimalistic project. I will design GUI just like Notepadqq so there is no new GUI learning. For now I just release for Linux which has Qt6 installed (dynamic compile). +It is a while I didn't code in C++ and my knowledge of Qt is a little. All that said this is a **toy** project, at least for a while. The -- (minus minus) indicates that this is a minimalistic project. I will design GUI just like Notepadqq so there is no new GUI learning. For now I just release for Linux which has Qt6 installed (dynamic compile) and C++ 20. Any contribution is welcome. In a world without walls and fences, who needs **windows** and **gates**? diff --git a/src/codeeditor.cpp b/src/codeeditor.cpp index 17d6f41..52c5739 100755 --- a/src/codeeditor.cpp +++ b/src/codeeditor.cpp @@ -1,6 +1,7 @@ #include "codeeditor.h" #include #include +#include "mainwindow/helpers.h" CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent), lineNumberArea(new LineNumberArea(this)) { @@ -148,3 +149,7 @@ void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) { ++blockNumber; } } + +void CodeEditor::applyIndentation(bool useTabs, int indentationWidth) { + // TODO: Implement indentation +} diff --git a/src/codeeditor.h b/src/codeeditor.h index 2e0b761..0a9e40c 100755 --- a/src/codeeditor.h +++ b/src/codeeditor.h @@ -18,6 +18,7 @@ class CodeEditor : public QPlainTextEdit { void lineNumberAreaPaintEvent(QPaintEvent *event); int lineNumberAreaWidth(); void highlightCurrentLine(); + void applyIndentation(bool useTabs, int indentationWidth); protected: void resizeEvent(QResizeEvent *event) override; diff --git a/src/fileloaderworker.cpp b/src/fileloaderworker.cpp index 7bc2199..a4ea38a 100755 --- a/src/fileloaderworker.cpp +++ b/src/fileloaderworker.cpp @@ -7,7 +7,7 @@ #include FileLoaderWorker::FileLoaderWorker(const QString &filePath, Document *doc, QObject *parent) - : QObject(parent), m_filePath(filePath), m_file(filePath), document(doc) { + : QObject(parent), m_file(filePath), m_filePath(filePath), document(doc) { qDebug() << "FileLoaderWorker initialized for file:" << filePath; qDebug() << "FileLoaderWorker thread at initialization:" << QThread::currentThread(); } diff --git a/src/fileloaderworker.h b/src/fileloaderworker.h index d067e66..56c2656 100755 --- a/src/fileloaderworker.h +++ b/src/fileloaderworker.h @@ -32,8 +32,8 @@ public slots: void startLoading(); private: - qint64 m_fileSize; - Document *document; - QString m_filePath; QFile m_file; + QString m_filePath; + Document *document; + qint64 m_fileSize; }; diff --git a/src/indentation/indentationdialog.cpp b/src/indentation/indentationdialog.cpp new file mode 100644 index 0000000..68c306b --- /dev/null +++ b/src/indentation/indentationdialog.cpp @@ -0,0 +1,89 @@ +#include +#include "indentationdialog.h" +#include "ui_indentationdialog.h" +#include "../settings.h" +#include "../document.h" +#include "../codeeditor.h" +#include "../mainwindow/helpers.h" + +IndentationDialog::IndentationDialog(QWidget *parent) + : QDialog(parent), ui(new Ui::IndentationDialog) +{ + ui->setupUi(this); + + loadSettings(); + + connect(ui->tabs, &QRadioButton::clicked, this, &IndentationDialog::onIndentationSelected); + connect(ui->spaces, &QRadioButton::clicked, this, &IndentationDialog::onIndentationSelected); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &IndentationDialog::onOkClicked); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &IndentationDialog::reject); +} + +IndentationDialog::~IndentationDialog() +{ + delete ui; +} + +bool IndentationDialog::isTabsSelected() const { + return ui->tabs->isChecked(); +} + +int IndentationDialog::getIndentationValue() const { + return ui->number->value(); +} + +void IndentationDialog::onIndentationSelected() { + // Your logic when the indentation is selected + qDebug() << "Indentation option selected."; +} + +void IndentationDialog::loadSettings() { + QSettings settings("Remisa", "Notepad--"); + settings.beginGroup("IndentationSettings"); + QString value = settings.value("indentationOption", "Tabs").toString(); // Default to tabs if no value found + int indentationSize = settings.value("indentationSize", 1).toInt(); // Default to 1 if no value found + settings.endGroup(); + + ui->tabs->setChecked(value == "Tabs"); + ui->spaces->setChecked(value == "Spaces"); + ui->number->setValue(indentationSize); +} + +void IndentationDialog::saveSettings() { + QSettings settings("Remisa", "Notepad--"); // Adjust organization and application name + settings.beginGroup("IndentationSettings"); + settings.setValue("indentationOption", ui->tabs->isChecked() ? "Tabs" : "Spaces"); + settings.setValue("indentationSize", ui->number->value()); + settings.endGroup(); +} + +void IndentationDialog::onOkClicked() { + saveSettings(); // Save settings when OK is clicked + accept(); +} + +void IndentationDialog::setTabsChecked(bool checked) { + ui->tabs->setChecked(checked); +} + +bool IndentationDialog::isTabsChecked() const { + return ui->tabs->isChecked(); +} + +void IndentationDialog::on_buttonBox_accepted() +{ + bool useTabs = ui->tabs->isChecked(); + int indentationWidth = ui->number->value(); + + auto* settings = Settings::instance(); + settings->setValue("IndentationSettings/indentationOption", useTabs ? "Tabs" : "Spaces"); + settings->setValue("IndentationSettings/indentationSize", indentationWidth); + + Document* doc = qobject_cast(parent()); + if (doc && doc->editor()) { + doc->editor()->applyIndentation(useTabs, indentationWidth); + } + Helpers::notImplemented(this); +} + diff --git a/src/indentation/indentationdialog.h b/src/indentation/indentationdialog.h new file mode 100644 index 0000000..55b5320 --- /dev/null +++ b/src/indentation/indentationdialog.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +namespace Ui { +class IndentationDialog; +} + +class IndentationDialog : public QDialog +{ + Q_OBJECT + +public: + explicit IndentationDialog(QWidget *parent = nullptr); + ~IndentationDialog(); + + bool isTabsSelected() const; + int getIndentationValue() const; + void setTabsChecked(bool checked); + bool isTabsChecked() const; + +private slots: + void onIndentationSelected(); + + void on_buttonBox_accepted(); + +private: + Ui::IndentationDialog *ui; + void loadSettings(); + void saveSettings(); + void onOkClicked(); +}; + diff --git a/src/indentation/indentationdialog.ui b/src/indentation/indentationdialog.ui new file mode 100644 index 0000000..5b82ad2 --- /dev/null +++ b/src/indentation/indentationdialog.ui @@ -0,0 +1,123 @@ + + + IndentationDialog + + + + 0 + 0 + 364 + 119 + + + + Dialog + + + + + 4 + 70 + 341 + 41 + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + 184 + 40 + 161 + 26 + + + + 1 + + + + + + 98 + 11 + 71 + 20 + + + + Spaces + + + + + + 30 + 9 + 51 + 23 + + + + Tabs + + + true + + + + + + 32 + 43 + 121 + 17 + + + + <html><head/><body><p><span style=" font-weight:700;">Indentation Width:</span></p></body></html> + + + + + + + buttonBox + accepted() + IndentationDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + IndentationDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/indentation/indentationmanager.cpp b/src/indentation/indentationmanager.cpp new file mode 100644 index 0000000..4ed3543 --- /dev/null +++ b/src/indentation/indentationmanager.cpp @@ -0,0 +1,134 @@ +#include +#include +#include "../mainwindow.h" +#include "indentationmanager.h" + +IndentationManager::IndentationManager(MainWindow* mainWindow, QObject* parent) + : QObject(parent), m_mainWindow(mainWindow) {} + +void IndentationManager::setupIndentationMenu(QAction* customAction, QAction* defaultAction, QAction* smartIndentAction) { + m_actionCustom = customAction; + m_actionDefaultSetting = defaultAction; + + m_actionCustom->setCheckable(true); + m_actionDefaultSetting->setCheckable(true); + + // Create an exclusive QActionGroup for radio behavior + QActionGroup* group = new QActionGroup(this); + group->setExclusive(true); + group->addAction(m_actionCustom); + group->addAction(m_actionDefaultSetting); + + connect(m_actionCustom, &QAction::triggered, this, [this]() { + saveIndentationSetting("Custom"); + }); + connect(m_actionDefaultSetting, &QAction::triggered, this, [this]() { + saveIndentationSetting("Default"); + }); + connect(smartIndentAction, &QAction::toggled, this, &IndentationManager::onSmartIndentTriggered); + loadIndentationSetting(); +} + +void IndentationManager::saveIndentationSetting(const QString& setting) { + auto* settings = Settings::instance(); + settings->setValue("IndentationSettings/indentationSetting", setting); + qDebug() << "Saved indentation setting:" << setting; +} + +void IndentationManager::loadIndentationSetting() { + auto* settings = Settings::instance(); + QString savedSetting = settings->value("IndentationSettings/indentationSetting", "Default").toString(); + + if (savedSetting == "Custom") { + m_actionCustom->setChecked(true); + } else { + m_actionDefaultSetting->setChecked(true); + } + + qDebug() << "Loaded indentation setting:" << savedSetting; +} + +void IndentationManager::onIndentationSelected() { + IndentationDialog dialog; + if (dialog.exec() == QDialog::Accepted) { + bool tabsSelected = dialog.isTabsSelected(); + int indentationValue = dialog.getIndentationValue(); + + qDebug() << "Tabs Selected:" << tabsSelected; + qDebug() << "Indentation Value:" << indentationValue; + + // Save the values to settings + auto* settings = Settings::instance(); + settings->setValue("IndentationSettings/indentationOption", tabsSelected ? "Tabs" : "Spaces"); + settings->setValue("IndentationSettings/indentationSize", indentationValue); + } +} + +void IndentationManager::openIndentationDialog() { + // Only create dialog once and reuse it + if (!m_indentationDialog) { + m_indentationDialog = new IndentationDialog(m_mainWindow); + + // Set up initial settings and connect OK/Cancel buttons only once + connect(m_indentationDialog, &QDialog::accepted, this, [this]() { + bool tabsSelected = m_indentationDialog->isTabsChecked(); + int indentationValue = m_indentationDialog->getIndentationValue(); + + // Save the values to settings + auto* settings = Settings::instance(); + settings->setValue("IndentationSettings/indentationOption", tabsSelected ? "Tabs" : "Spaces"); + settings->setValue("IndentationSettings/indentationSize", indentationValue); + }); + + connect(m_indentationDialog, &QDialog::rejected, m_indentationDialog, &QDialog::close); + } + + // Update dialog's tab checkbox state before showing + m_indentationDialog->setTabsChecked(isTabsSelected()); + m_indentationDialog->show(); +} + +bool IndentationManager::isTabsSelected() const { + auto* settings = Settings::instance(); // Using the singleton settings class + QString indentationOption = settings->value("IndentationSettings/indentationOption", "Tabs").toString(); + return indentationOption == "Tabs"; // Returns true if "Tabs" is the selected option +} + +void IndentationManager::setToDefaultIndentation() { + // Logic to apply the default indentation + auto* settings = Settings::instance(); + settings->setValue("IndentationSettings/indentationSetting", "Default"); + + // Ensure that the default setting is reflected in the UI + if (m_actionDefaultSetting) { + m_actionDefaultSetting->setChecked(true); + } + qDebug() << "Default indentation applied and saved in settings."; +} + +void IndentationManager::loadSmartIndentSetting() { + auto* settings = Settings::instance(); + bool isChecked = settings->value("IndentationSettings/smartIndentEnabled", false).toBool(); // Default to unchecked + m_mainWindow->setSmartIndentChecked(isChecked); +} + +void IndentationManager::saveSmartIndentSetting(bool enabled) { + auto* settings = Settings::instance(); + settings->setValue("IndentationSettings/smartIndentEnabled", enabled); + qDebug() << "Smart Indent setting saved as" << (enabled ? "enabled" : "disabled"); +} + +void IndentationManager::openIndentationDialog(MainWindow* mainWindow) { + IndentationDialog dialog(mainWindow); // Use mainWindow as parent + dialog.exec(); +} + +void IndentationManager::onSmartIndentTriggered(bool checked) { + auto* settings = Settings::instance(); + settings->setValue("IndentationSettings/smartIndentEnabled", checked); + qDebug() << "Smart Indent setting saved:" << checked; +} + + + + diff --git a/src/indentation/indentationmanager.h b/src/indentation/indentationmanager.h new file mode 100644 index 0000000..306bca8 --- /dev/null +++ b/src/indentation/indentationmanager.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include "../settings.h" +#include "indentationdialog.h" + +class MainWindow; + +class IndentationManager : public QObject { + Q_OBJECT + +public: + IndentationManager(MainWindow* mainWindow, QObject* parent = nullptr); + void setupIndentationMenu(QAction* customAction, QAction* defaultAction, QAction* smartIndentAction); + void loadIndentationSetting(); + void saveIndentationSetting(const QString& setting); + void openIndentationDialog(); + bool isTabsSelected() const; + void setToDefaultIndentation(); + void loadSmartIndentSetting(); + void saveSmartIndentSetting(bool enabled); + void openIndentationDialog(MainWindow* mainWindow); + +public slots: + void onIndentationSelected(); + void onSmartIndentTriggered(bool checked); + +private: + QAction* m_actionCustom; + QAction* m_actionDefaultSetting; + MainWindow* m_mainWindow; + IndentationDialog* m_indentationDialog = nullptr; +}; + diff --git a/src/mainwindow.bak.cpp b/src/mainwindow.bak.cpp deleted file mode 100755 index f052243..0000000 --- a/src/mainwindow.bak.cpp +++ /dev/null @@ -1,898 +0,0 @@ -#include "mainwindow.h" -#include "codeeditor.h" -#include "ui_mainwindow.h" -#include "document.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent), ui(new Ui::MainWindow), settings("Remisa", "Notepad--") { - ui->setupUi(this); - qDebug() << "Tab widget pointer: " << ui->documentsTab; - ui->documentsTab->setTabsClosable(true); - - QMenu *menuLanguage = ui->menu_Language; - QMenu *menuZ = new QMenu("z", this); - QAction *actionZ80 = new QAction("Z80", this); - menuZ->addAction(actionZ80); - menuLanguage->addMenu(menuZ); - connect(actionZ80, &QAction::triggered, this, &MainWindow::onActionZ80Triggered); - - QActionGroup *group = new QActionGroup(this); - group->setExclusive(true); // Ensure only one action is checked at a time - - // Add actions to the group - group->addAction(ui->actionWindows_Format); - group->addAction(ui->action_Unix_OS_X_Format); - group->addAction(ui->action_Old_Mac_Format); - - // Optionally, set a default action checked - ui->action_Unix_OS_X_Format->setChecked(true); - - qDebug() << "Setting up UI and clearing existing tabs."; - - // Explicitly remove any existing tabs - while (ui->documentsTab->count() > 0) { - ui->documentsTab->removeTab(0); - } - - ui->documentsTab->setTabsClosable(true); - - connect(ui->documentsTab, &QTabWidget::tabCloseRequested, this, &MainWindow::on_documentsTab_tabCloseRequested); - connect(ui->actionE_xit, &QAction::triggered, this, &MainWindow::on_actionE_xit_triggered); - - connect(ui->action_Undo, &QAction::triggered, this, &MainWindow::on_action_Undo_triggered); - connect(ui->action_Redo, &QAction::triggered, this, &MainWindow::on_action_Redo_triggered); - connect(ui->documentsTab, &QTabWidget::currentChanged, this, [this](int index) { - if (auto *editor = getCurrentEditor()) { - editor->setFocus(); // Ensure focus on current editor - } - }); - - - - qDebug() << "Tabs cleared, preparing to open files."; - - // Get arguments from argv and open files - QStringList arguments = QCoreApplication::arguments(); - - if (arguments.size() <=1) { - Document *newDoc = new Document("", this); // Empty file path for untitled document - ui->documentsTab->addTab(newDoc, "Untitled Document"); - connectSignals(newDoc); - ui->documentsTab->setCurrentWidget(newDoc); - - qDebug() << "Untitled Document created"; - } else { - qDebug() << "Arguments passed: " << arguments; - - for (int i = 1; i < arguments.size(); ++i) { // Skip argv(0), which is the app name - QString filePath = arguments.at(i); - qDebug() << "Opening document: " << filePath; - openDocument(filePath); // Open each file in a new tab - } - } - - // Set up signal connections for all existing tabs/documents - for (int i = 0; i < ui->documentsTab->count(); ++i) { - Document* doc = qobject_cast(ui->documentsTab->widget(i)); - if (doc) { - qDebug() << "Connecting signals for document at tab index:" << i; - connectSignals(doc); // Connect signals to each document - } - } - - qDebug() << "Loaded recent files:" << settings.value("recentFiles").toStringList(); - // Create a QMenu dynamically and assign it to the action - recentFilesMenu = new QMenu("Recent Files", this); - ui->menu_File->insertMenu(ui->actionRecent_Files, recentFilesMenu); - // Remove the placeholder QAction (if not needed anymore) - ui->menu_File->removeAction(ui->actionRecent_Files); - // Load and update recent files - loadRecentFiles(); - updateRecentFilesMenu(); - - qDebug() << "Initialization complete, emitting uiReady signal."; - initialize(); // Initialize UI readiness -} - -MainWindow::~MainWindow() { - settings.setValue("recentFiles", recentFiles); - delete ui; -} - -void MainWindow::closeEvent(QCloseEvent *event) { - saveRecentFiles(); - QMainWindow::closeEvent(event); -} - -void MainWindow::initialize() { - QTimer::singleShot(100, this, [this]() { - qDebug() << "Emitting uiReady signal after 100ms delay"; - qDebug() << "About to emit uiReady signal..."; - emit uiReady(); - }); -} - -void MainWindow::openDocument(const QString &filePath) { - if (!QFile::exists(filePath)) { - qDebug() << "Error: File does not exist: " << filePath; - return; - } - - QString fileName = QFileInfo(filePath).fileName(); - qDebug() << "Opening file: " << filePath; - - // Ensure the file can be opened - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "Error: Unable to open file: " << filePath; - QMessageBox::warning(this, tr("Error"), tr("Failed to open the file.")); - return; - } - - if (ui->documentsTab->count() > 0) { - Document* doc = qobject_cast(ui->documentsTab->widget(0)); - - if (doc && isUntitledDocument(ui->documentsTab->tabText(0))) { - QString content = doc->getEditorContent(); // Retrieve the editor content - if (content.isEmpty()) { // Check if the document is empty - qDebug() << "Closing untitled and empty document."; - ui->documentsTab->removeTab(0); - doc->deleteLater(); // Schedule safe deletion - } else { - qDebug() << "Untitled document is not empty, skipping removal."; - } - } - } - - if (filePath != "") addToRecentFiles(filePath); - // Create a new document and add it as a tab - Document* newDoc = new Document(filePath, this); - ui->documentsTab->addTab(newDoc, fileName); - connectSignals(newDoc); - ui->documentsTab->setCurrentWidget(newDoc); - - qDebug() << "Document added with file path: " << filePath << " and file name: " << fileName; -} - -void MainWindow::on_action_Open_triggered() { - QString filePath = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("Text Files (*.txt);;All Files (*)")); - if (!filePath.isEmpty()) { - openDocument(filePath); - } -} - -void MainWindow::addToRecentFiles(const QString &filePath) { - recentFiles.removeAll(filePath); // Avoid duplicates - recentFiles.prepend(filePath); // Add to the top - - if (recentFiles.size() > 10) { - recentFiles.removeLast(); // Keep only the last 10 items - } - - updateRecentFilesMenu(); // Refresh the menu - qDebug() << "Recent files updated:" << recentFiles; - -} - -void MainWindow::saveRecentFiles() { - QSettings settings("Remisa", "Notepad--"); - settings.setValue("recentFiles", recentFiles); -} - -void MainWindow::updateRecentFilesMenu() { - if (!recentFilesMenu) { - qWarning() << "Recent files menu is not initialized!"; - return; - } - - recentFilesMenu->clear(); // Clear existing items - - // Add recent file actions - for (const QString &filePath : recentFiles) { - QAction *action = new QAction(filePath, this); - connect(action, &QAction::triggered, this, [this, filePath]() { openRecentFile(filePath); }); - recentFilesMenu->addAction(action); - } - - // Add separator and "Clear Recent Files" action - recentFilesMenu->addSeparator(); - QAction *clearAction = new QAction("Clear Recent Files", this); - connect(clearAction, &QAction::triggered, this, &MainWindow::clearRecentFiles); - recentFilesMenu->addAction(clearAction); -} - -void MainWindow::openRecentFile(const QString &filePath) { - // Logic to open the recent file - qDebug() << "Opening recent file:" << filePath; - openDocument(filePath); // Your file opening logic -} - -void MainWindow::clearRecentFiles() { - recentFiles.clear(); - updateRecentFilesMenu(); -} - -void MainWindow::loadRecentFiles() { - QSettings settings("Remisa", "Notepad--"); - recentFiles = settings.value("recentFiles").toStringList(); -} - -bool MainWindow::isUntitledDocument(const QString &title) { - // Static QRegularExpression to avoid repeated creation - static const QRegularExpression regex( - R"((?:&?U&?n&?t&?i&?t&?l&?e&?d&?) (?:&?D&?o&?c&?u&?m&?e&?n&?t))"); - - // Perform the regex match - return regex.match(title).hasMatch(); -} - -void MainWindow::on_action_Save_triggered() { - Document *doc = qobject_cast(ui->documentsTab->currentWidget()); - if (doc) { - int currentIndex = ui->documentsTab->currentIndex(); - if (currentIndex != -1) { - QString title = ui->documentsTab->tabText(currentIndex); - qDebug() << "Command save for Untitled Document, title is: " << title; - if (isUntitledDocument(title)) { - qDebug() << "Save As dialog for Untitled Document Save command, title is: " << title; - QString filePath = QFileDialog::getSaveFileName(this, tr("Save File As"), QString(), - tr("Text Files (*.txt);;All Files (*)")); - - if (filePath.isEmpty()) return; - doc->saveFileAs(filePath); - return; - } - } else { - return; - } - doc->saveFile(); - } else { - QMessageBox::warning(this, tr("Error"), tr("No document to save.")); - } -} - -void MainWindow::on_actionSave_As_triggered() { - Document *doc = qobject_cast(ui->documentsTab->currentWidget()); - if (doc) { - QString filePath = QFileDialog::getSaveFileName(this, tr("Save File As"), "", tr("Text Files (*.txt);;All Files (*)")); - if (!filePath.isEmpty()) { - doc->saveFileAs(filePath); - int tabIndex = ui->documentsTab->indexOf(doc); - if (tabIndex != -1) { - ui->documentsTab->setTabText(tabIndex, doc->fileName()); - } - } - } else { - QMessageBox::warning(this, tr("Error"), tr("No document to save.")); - } -} - -void MainWindow::on_action_New_triggered() { - Document *newDoc = new Document("", this); - ui->documentsTab->addTab(newDoc, "Untitled Document"); - connectSignals(newDoc); - ui->documentsTab->setCurrentWidget(newDoc); -} - -void MainWindow::on_action_Go_to_line_in_editor_triggered() -{ - Document *doc = qobject_cast(ui->documentsTab->currentWidget()); - if (doc) { - doc->goToLineNumberInEditor (); - } else { - QMessageBox::warning(this, tr("Error"), tr("No document open.")); - } -} - -void MainWindow::on_action_Go_to_line_in_text_triggered() { - Document* doc = qobject_cast(ui->documentsTab->currentWidget()); - if (doc) { - doc->goToLineNumberInText(this); - } else { - QMessageBox::warning(this, tr("No Document"), tr("There is no document open.")); - } -} - -void MainWindow::on_action_Close_triggered() -{ - int activeTabIndex = ui->documentsTab->currentIndex(); // Get the index of the active tab - - if (activeTabIndex != -1) { // Check if there's an active tab - on_documentsTab_tabCloseRequested(activeTabIndex); // Reuse the existing close logic - } -} - -void MainWindow::on_actionC_lose_all_triggered() { - closeAllDocuments(); // Call the method to close all documents -} - -void MainWindow::closeAllDocuments() { - int tabCount = ui->documentsTab->count(); - qDebug() << "Attempting to close all tabs. Current tab count:" << tabCount; - - QList docsToClose; - for (int i = 0; i < tabCount; ++i) { - Document* doc = qobject_cast(ui->documentsTab->widget(i)); - if (doc && doc->closeDocument()) { // Check if the document can be closed - docsToClose.append(doc); - } else { - qDebug() << "Skipped closing tab due to unsaved changes."; - } - } - - // Batch remove the collected tabs - for (Document* doc : docsToClose) { - int index = ui->documentsTab->indexOf(doc); - if (index != -1) { - ui->documentsTab->removeTab(index); - doc->deleteLater(); // Safely delete the document - } - } - - qDebug() << "All tabs have been closed."; -} - - -void MainWindow::on_actionC_3_triggered() { - Document *doc = qobject_cast(ui->documentsTab->currentWidget()); - if (doc) { - qDebug() << "Menu action triggered for C++ syntax highlighting"; - doc->applySyntaxHighlighter("C++"); - } else { - QMessageBox::warning(this, tr("Error"), tr("No document to format.")); - } -} - -void MainWindow::on_actionPython_triggered() -{ - Document *doc = qobject_cast(ui->documentsTab->currentWidget()); - if (doc) { - qDebug() << "Menu action triggered for Python syntax highlighting"; - doc->applySyntaxHighlighter("Python"); - } else { - QMessageBox::warning(this, tr("Error"), tr("No document to format.")); - } -} - -void MainWindow::on_actionSav_e_all_triggered() { - int tabCount = ui->documentsTab->count(); - qDebug() << "Save All triggered. Total open tabs:" << tabCount; - - // Iterate over all open tabs - for (int i = 0; i < tabCount; ++i) { - Document *doc = qobject_cast(ui->documentsTab->widget(i)); - if (doc && doc->isModified()) { - qDebug() << "Saving modified document in tab:" << i; - - QString filePath = doc->filePath(); - - // If the document doesn't have a file path, prompt the user to save it - if (filePath.isEmpty()) { - QString title = ui->documentsTab->tabText(i); // Get the current tab title - - QString savePath = QFileDialog::getSaveFileName( - this, - tr("Save %1").arg(title), // Dialog title with current tab title - QString(), // Default path - tr("Text Files (*.txt);;All Files (*)") - ); - - if (savePath.isEmpty()) { - qDebug() << "User canceled save for tab:" << i; - continue; // Skip saving this document - } - - // Update the document's file path - doc->setFilePath(savePath); - - // Directly set the tab title to the new file name - ui->documentsTab->setTabText(i, QFileInfo(savePath).fileName()); - qDebug() << "Updated tab title to:" << QFileInfo(savePath).fileName(); - } - - // Save the document - doc->saveFile(); - } - } - - qDebug() << "Save All completed."; -} - -void MainWindow::on_actionCu_t_triggered() -{ - // TODO: Cut -} - - -void MainWindow::on_action_Copy_triggered() -{ - // TODO: Copy -} - - -void MainWindow::on_action_Paste_triggered() -{ - // TODO: Paste -} - - -void MainWindow::on_action_Undo_triggered() -{ - if (auto *editor = getCurrentEditor()) { - editor->undo(); // Perform undo operation - } -} - - -void MainWindow::on_action_Redo_triggered() -{ - if (auto *editor = getCurrentEditor()) { - editor->redo(); // Perform redo operation - } -} - -CodeEditor* MainWindow::getCurrentEditor() const { - int currentIndex = ui->documentsTab->currentIndex(); - if (currentIndex == -1) return nullptr; // No active tab - return qobject_cast(ui->documentsTab->widget(currentIndex)); -} - -void MainWindow::on_actionZoom_In_triggered() -{ - // TODO: Zoom In -} - - -void MainWindow::on_actionoom_Out_triggered() -{ - // TODO: Zoom Out -} - - -void MainWindow::on_action_Restore_Default_Zoom_triggered() -{ - // TODO: Restore Default Zoom -} - - -void MainWindow::on_action_Word_wrap_triggered() -{ - // TODO: Word Wrap -} - -void MainWindow::onActionZ80Triggered() -{ - qDebug() << "Z80 action triggered!"; -} - -void MainWindow::on_actionAbout_Qt_triggered() -{ - QApplication::aboutQt(); -} - - -void MainWindow::on_action_About_Notepad_triggered() -{ - // TODO: About Remisa Yousefvand -} - -void MainWindow::on_actionOpen_Folder_triggered() { - // Step 1: Open a folder selection dialog - QString folderPath = QFileDialog::getExistingDirectory(this, tr("Select Folder"), QString(), - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - - if (folderPath.isEmpty()) { - qDebug() << "No folder selected."; - return; - } - - // Step 2: Get all files from the selected folder - QDir directory(folderPath); - QStringList fileList = directory.entryList(QDir::Files); - - if (fileList.isEmpty()) { - QMessageBox::information(this, tr("No Files Found"), tr("No files were found in the selected folder.")); - return; - } - - // Step 3: Use QMimeDatabase to check MIME types and open text files - QMimeDatabase mimeDatabase; - bool textFilesFound = false; - - for (const QString &fileName : fileList) { - QString filePath = directory.absoluteFilePath(fileName); - - // Get the MIME type of the file - QMimeType mimeType = mimeDatabase.mimeTypeForFile(filePath); - - // Check if the MIME type is text/plain (or another text-related MIME type) - if (mimeType.name().startsWith("text/")) { - qDebug() << "Opening file with MIME type:" << mimeType.name(); - openDocument(filePath); // This function opens the document in a new tab - textFilesFound = true; - } else { - qDebug() << "Skipping file with MIME type:" << mimeType.name(); - } - } - - if (!textFilesFound) { - QMessageBox::information(this, tr("No Text Files Found"), tr("No text files were found in the selected folder based on MIME types.")); - } -} - -void MainWindow::on_actionSa_ve_a_copy_as_triggered() { - Document *doc = qobject_cast(ui->documentsTab->currentWidget()); - doc->saveAcopyAs(); -} - -void MainWindow::setTabColor(int index, const QString &color) { - if (index < 0 || index >= ui->documentsTab->count()) return; - - ui->documentsTab->tabBar()->setTabTextColor(index, QColor(color)); - ui->documentsTab->tabBar()->update(); // Force repaint - qDebug() << "Set tab color to" << color << "for tab at index:" << index; -} - -void MainWindow::connectSignals(Document *doc) { - if (!doc) return; - - // Connect modification change to apply color coding. - connect(doc->editor(), &QPlainTextEdit::modificationChanged, this, [this, doc](bool changed) { - applyColorCoding(doc, changed); - }); - - // Connect the worker’s save completion signal. - connect(doc->worker(), &FileLoaderWorker::savingFinished, this, [this, doc]() { - applyColorCoding(doc, false); - }); - - // Connect undo and redo actions to the editor. - connect(ui->action_Undo, &QAction::triggered, doc->editor(), &QPlainTextEdit::undo); - connect(ui->action_Redo, &QAction::triggered, doc->editor(), &QPlainTextEdit::redo); - - // Enable/disable the undo and redo actions based on editor state. - connect(doc->editor(), &QPlainTextEdit::undoAvailable, ui->action_Undo, &QAction::setEnabled); - connect(doc->editor(), &QPlainTextEdit::redoAvailable, ui->action_Redo, &QAction::setEnabled); - - // Ensure undo/redo actions are enabled/disabled initially. - ui->action_Undo->setEnabled(doc->editor()->document()->isUndoAvailable()); - ui->action_Redo->setEnabled(doc->editor()->document()->isRedoAvailable()); -} - -void MainWindow::removeTabSafely(int index) { - qDebug() << "Removing tab safely at index:" << index; - - // Ensure the index is still valid after any potential shifts - if (index < 0 || index >= ui->documentsTab->count()) { - qDebug() << "Cannot remove tab, invalid index: " << index; - return; - } - - // Get the document from the current index - Document *doc = qobject_cast(ui->documentsTab->widget(index)); - if (!doc) { - qDebug() << "No document found at index:" << index << " for removal."; - return; - } - - // Remove the tab and schedule the document for safe deletion - ui->documentsTab->removeTab(index); - - QTimer::singleShot(0, this, [doc]() { - qDebug() << "Deleting document after tab closure."; - doc->deleteLater(); // Safely delete the document - }); - - qDebug() << "Tab at index:" << index << " removed. Remaining tabs:" << ui->documentsTab->count(); -} - -void MainWindow::on_documentsTab_tabCloseRequested(int index) { - static bool closingInProgress = false; // Prevent double closing - - if (closingInProgress) { - qDebug() << "Tab close already in progress. Ignoring."; - return; - } - - closingInProgress = true; - - // Use 'this' as the context object to ensure proper signal management. - QTimer::singleShot(0, this, [this, index]() { - if (index >= ui->documentsTab->count()) { - qDebug() << "Invalid tab index: " << index; - closingInProgress = false; - return; - } - - Document* doc = qobject_cast(ui->documentsTab->widget(index)); - if (doc && doc->closeDocument()) { - qDebug() << "Closing tab at index:" << index; - ui->documentsTab->removeTab(index); - doc->deleteLater(); - } else { - qDebug() << "Tab close canceled."; - } - - closingInProgress = false; - }); -} - -void MainWindow::on_actionClose_all_BUT_current_document_triggered() { - int activeTabIndex = ui->documentsTab->currentIndex(); // Get the index of the active tab - int tabCount = ui->documentsTab->count(); - - if (activeTabIndex == -1 || tabCount <= 1) { - qDebug() << "No tabs to close or only one active tab."; - return; - } - - qDebug() << "Closing all tabs except the active tab at index:" << activeTabIndex; - - // Collect documents to close except the active one - QList docsToClose; - for (int i = 0; i < tabCount; ++i) { - if (i != activeTabIndex) { - Document* doc = qobject_cast(ui->documentsTab->widget(i)); - if (doc && doc->closeDocument()) { // Check if the document can be closed - docsToClose.append(doc); - } else { - qDebug() << "Skipped closing tab due to unsaved changes."; - } - } - } - - // Batch remove the collected tabs - for (Document* doc : docsToClose) { - int index = ui->documentsTab->indexOf(doc); - if (index != -1) { - ui->documentsTab->removeTab(index); - doc->deleteLater(); // Safely delete the document - } - } - - qDebug() << "All tabs except the active one have been closed."; -} - -void MainWindow::on_actionSave_session_triggered() { - QString filePath = QFileDialog::getSaveFileName( - this, tr("Save Session"), "", tr("JSON Files (*.json);;All Files (*)")); - - if (filePath.isEmpty()) return; - - QJsonArray tabsArray; - - for (int i = 0; i < ui->documentsTab->count(); ++i) { - Document* doc = qobject_cast(ui->documentsTab->widget(i)); - if (doc) { - QJsonObject tabData; - - // Ensure correct order: filePath -> isModified -> cursorPosition -> content - tabData["filePath"] = doc->filePath(); - tabData["isModified"] = doc->isModified(); - tabData["cursorPosition"] = doc->editor()->textCursor().position(); - - QString content = doc->isModified() ? doc->editor()->toPlainText() : ""; - tabData["content"] = content; // Ensure content is added last - - tabsArray.append(tabData); - } - } - - QJsonObject sessionData; - sessionData["activeTab"] = ui->documentsTab->currentIndex(); - sessionData["tabs"] = tabsArray; - - QJsonDocument doc(sessionData); - QFile file(filePath); - if (file.open(QIODevice::WriteOnly)) { - file.write(doc.toJson(QJsonDocument::Indented)); - file.close(); - } -} - -void MainWindow::applyColorCoding(Document* doc, bool isModified) { - int index = ui->documentsTab->indexOf(doc); - if (index == -1) return; // Invalid tab index - - QColor tabColor = isModified ? Qt::red : QColor(0, 100, 0); // Dark Green for saved - - ui->documentsTab->tabBar()->setTabTextColor(index, tabColor); - qDebug() << "Applied color" << tabColor.name() << "to tab index:" << index; -} - -void MainWindow::restoreCursorPosition(Document *doc, int position) { - QTimer::singleShot(0, doc->editor(), [doc, position]() { - QTextCursor cursor = doc->editor()->textCursor(); - cursor.setPosition(position); - doc->editor()->setTextCursor(cursor); - doc->editor()->ensureCursorVisible(); - }); -} - -void MainWindow::on_actionLoad_session_triggered() { - QString filePath = QFileDialog::getOpenFileName( - this, tr("Load Session"), "", tr("JSON Files (*.json);;All Files (*)")); - - if (filePath.isEmpty()) return; - - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly)) return; - - QByteArray sessionData = file.readAll(); - QJsonDocument jsonDoc = QJsonDocument::fromJson(sessionData); - QJsonObject rootObj = jsonDoc.object(); - - closeAllDocuments(); // Close all existing tabs before restoring the session - - QJsonArray tabsArray = rootObj["tabs"].toArray(); - int activeTabIndex = rootObj["activeTab"].toInt(); - - for (int i = 0; i < tabsArray.size(); ++i) { - QJsonObject tabData = tabsArray[i].toObject(); - loadTabFromSession(tabData); - } - - ui->documentsTab->setCurrentIndex(activeTabIndex); -} - -void MainWindow::loadTabFromSession(const QJsonObject &tabData) { - QString filePath = tabData["filePath"].toString(); - bool isModified = tabData["isModified"].toBool(); - int cursorPosition = tabData["cursorPosition"].toInt(); - QString content = tabData["content"].toString(); - - qDebug() << "\n==== Restoring Tab from Session ===="; - qDebug() << "File Path:" << filePath; - qDebug() << "Is Modified:" << isModified; - qDebug() << "Cursor Position:" << cursorPosition; - - Document *newDoc = nullptr; - QString tabTitle; - - // Case 1: Untitled Document (no path) - if (filePath.isEmpty()) { - newDoc = new Document("", this); - newDoc->editor()->setPlainText(content); - newDoc->setModified(isModified); - tabTitle = "Untitled Document"; - } - // Case 2: Modified Document with Path (use session content) - else if (isModified) { - newDoc = new Document(filePath, this); - newDoc->editor()->setPlainText(""); - newDoc->editor()->appendPlainText(content); - newDoc->setModified(true); - tabTitle = newDoc->fileName(); - } - // Case 3: Unmodified Document with Path (load from path) - else { - newDoc = new Document(filePath, this); - tabTitle = newDoc->fileName(); - } - - int tabIndex = ui->documentsTab->addTab(newDoc, tabTitle); - applyColorCoding(newDoc, isModified); - ui->documentsTab->setCurrentIndex(tabIndex); - - // Restore the cursor only after the document loading is completed - connect(newDoc->worker(), &FileLoaderWorker::loadingFinished, this, [this, newDoc, cursorPosition]() { - qDebug() << "Worker thread finished loading document."; - - QTextCursor cursor = newDoc->editor()->textCursor(); - int docLength = newDoc->editor()->document()->characterCount(); - - // Set the cursor to the saved position or move to the end if out of bounds - if (cursorPosition >= 0 && cursorPosition <= docLength) { - cursor.setPosition(cursorPosition); - newDoc->editor()->setTextCursor(cursor); - qDebug() << "Cursor successfully restored to position:" << cursor.position(); - } else { - qDebug() << "Cursor position" << cursorPosition << "out of bounds, moving to end."; - newDoc->editor()->moveCursor(QTextCursor::End); - } - - // Ensure UI updates are applied - newDoc->editor()->ensureCursorVisible(); - newDoc->editor()->update(); - }); - - // Connect all required signals for the document - connectSignals(newDoc); - - qDebug() << "Connected signals for tab with title:" << tabTitle; - qDebug() << "==== Tab Restoration Complete ===="; -} - -void MainWindow::on_action_Print_triggered() { - // Create a printer object - QPrinter printer; - - // Show a print dialog to the user - QPrintDialog printDialog(&printer, this); - printDialog.setWindowTitle("Print Document"); - - // Check if the user accepted the dialog - if (printDialog.exec() != QDialog::Accepted) { - QMessageBox::information(this, "Print", "Printing was canceled."); - return; - } - - // Get the currently active document from the tab widget - int currentTabIndex = ui->documentsTab->currentIndex(); - if (currentTabIndex == -1) { - QMessageBox::warning(this, "Print Error", "No document to print."); - return; - } - - Document *currentDoc = qobject_cast(ui->documentsTab->widget(currentTabIndex)); - if (!currentDoc) { - QMessageBox::warning(this, "Print Error", "Failed to retrieve the document."); - return; - } - - // Print the content of the editor associated with the current document - QTextDocument *textDoc = currentDoc->editor()->document(); - textDoc->print(&printer); - - QMessageBox::information(this, "Print", "Document printed successfully."); -} - - -void MainWindow::on_actionE_xit_triggered() -{ - qDebug() << "Exit triggered, checking for worker thread activity..."; - // Access the worker thread through one of the documents - auto* document = qobject_cast(ui->documentsTab->widget(0)); // Assuming at least one document exists - if (document) { - QThread* workerThread = document->workerThread(); - if (workerThread && workerThread->isRunning()) { - qDebug() << "Worker thread is running. Waiting for it to finish..."; - // Show a message to the user if necessary - QMessageBox::information(this, "Exiting", - "Please wait while the application completes pending operations..."); - - // Request the worker thread to quit gracefully - workerThread->quit(); - - // Wait for the thread to finish with a timeout of 5 seconds - if (!workerThread->wait(5000)) { - qDebug() << "Worker thread did not respond. Forcing termination..."; - workerThread->terminate(); // Force terminate if not responsive - workerThread->wait(); - } - } - } - - // Ensure all recent files are saved before exiting - saveRecentFiles(); - - qDebug() << "Exiting application..."; - QCoreApplication::quit(); // Gracefully exit the application -} - diff --git a/src/mainwindow.bak.h b/src/mainwindow.bak.h deleted file mode 100755 index 14a4dbb..0000000 --- a/src/mainwindow.bak.h +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include "document.h" -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -namespace Ui { class MainWindow; } -QT_END_NAMESPACE - -class MainWindow : public QMainWindow { - Q_OBJECT - -public: - MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - void restoreCursorPosition(Document* doc, int position); - -protected: - void closeEvent(QCloseEvent *event) override; // Override close event - -signals: - void uiReady(); - -public slots: - void notifyUIReady() { - emit uiReady(); - } - - -private slots: - void on_action_Open_triggered(); - void on_action_Save_triggered(); - void on_actionSave_As_triggered(); - void on_documentsTab_tabCloseRequested(int index); - void on_action_New_triggered(); - void on_action_Go_to_line_in_editor_triggered(); - void on_action_Go_to_line_in_text_triggered(); - void on_action_Close_triggered(); - void on_actionC_lose_all_triggered(); - void on_actionC_3_triggered(); - void on_actionPython_triggered(); - void onActionZ80Triggered(); - - void on_actionSav_e_all_triggered(); - - void on_actionCu_t_triggered(); - - void on_action_Copy_triggered(); - - void on_action_Paste_triggered(); - - void on_action_Undo_triggered(); - - void on_action_Redo_triggered(); - - void on_actionZoom_In_triggered(); - - void on_actionoom_Out_triggered(); - - void on_action_Restore_Default_Zoom_triggered(); - - void on_action_Word_wrap_triggered(); - - void on_actionAbout_Qt_triggered(); - - void on_action_About_Notepad_triggered(); - - void on_actionOpen_Folder_triggered(); - - void on_actionSa_ve_a_copy_as_triggered(); - - void on_actionClose_all_BUT_current_document_triggered(); - - void on_actionSave_session_triggered(); - - void on_actionLoad_session_triggered(); - - void on_action_Print_triggered(); - - void openRecentFile(const QString &filePath); // Open a file from recent files - - void clearRecentFiles(); // Clear all recent files - - void on_actionE_xit_triggered(); - -private: - Ui::MainWindow *ui; - void initialize(); - void openDocument(const QString &filePath); - void closeAllDocuments(); - void removeTabSafely(int index); - int findUntitledDocumentIndex(); - void setTabColor(int index, const QString& color); - void connectSignals(Document* doc); - bool isUntitledDocument(const QString &title); - void applyColorCoding(Document* doc, bool isModified); - void loadTabFromSession(const QJsonObject &tabData); - QStringList recentFiles; // List of recent files - QSettings settings; // Store recent files inside the application - QMenu *recentFilesMenu = nullptr; // Pointer to the Recent Files submenu - void addToRecentFiles(const QString &filePath); // Add new file path - void updateRecentFilesMenu(); // Refresh submenu dynamically - void loadRecentFiles(); // Load recent files from settings - void saveRecentFiles(); // Save recent files to settings - CodeEditor* getCurrentEditor() const; -}; - diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 609b0ae..f2d871c 100755 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,19 +1,22 @@ #include +#include #include #include #include #include "mainwindow.h" #include "codeeditor.h" +#include "settings.h" #include "mainwindow/textoperations.h" #include "mainwindow/recentfiles.h" #include "mainwindow/session.h" -#include "ui_mainwindow.h" +#include "src/ui_mainwindow.h" #include "mainwindow/helpers.h" +#include "indentation/indentationdialog.h" MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), - fileOperations(new FileOperations(this, this)) { + indentationManager(new IndentationManager(this)) { qDebug() << "Initializing MainWindow..."; @@ -25,6 +28,9 @@ MainWindow::MainWindow(QWidget* parent) fileOperations = new FileOperations(this); textOperations = new TextOperations(ui->documentsTab); + indentationManager = new IndentationManager(this, this); + indentationManager->setupIndentationMenu(ui->action_Custom, ui->action_Default_Setting, ui->smartIndent); + indentationManager->loadSmartIndentSetting(); ui->actionRecent_Files->setVisible(false); RecentFiles::instance().loadRecentFiles(); @@ -191,6 +197,12 @@ void MainWindow::on_actionCopy_Directory_to_Clipboard_triggered() fileOperations->copyDirectoryPathToClipboard(); } +// helper function +FileOperations* MainWindow::getFileOperations() const +{ + return fileOperations; +} + void MainWindow::on_action_UPPERCASE_triggered() { textOperations->convertToUpperCase(); @@ -221,18 +233,73 @@ void MainWindow::on_actionMove_Line_Down_triggered() textOperations->moveLineDown(); } +void MainWindow::on_action_Trim_Trailing_Space_triggered() +{ + formatting->trimTrailingSpace(); +} +void MainWindow::on_actionTrim_Leading_Space_triggered() +{ + formatting->trimLeadingSpace(); +} +void MainWindow::on_actionTrim_Leading_and_Trailing_Space_triggered() +{ + formatting->trimLeadingAndTrailingSpace(); +} +void MainWindow::on_action_EOL_to_Space_triggered() +{ + formatting->eolToSpace(); +} +void MainWindow::on_actionTab_to_Space_triggered() +{ + formatting->tabToSpace(2); // TODO: Number of spaces is hardcoded. +} +void MainWindow::on_action_Space_to_TAB_all_triggered() +{ + Helpers::notImplemented(this); + // formatting->spaceToTab(2); // FIXME: Various methods doesn't work +} +void MainWindow::on_actionS_pace_to_Tab_Leading_triggered() +{ + Helpers::notImplemented(this); + // formatting->spaceToTabLeading(2); // FIXME: Various methods doesn't work +} +void MainWindow::on_action_Default_Setting_triggered() { + // Code to handle Default Setting selection + indentationManager->setToDefaultIndentation(); + saveIndentationSetting("Default"); + qDebug() << "Default indentation setting applied."; +} +void MainWindow::on_action_Custom_triggered() +{ + if (indentationManager) indentationManager->openIndentationDialog(); +} +void MainWindow::on_smartIndent_triggered() +{ + Helpers::notImplemented(this); + bool isChecked = isSmartIndentChecked(); + indentationManager->saveSmartIndentSetting(isChecked); +} +// helper function +void MainWindow::setSmartIndentChecked(bool checked) { + ui->smartIndent->setChecked(checked); +} +// helper function +bool MainWindow::isSmartIndentChecked() const { + return ui->smartIndent->isChecked(); +} +/* Search Menu */ @@ -261,19 +328,59 @@ void MainWindow::on_actionMove_Line_Down_triggered() +void MainWindow::onActionZ80Triggered() +{ + qDebug() << "Z80 action triggered!"; +} +// helper function +void MainWindow::connectSignals(Document *doc) +{ + if (!doc) return; + // Connect modification change to apply color coding. + connect(doc->editor(), &QPlainTextEdit::modificationChanged, this, [this, doc](bool changed) { + applyColorCoding(doc, changed); + }); + // Connect the worker’s save completion signal. + connect(doc->worker(), &FileLoaderWorker::savingFinished, this, [this, doc]() { + applyColorCoding(doc, false); + }); + // Connect undo and redo actions to the editor. + connect(ui->action_Undo, &QAction::triggered, doc->editor(), &QPlainTextEdit::undo); + connect(ui->action_Redo, &QAction::triggered, doc->editor(), &QPlainTextEdit::redo); + // Enable/disable the undo and redo actions based on editor state. + connect(doc->editor(), &QPlainTextEdit::undoAvailable, ui->action_Undo, &QAction::setEnabled); + connect(doc->editor(), &QPlainTextEdit::redoAvailable, ui->action_Redo, &QAction::setEnabled); + // Ensure undo/redo actions are enabled/disabled initially. + ui->action_Undo->setEnabled(doc->editor()->document()->isUndoAvailable()); + ui->action_Redo->setEnabled(doc->editor()->document()->isRedoAvailable()); +} +// helper function +void MainWindow::applyColorCoding(Document* doc, bool isModified) +{ + int index = ui->documentsTab->indexOf(doc); + if (index == -1) return; // Invalid tab index + QColor tabColor = isModified ? Qt::red : QColor(0, 100, 0); // Dark Green for saved + ui->documentsTab->tabBar()->setTabTextColor(index, tabColor); + qDebug() << "Applied color" << tabColor.name() << "to tab index:" << index; +} +void MainWindow::saveIndentationSetting(const QString& setting) { + auto* settings = Settings::instance(); // Use the singleton Settings instance + settings->setValue("IndentationSettings/indentationSetting", setting); + qDebug() << "Saved indentation setting:" << setting; +} @@ -311,67 +418,6 @@ void MainWindow::on_actionMove_Line_Down_triggered() -FileOperations* MainWindow::getFileOperations() const -{ - return fileOperations; -} - -void MainWindow::onActionZ80Triggered() -{ - qDebug() << "Z80 action triggered!"; -} - - - - - - - - - -void MainWindow::connectSignals(Document *doc) -{ - if (!doc) return; - - // Connect modification change to apply color coding. - connect(doc->editor(), &QPlainTextEdit::modificationChanged, this, [this, doc](bool changed) { - applyColorCoding(doc, changed); - }); - - // Connect the worker’s save completion signal. - connect(doc->worker(), &FileLoaderWorker::savingFinished, this, [this, doc]() { - applyColorCoding(doc, false); - }); - - // Connect undo and redo actions to the editor. - connect(ui->action_Undo, &QAction::triggered, doc->editor(), &QPlainTextEdit::undo); - connect(ui->action_Redo, &QAction::triggered, doc->editor(), &QPlainTextEdit::redo); - - // Enable/disable the undo and redo actions based on editor state. - connect(doc->editor(), &QPlainTextEdit::undoAvailable, ui->action_Undo, &QAction::setEnabled); - connect(doc->editor(), &QPlainTextEdit::redoAvailable, ui->action_Redo, &QAction::setEnabled); - - // Ensure undo/redo actions are enabled/disabled initially. - ui->action_Undo->setEnabled(doc->editor()->document()->isUndoAvailable()); - ui->action_Redo->setEnabled(doc->editor()->document()->isRedoAvailable()); -} - - - - -void MainWindow::applyColorCoding(Document* doc, bool isModified) -{ - int index = ui->documentsTab->indexOf(doc); - if (index == -1) return; // Invalid tab index - - QColor tabColor = isModified ? Qt::red : QColor(0, 100, 0); // Dark Green for saved - - ui->documentsTab->tabBar()->setTabTextColor(index, tabColor); - qDebug() << "Applied color" << tabColor.name() << "to tab index:" << index; -} - - - diff --git a/src/mainwindow.h b/src/mainwindow.h index ad58442..e7f8caa 100755 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1,11 +1,15 @@ #pragma once +#include +#include +#include #include #include "document.h" #include "mainwindow/helpers.h" #include "mainwindow/formatting.h" #include "mainwindow/fileoperations.h" #include "mainwindow/textoperations.h" +#include "indentation/indentationmanager.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -26,6 +30,8 @@ class MainWindow : public QMainWindow { Ui::MainWindow* getUi() const; void connectSignals(Document* doc); FileOperations* getFileOperations() const; + void setSmartIndentChecked(bool checked); + bool isSmartIndentChecked() const; protected: void closeEvent(QCloseEvent* event) override; @@ -91,6 +97,26 @@ private slots: void on_actionMove_Line_Down_triggered(); + void on_action_Trim_Trailing_Space_triggered(); + + void on_actionTrim_Leading_Space_triggered(); + + void on_actionTrim_Leading_and_Trailing_Space_triggered(); + + void on_action_EOL_to_Space_triggered(); + + void on_actionTab_to_Space_triggered(); + + void on_action_Space_to_TAB_all_triggered(); + + void on_actionS_pace_to_Tab_Leading_triggered(); + + void on_action_Default_Setting_triggered(); + + void on_action_Custom_triggered(); + + void on_smartIndent_triggered(); + private: Ui::MainWindow* ui; FileOperations* fileOperations; @@ -101,4 +127,12 @@ private slots: Formatting* formatting; RecentFiles* recentFiles; void applyColorCoding(Document* doc, bool isModified); + + void setupIndentationMenu(); + QAction* action_Custom; + QAction* action_Default_Setting; + + void saveIndentationSetting(const QString& setting); // Save the selected option + void loadIndentationSetting(); // Load and apply the saved setting + IndentationManager* indentationManager; }; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index d523a30..8ea6998 100755 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -135,7 +135,7 @@ - + @@ -1870,7 +1870,7 @@ &Custom... - + true diff --git a/src/mainwindow/formatting.cpp b/src/mainwindow/formatting.cpp index af68258..298a960 100644 --- a/src/mainwindow/formatting.cpp +++ b/src/mainwindow/formatting.cpp @@ -1,8 +1,9 @@ #include #include +#include #include "formatting.h" #include "../mainwindow.h" -#include "settings.h" +#include "../settings.h" #include "helpers.h" #include "../codeeditor.h" @@ -107,6 +108,229 @@ void Formatting::applyEOL(EOLType eolType) { doc->setModified(true); } +void Formatting::trimTrailingSpace() { + Document* doc = Helpers::getCurrentDocument(m_documentsTab); + if (!doc) return; // Ensure document is valid + + QTextDocument* textDoc = doc->editor()->document(); + QTextCursor cursor(textDoc); + + cursor.beginEditBlock(); // Group all changes into a single undo step + + for (QTextBlock block = textDoc->begin(); block != textDoc->end(); block = block.next()) { + QString trimmedText = block.text().trimmed(); // Remove trailing spaces + cursor.setPosition(block.position()); + cursor.select(QTextCursor::LineUnderCursor); + cursor.insertText(trimmedText); + } + + cursor.endEditBlock(); // End the grouped undo step +} + +void Formatting::trimLeadingSpace() { + // Use a static QRegularExpression to avoid repeated creation. + static const QRegularExpression leadingSpaceRegex("^\\s+"); + + // Get the current document using helper function. + Document* doc = Helpers::getCurrentDocument(m_documentsTab); + if (!doc) return; // Ensure the document is valid. + + QTextDocument* textDoc = doc->editor()->document(); + QTextCursor cursor(textDoc); + + cursor.beginEditBlock(); // Begin grouped undo step. + + // Iterate over all blocks (lines) in the document. + for (QTextBlock block = textDoc->begin(); block != textDoc->end(); block = block.next()) { + QString text = block.text(); + + // Use the static QRegularExpression to trim leading spaces. + QString trimmedText = text.remove(leadingSpaceRegex); + + cursor.setPosition(block.position()); + cursor.select(QTextCursor::LineUnderCursor); + cursor.insertText(trimmedText); + } + + cursor.endEditBlock(); // End grouped undo step. +} + +void Formatting::trimLeadingAndTrailingSpace() { + // Use a static QRegularExpression to avoid unnecessary creation. + static const QRegularExpression leadingTrailingSpaceRegex("^\\s+|\\s+$"); + + // Get the current document using the helper function. + Document* doc = Helpers::getCurrentDocument(m_documentsTab); + if (!doc) return; // Ensure the document is valid. + + QTextDocument* textDoc = doc->editor()->document(); + QTextCursor cursor(textDoc); + + cursor.beginEditBlock(); // Begin grouped undo step. + + // Iterate over all lines (blocks) in the document. + for (QTextBlock block = textDoc->begin(); block != textDoc->end(); block = block.next()) { + QString text = block.text(); + + // Use the static regular expression to trim both leading and trailing spaces. + QString trimmedText = text.remove(leadingTrailingSpaceRegex); + + cursor.setPosition(block.position()); + cursor.select(QTextCursor::LineUnderCursor); + cursor.insertText(trimmedText); + } + + cursor.endEditBlock(); // End grouped undo step. +} + +void Formatting::eolToSpace() { + // Get the current document using the helper function. + Document* doc = Helpers::getCurrentDocument(m_documentsTab); + if (!doc) return; // Ensure the document is valid. + + QTextDocument* textDoc = doc->editor()->document(); + QString content = textDoc->toPlainText(); // Retrieve the entire text as plain text. + + // Replace all EOL characters (Windows, Unix, OldMac) with spaces. + content.replace("\r\n", " ") // Windows EOL + .replace('\n', ' ') // Unix EOL + .replace('\r', ' '); // Old Mac EOL + + // Replace the document's content with the modified content. + QTextCursor cursor(textDoc); + cursor.beginEditBlock(); // Start grouped undo step. + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); // Clear existing text. + cursor.insertText(content); // Insert modified text. + cursor.endEditBlock(); // End grouped undo step. +} + +void Formatting::tabToSpace(int spaces) { + if (spaces <= 0) { + qDebug() << "Invalid number of spaces. Must be greater than 0."; + return; + } + + // Get the current document + Document* doc = Helpers::getCurrentDocument(m_documentsTab); + if (!doc) { + qDebug() << "No active document."; + return; + } + // Access the text editor + auto* editor = doc->editor(); + if (!editor) { + qDebug() << "No valid editor found."; + return; + } + + // Create the space string dynamically + QString spaceString(spaces, ' '); + + // Use a QTextCursor to navigate through the document content + QTextCursor cursor(editor->textCursor()); + cursor.movePosition(QTextCursor::Start); + + while (!cursor.atEnd()) { + cursor.select(QTextCursor::LineUnderCursor); + QString lineText = cursor.selectedText(); + + // Replace tabs with spaces + QString modifiedLine = lineText.replace("\t", spaceString); + + // Replace the line in the document + cursor.insertText(modifiedLine); + cursor.movePosition(QTextCursor::NextBlock); + } + + qDebug() << "Replaced all tabs with" << spaces << "spaces."; +} + +void Formatting::spaceToTab(int spaces) { + if (spaces <= 0) { + qDebug() << "Invalid number of spaces. Must be greater than 0."; + return; + } + + // Get the active document and its editor + Document* doc = Helpers::getCurrentDocument(m_documentsTab); + if (!doc) { + qDebug() << "No active document."; + return; + } + + QPlainTextEdit* editor = doc->editor(); + if (!editor) { + qDebug() << "No valid editor found."; + return; + } + + // Create the space string to match and replace + QString spaceString(spaces, ' '); + + // Start an edit block to batch changes (improves undo/redo performance) + QTextCursor cursor(editor->document()); + cursor.beginEditBlock(); + + // Iterate through each block (line) in the document + for (QTextBlock block = editor->document()->begin(); block.isValid(); block = block.next()) { + QString lineText = block.text(); + // Replace all occurrences of the specified number of spaces with a tab + QString modifiedLine = lineText.replace(spaceString, "\t"); + + // Update the block content + cursor.setPosition(block.position()); + cursor.select(QTextCursor::LineUnderCursor); + cursor.insertText(modifiedLine); + } + + cursor.endEditBlock(); // End the edit block + + qDebug() << "Replaced every" << spaces << "spaces with tabs."; +} + +void Formatting::spaceToTabLeading(int spaces) { + if (spaces <= 0) { + qDebug() << "Invalid number of spaces. Must be greater than 0."; + return; + } + + // Get the current document + Document* doc = Helpers::getCurrentDocument(m_documentsTab); + if (!doc) { + Helpers::showInformationMessage("No active document."); + return; + } + + // Access the text editor + auto* editor = doc->editor(); + if (!editor) { + Helpers::showInformationMessage("No valid editor found."); + return; + } + + // Create the space pattern for leading spaces + QString spacePattern = QString("^%1").arg(QString(spaces, ' ')); + + // Prepare the text cursor to modify the document + QTextCursor cursor(editor->document()); + cursor.beginEditBlock(); // Start an edit block for batch operations + + while (!cursor.atEnd()) { + cursor.select(QTextCursor::LineUnderCursor); + QString lineText = cursor.selectedText(); + + // Replace leading spaces with tabs + QString modifiedLine = lineText.replace(QRegularExpression(spacePattern), "\t"); + + // Update the line with the modified text + cursor.insertText(modifiedLine); + cursor.movePosition(QTextCursor::NextBlock); + } + + cursor.endEditBlock(); // End the edit block + qDebug() << "Replaced leading spaces with tabs."; +} diff --git a/src/mainwindow/formatting.h b/src/mainwindow/formatting.h index f15cdb0..d969621 100644 --- a/src/mainwindow/formatting.h +++ b/src/mainwindow/formatting.h @@ -17,6 +17,13 @@ class Formatting : public QObject { Q_ENUM(EOLType) void applyEOL(EOLType eolType); void setupActions(QAction* windowsAction, QAction* unixAction, QAction* oldMacAction); + void trimTrailingSpace(); + void trimLeadingSpace(); + void trimLeadingAndTrailingSpace(); + void eolToSpace(); + void tabToSpace(int spaces); + void spaceToTab(int spaces); + void spaceToTabLeading(int spaces); private: MainWindow* m_mainWindow; diff --git a/src/mainwindow/helpers.cpp b/src/mainwindow/helpers.cpp index 679a795..0d08099 100644 --- a/src/mainwindow/helpers.cpp +++ b/src/mainwindow/helpers.cpp @@ -110,6 +110,15 @@ Document* Helpers::getCurrentDocument(QTabWidget* documentsTab) { return qobject_cast(documentsTab->widget(currentIndex)); } +void Helpers::showInformationMessage(const QString& message) { + QMessageBox::information(nullptr, "Information", message, QMessageBox::Ok); +} + +void Helpers::notImplemented(QWidget* parent) { + QString hardcodedMessage = "Sorry, this option is not available now.\nIt will be implemented in future versions."; + QMessageBox::information(parent, "Information", hardcodedMessage, QMessageBox::Ok); +} + diff --git a/src/mainwindow/helpers.h b/src/mainwindow/helpers.h index d1296cf..a561dc6 100644 --- a/src/mainwindow/helpers.h +++ b/src/mainwindow/helpers.h @@ -4,7 +4,8 @@ #include #include #include -#include +#include +#include #include #include "../document.h" @@ -19,6 +20,8 @@ class Helpers { static void zMenu(QMenu* menuLanguage, QObject* receiver); void Print(QTabWidget* documentsTab, QWidget* parent); static Document* getCurrentDocument(QTabWidget* documentsTab); + static void showInformationMessage(const QString& message); + static void notImplemented(QWidget* parent = nullptr); private: bool validateDocument(Document* doc, QWidget* parent); diff --git a/src/mainwindow/recentfiles.cpp b/src/mainwindow/recentfiles.cpp index 4a9d8e8..c256e3e 100644 --- a/src/mainwindow/recentfiles.cpp +++ b/src/mainwindow/recentfiles.cpp @@ -8,7 +8,7 @@ #include "recentfiles.h" #include "../mainwindow.h" #include "fileoperations.h" -#include "settings.h" +#include "../settings.h" RecentFiles& RecentFiles::instance() { static RecentFiles instance; diff --git a/src/mainwindow/textoperations.cpp b/src/mainwindow/textoperations.cpp index b6892fa..5f2a7ff 100644 --- a/src/mainwindow/textoperations.cpp +++ b/src/mainwindow/textoperations.cpp @@ -8,7 +8,7 @@ #include "../codeeditor.h" #include "textoperations.h" #include "helpers.h" -#include "settings.h" +#include "../settings.h" TextOperations::TextOperations(QTabWidget* documentsTab) : m_documentsTab(documentsTab) { diff --git a/src/mainwindow/settings.cpp b/src/settings.cpp similarity index 95% rename from src/mainwindow/settings.cpp rename to src/settings.cpp index 56818a2..63d1f0d 100644 --- a/src/mainwindow/settings.cpp +++ b/src/settings.cpp @@ -1,5 +1,5 @@ #include "settings.h" -#include "../mainwindow.h" +#include "mainwindow.h" // Initialize the singleton instance to nullptr Settings* Settings::s_instance = nullptr; diff --git a/src/mainwindow/settings.h b/src/settings.h similarity index 100% rename from src/mainwindow/settings.h rename to src/settings.h