diff --git a/CMakeLists.txt b/CMakeLists.txt index 75eb2f2..b1599e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,11 +56,13 @@ add_executable(${TARGET_NAME} src/CodeEditor.cpp src/Syntax.cpp src/Tree.cpp + src/FileManager.cpp include/MainWindow.h include/CodeEditor.h include/Syntax.h include/Tree.h include/LineNumberArea.h + include/FileManager.h ) qt_add_resources(APP_RESOURCES resources.qrc) diff --git a/include/CodeEditor.h b/include/CodeEditor.h index a0e04f2..dd8afa8 100644 --- a/include/CodeEditor.h +++ b/include/CodeEditor.h @@ -3,6 +3,16 @@ #include #include +class FileManager; // Forward declaration + +/** + * @class CodeEditor + * @brief A custom code editor widget that extends QPlainTextEdit. + * + * The CodeEditor class provides a code editor with line number area, syntax highlighting, + * and basic editing modes (NORMAL and INSERT). It emits signals for status messages and + * handles key press and resize events. + */ class CodeEditor : public QPlainTextEdit { Q_OBJECT @@ -18,8 +28,6 @@ class CodeEditor : public QPlainTextEdit Mode mode = NORMAL; void lineNumberAreaPaintEvent(QPaintEvent *event); int lineNumberAreaWidth(); - QString getCurrentFileName() const { return m_currentFileName; } - void setCurrentFileName(const QString &fileName) { m_currentFileName = fileName; } signals: void statusMessageChanged(const QString &message); @@ -35,9 +43,8 @@ private slots: private: QWidget *m_lineNumberArea; - QString m_currentFileName; + FileManager *m_fileManager; - QString getFileExtension(); void addLanguageSymbol(QTextCursor &cursor, const QString &commentSymbol); void commentSelection(QTextCursor &cursor, const QString &commentSymbol); void commentLine(QTextCursor &cursor, const QString &commentSymbol); diff --git a/include/FileManager.h b/include/FileManager.h new file mode 100644 index 0000000..160026f --- /dev/null +++ b/include/FileManager.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +class CodeEditor; +class MainWindow; + +/** + * @class FileManager + * @brief Manages file operations such as creating, saving, and opening files. + * + * The FileManager class is a singleton that handles multiple file-related operations + * within the application. It interacts with the CodeEditor and MainWindow classes + * to perform tasks such as creating new files, saving existing files, and opening + * files from the filesystem. The class ensures that only one instance of FileManager + * exists and provides a global point of access to it. + */ +class FileManager : public QObject +{ + Q_OBJECT + +public: + static FileManager &getInstance(CodeEditor *editor = nullptr, MainWindow *mainWindow = nullptr) + { + static FileManager instance(editor, mainWindow); + return instance; + } + + FileManager(const FileManager &) = delete; + FileManager &operator=(const FileManager &) = delete; + + QString getFileExtension() const; + QString getCurrentFileName() const; + + void setCurrentFileName(const QString fileName); + void initialize(CodeEditor *editor, MainWindow *mainWindow); + +public slots: + void newFile(); + void saveFile(); + void saveFileAs(); + void openFile(); + void loadFileInEditor(const QString &filePath); + +private: + FileManager(CodeEditor *editor, MainWindow *mainWindow); + ~FileManager(); + + CodeEditor *m_editor; + MainWindow *m_mainWindow; + QString m_currentFileName; +}; diff --git a/include/LineNumberArea.h b/include/LineNumberArea.h index 64f923d..1f2a85e 100644 --- a/include/LineNumberArea.h +++ b/include/LineNumberArea.h @@ -6,6 +6,15 @@ #include #include +/** + * @class LineNumberArea + * @brief A widget that displays line numbers for the CodeEditor. + * + * The LineNumberArea class is a QWidget that is used to display line numbers + * alongside the CodeEditor widget. + * + * @note This class is intended to be used as a part of the CodeEditor widget. + */ class LineNumberArea : public QWidget { public: diff --git a/include/MainWindow.h b/include/MainWindow.h index 9487c91..7cd1ce8 100644 --- a/include/MainWindow.h +++ b/include/MainWindow.h @@ -6,12 +6,19 @@ #include #include #include -#include class CodeEditor; class Syntax; class Tree; +class FileManager; +/** + * @class MainWindow + * @brief The MainWindow class represents the main UI window of the application. + * + * This class is responsible for initializing and managing the main components + * of the application, including the file tree view, code editor, and menu bar. + */ class MainWindow : public QMainWindow { Q_OBJECT @@ -19,16 +26,12 @@ class MainWindow : public QMainWindow public: explicit MainWindow(QWidget *parent = nullptr); virtual ~MainWindow(); - void loadFileInEditor(const QString &filePath); + // Initialize the file tree view and set it as the central widget // of the main window, alongside the code editor void initTree(); private slots: - void newFile(); - void openFile(); - void saveFile(); - void saveFileAs(); void showAbout(); private: @@ -36,11 +39,14 @@ private slots: void createFileActions(QMenu *fileMenu); void createHelpActions(QMenu *helpMenu); void createAppActions(QMenu *appMenu); + QAction *createAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, const QString &statusTip, - void (MainWindow::*slot)()); + const std::function &slot); + std::unique_ptr m_editor; std::unique_ptr m_syntax; std::unique_ptr m_tree; - QString m_currentFileName; + + FileManager *m_fileManager; }; \ No newline at end of file diff --git a/include/Syntax.h b/include/Syntax.h index 35f0ea0..dcfc5c7 100644 --- a/include/Syntax.h +++ b/include/Syntax.h @@ -5,6 +5,17 @@ #include #include +/** + * @class Syntax + * @brief A class for syntax highlighting in a QTextDocument. + * + * This class inherits from QSyntaxHighlighter and provides functionality + * to highlight different syntax elements such as keywords, comments, + * functions, parentheses, characters, and quotations in a QTextDocument. + * + * The Syntax class uses regular expressions to define patterns for different + * syntax elements and applies corresponding text formats to them. + */ class Syntax : public QSyntaxHighlighter { Q_OBJECT diff --git a/include/Tree.h b/include/Tree.h index 4a54eb9..2fc65a1 100644 --- a/include/Tree.h +++ b/include/Tree.h @@ -5,17 +5,24 @@ #include // Forward declarations -class MainWindow; class QTreeView; class QFileSystemModel; class QFileIconProvider; +class FileManager; +/** + * @class Tree + * @brief A class that represents a tree view for displaying the file system. + * + * The Tree class is responsible for creating and managing a tree view that displays + * the file system. + */ class Tree : public QObject { Q_OBJECT public: - explicit Tree(QSplitter *splitter, MainWindow *mainWindow); + explicit Tree(QSplitter *splitter, FileManager *FileManager); ~Tree(); private: @@ -23,11 +30,12 @@ class Tree : public QObject void setupModel(); void setupTree(); void openFile(const QModelIndex &index); + QString getDirectoryPath() const; std::unique_ptr m_iconProvider; std::unique_ptr m_model; std::unique_ptr m_tree; - MainWindow *m_mainWindow; + FileManager * m_FileManager; }; \ No newline at end of file diff --git a/src/CodeEditor.cpp b/src/CodeEditor.cpp index 9070140..0d23421 100644 --- a/src/CodeEditor.cpp +++ b/src/CodeEditor.cpp @@ -1,6 +1,7 @@ #include "CodeEditor.h" #include "MainWindow.h" #include "LineNumberArea.h" +#include "FileManager.h" #include #include @@ -9,7 +10,8 @@ CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent), - m_lineNumberArea(new LineNumberArea(this)) + m_lineNumberArea(new LineNumberArea(this)), + m_fileManager(&FileManager::getInstance()) { connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth); connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea); @@ -73,18 +75,6 @@ void CodeEditor::keyPressEvent(QKeyEvent *event) } } -QString CodeEditor::getFileExtension() -{ - QString filePath = getCurrentFileName(); - if (!QFile::exists(filePath)) - { - return QString(); - } - - // Extract the file extension from the file path - return QFileInfo(filePath).suffix().toLower(); -} - void CodeEditor::addLanguageSymbol(QTextCursor &cursor, const QString &commentSymbol) { if (cursor.hasSelection()) @@ -116,7 +106,7 @@ void CodeEditor::commentSelection(QTextCursor &cursor, const QString &commentSym if (lineText.startsWith(commentSymbol)) { - cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 3); + cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, commentSymbol.length() + 1); cursor.removeSelectedText(); } else @@ -136,7 +126,7 @@ void CodeEditor::commentLine(QTextCursor &cursor, const QString &commentSymbol) if (lineText.startsWith(commentSymbol)) { - lineText.remove(0, 3); + lineText.remove(0, commentSymbol.length() + 1); } else { @@ -149,7 +139,7 @@ void CodeEditor::commentLine(QTextCursor &cursor, const QString &commentSymbol) void CodeEditor::addComment() { QTextCursor cursor = textCursor(); - QString fileExtension = getFileExtension(); + QString fileExtension = m_fileManager->getFileExtension(); qDebug() << "File Extension:" << fileExtension; if (fileExtension == "cpp" || fileExtension == "h" || @@ -172,7 +162,6 @@ void CodeEditor::addComment() else { qDebug() << "Unsupported file extension for commenting."; - return; } } diff --git a/src/FileManager.cpp b/src/FileManager.cpp new file mode 100644 index 0000000..ab3c6a3 --- /dev/null +++ b/src/FileManager.cpp @@ -0,0 +1,146 @@ +#include "FileManager.h" + +#include +#include +#include +#include +#include "CodeEditor.h" +#include "MainWindow.h" + +FileManager::FileManager(CodeEditor *editor, MainWindow *mainWindow) + : m_editor(editor), m_mainWindow(mainWindow) +{ + qDebug() << "FileManager initialized."; +} + +FileManager::~FileManager() {} + +void FileManager::initialize(CodeEditor *editor, MainWindow *mainWindow) +{ + m_editor = editor; + m_mainWindow = mainWindow; +} + +QString FileManager::getCurrentFileName() const +{ + return m_currentFileName; +} + +void FileManager::setCurrentFileName(const QString fileName) +{ + m_currentFileName = fileName; +} + +void FileManager::newFile() +{ + // Logic to create a new file +} + +void FileManager::saveFile() +{ + if (m_currentFileName.isEmpty()) + { + saveFileAs(); + return; + } + + qDebug() << "Saving file:" << m_currentFileName; + + QFile file(m_currentFileName); + if (!file.open(QFile::WriteOnly | QFile::Text)) + { + QMessageBox::warning(nullptr, "Error", "Cannot save file: " + file.errorString()); + return; + } + + QTextStream out(&file); + if (m_editor) + { + out << m_editor->toPlainText(); + } + else + { + QMessageBox::critical(nullptr, "Error", "Editor is not initialized."); + return; + } + file.close(); + + emit m_editor->statusMessageChanged("File saved successfully."); +} + +void FileManager::saveFileAs() +{ + QString fileExtension = getFileExtension(); + QString filter = "All Files (*);;C++ Files (*.cpp *.h);;Text Files (*.txt)"; + if (!fileExtension.isEmpty()) + { + filter = QString("%1 Files (*.%2);;%3").arg(fileExtension.toUpper(), fileExtension, filter); + } + + QString fileName = QFileDialog::getSaveFileName(nullptr, "Save File As", QString(), filter); + + if (!fileName.isEmpty()) + { + m_currentFileName = fileName; + saveFile(); + } +} + +void FileManager::openFile() +{ + QString fileName = QFileDialog::getOpenFileName(nullptr, "Open File", QString(), + "All Files (*);;C++ Files (*.cpp *.h);;Text Files (*.txt)"); + if (!fileName.isEmpty()) + { + qDebug() << "Opening file: " << fileName; + m_currentFileName = fileName; + loadFileInEditor(fileName); + } + else + { + qDebug() << "No file selected."; + } +} + +void FileManager::loadFileInEditor(const QString &filePath) +{ + qDebug() << "Loading file:" << filePath; + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QMessageBox::warning(nullptr, "Error", "Cannot open file: " + file.errorString()); + return; + } + + QTextStream in(&file); + if (m_editor) + { + m_editor->setPlainText(in.readAll()); + } + else + { + QMessageBox::critical(nullptr, "Error", "Editor is not initialized."); + return; + } + file.close(); + + if (m_mainWindow) + { + m_mainWindow->setWindowTitle("CodeAstra ~ " + QFileInfo(filePath).fileName()); + } + else + { + qWarning() << "MainWindow is initialized in FileManager."; + } +} + +QString FileManager::getFileExtension() const +{ + if (m_currentFileName.isEmpty()) + { + qDebug() << "Error: No File name set!"; + return QString(); + } + + return QFileInfo(m_currentFileName).suffix().toLower(); +} diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 366b94d..b3c78a2 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -2,23 +2,23 @@ #include "Syntax.h" #include "Tree.h" #include "CodeEditor.h" +#include "FileManager.h" #include #include -#include -#include #include #include #include #include -#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), m_editor(std::make_unique(this)), m_syntax(std::make_unique(m_editor->document())), - m_tree(nullptr) + m_tree(nullptr), + m_fileManager(&FileManager::getInstance()) { + m_fileManager->initialize(m_editor.get(), this); setWindowTitle("CodeAstra ~ Code Editor"); connect(m_editor.get(), &CodeEditor::statusMessageChanged, this, [this](const QString &message) @@ -45,7 +45,7 @@ void MainWindow::initTree() QSplitter *splitter = new QSplitter(Qt::Horizontal, this); setCentralWidget(splitter); - m_tree = std::make_unique(splitter, this); + m_tree = std::make_unique(splitter, m_fileManager); splitter->addWidget(m_editor.get()); splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -74,18 +74,21 @@ void MainWindow::createMenuBar() void MainWindow::createFileActions(QMenu *fileMenu) { - fileMenu->addAction(createAction(QIcon(), tr("&New"), QKeySequence::New, tr("Create a new file"), &MainWindow::newFile)); - fileMenu->addAction(createAction(QIcon(), tr("&Open"), QKeySequence::Open, tr("Open an existing file"), &MainWindow::openFile)); + fileMenu->addAction(createAction(QIcon(), tr("&New"), QKeySequence::New, tr("Create a new file"), [this]() { m_fileManager->newFile(); })); + fileMenu->addAction(createAction(QIcon(), tr("&Open"), QKeySequence::Open, tr("Open an existing file"), [this]() { m_fileManager->openFile(); })); fileMenu->addSeparator(); - fileMenu->addAction(createAction(QIcon(), tr("&Save"), QKeySequence::Save, tr("Save the current file"), &MainWindow::saveFile)); - fileMenu->addAction(createAction(QIcon(), tr("Save &As"), QKeySequence::SaveAs, tr("Save the file with a new name"), &MainWindow::saveFileAs)); + fileMenu->addAction(createAction(QIcon(), tr("&Save"), QKeySequence::Save, tr("Save the current file"), [this]() { m_fileManager->saveFile(); })); + fileMenu->addAction(createAction(QIcon(), tr("Save &As"), QKeySequence::SaveAs, tr("Save the file with a new name"), [this]() { m_fileManager->saveFileAs(); })); } void MainWindow::createHelpActions(QMenu *helpMenu) { QAction *helpDoc = new QAction(tr("Documentation"), this); connect(helpDoc, &QAction::triggered, this, []() - { QDesktopServices::openUrl(QUrl("https://github.com/sandbox-science/CodeAstra/wiki")); }); + { + QDesktopServices::openUrl(QUrl("https://github.com/sandbox-science/CodeAstra/wiki")); + }); + helpDoc->setStatusTip(tr("Open Wiki")); helpMenu->addAction(helpDoc); } @@ -97,7 +100,7 @@ void MainWindow::createAppActions(QMenu *appMenu) appMenu->addAction(aboutAction); } -QAction *MainWindow::createAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, const QString &statusTip, void (MainWindow::*slot)()) +QAction *MainWindow::createAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, const QString &statusTip, const std::function &slot) { QAction *action = new QAction(icon, text, this); @@ -108,11 +111,6 @@ QAction *MainWindow::createAction(const QIcon &icon, const QString &text, const return action; } -void MainWindow::newFile() -{ - // TO-DO: Implement new file function -} - void MainWindow::showAbout() { // Extract the C++ version from the __cplusplus macro @@ -157,81 +155,3 @@ void MainWindow::showAbout() QMessageBox::about(this, tr("About"), aboutText); } - -void MainWindow::openFile() -{ - QString fileName = QFileDialog::getOpenFileName(this, "Open File", QString(), - "C++ Files (*.cpp *.h);;Text Files (*.txt);;All Files (*)"); - if (!fileName.isEmpty()) - { - loadFileInEditor(fileName); - } -} - -void MainWindow::saveFile() -{ - if (m_editor->getCurrentFileName().isEmpty()) - { - saveFileAs(); - return; - } - - QFile file(m_editor->getCurrentFileName()); - if (!file.open(QFile::WriteOnly | QFile::Text)) - { - QMessageBox::warning(this, "Error", "Cannot save file: " + file.errorString()); - return; - } - - QTextStream out(&file); - if (m_editor) - { - out << m_editor->toPlainText(); - } - else - { - QMessageBox::critical(this, "Error", "Editor is not initialized."); - return; - } - file.close(); - - emit m_editor->statusMessageChanged("File saved successfully."); -} - -void MainWindow::saveFileAs() -{ - QString fileName = QFileDialog::getSaveFileName(this, "Save File As", QString(), - "C++ Files (*.cpp *.h);;Text Files (*.txt);;All Files (*)"); - - if (!fileName.isEmpty()) - { - m_editor->setCurrentFileName(fileName); - saveFile(); - } -} - -void MainWindow::loadFileInEditor(const QString &filePath) -{ - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QMessageBox::warning(this, "Error", "Cannot open file: " + file.errorString()); - return; - } - - QTextStream in(&file); - if (m_editor) - { - m_editor->setPlainText(in.readAll()); - } - else - { - QMessageBox::critical(this, "Error", "Editor is not initialized."); - return; - } - file.close(); - - m_editor->setCurrentFileName(filePath); - setWindowTitle("CodeAstra ~ " + QFileInfo(filePath).fileName()); - emit m_editor->statusMessageChanged("File loaded successfully: " + QFileInfo(filePath).fileName()); -} diff --git a/src/Syntax.cpp b/src/Syntax.cpp index 9f841c2..4f71a6e 100644 --- a/src/Syntax.cpp +++ b/src/Syntax.cpp @@ -2,8 +2,7 @@ #include #include -Syntax::Syntax(QTextDocument *parent) - : QSyntaxHighlighter(parent) +Syntax::Syntax(QTextDocument *parent) : QSyntaxHighlighter(parent) { initKeywordRules(); initFunctionRules(); diff --git a/src/Tree.cpp b/src/Tree.cpp index acaabde..f8fab29 100644 --- a/src/Tree.cpp +++ b/src/Tree.cpp @@ -1,19 +1,20 @@ #include "Tree.h" -#include "MainWindow.h" #include "CodeEditor.h" +#include "FileManager.h" #include #include #include #include #include +#include -Tree::Tree(QSplitter *splitter, MainWindow *mainWindow) +Tree::Tree(QSplitter *splitter, FileManager *FileManager) : QObject(splitter), m_iconProvider(std::make_unique()), m_model(std::make_unique()), m_tree(std::make_unique(splitter)), - m_mainWindow(mainWindow) + m_FileManager(FileManager) { setupModel(); setupTree(); @@ -69,7 +70,8 @@ void Tree::openFile(const QModelIndex &index) return; } - m_mainWindow->loadFileInEditor(filePath); + FileManager::getInstance().setCurrentFileName(filePath); + FileManager::getInstance().loadFileInEditor(filePath); } // Context menu for file operations