Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b8a56b8

Browse files
authoredMar 16, 2025
Merge pull request #16 from sandbox-science/fileTree
File Tree Navigation
2 parents da95e0f + aa3008c commit b8a56b8

File tree

5 files changed

+343
-195
lines changed

5 files changed

+343
-195
lines changed
 

‎CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ add_executable(${TARGET_NAME}
5555
src/MainWindow.cpp
5656
src/CodeEditor.cpp
5757
src/Syntax.cpp
58+
src/Tree.cpp
5859
include/MainWindow.h
5960
include/CodeEditor.h
6061
include/Syntax.h
62+
include/Tree.h
6163
)
6264

6365
qt_add_resources(APP_RESOURCES resources.qrc)

‎include/MainWindow.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "CodeEditor.h"
55
#include "Syntax.h"
6+
#include "Tree.h"
7+
68
#include <QMainWindow>
79
#include <QMenu>
810
#include <QAction>
@@ -17,6 +19,7 @@ class MainWindow : public QMainWindow
1719
public:
1820
explicit MainWindow(QWidget *parent = nullptr);
1921
virtual ~MainWindow();
22+
void loadFileInEditor(const QString &filePath);
2023

2124
private slots:
2225
void newFile();
@@ -36,6 +39,7 @@ private slots:
3639
CodeEditor *editor;
3740
QString currentFileName;
3841
Syntax *syntax;
42+
Tree *tree;
3943
};
4044

4145
#endif // MAINWINDOW_H

‎include/Tree.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef TREE_H
2+
#define TREE_H
3+
4+
#include <QSplitter>
5+
#include <QTreeView>
6+
#include <QFileSystemModel>
7+
#include <QObject>
8+
9+
class MainWindow; // Forward declaration
10+
11+
class Tree : public QObject
12+
{
13+
Q_OBJECT
14+
15+
public:
16+
Tree(QSplitter *splitter, MainWindow *mainWindow);
17+
~Tree();
18+
19+
private:
20+
void showContextMenu(const QPoint &pos);
21+
void setupModel();
22+
void setupTree();
23+
void openFile(const QModelIndex &index);
24+
QString getDirectoryPath();
25+
26+
QFileSystemModel *model;
27+
QTreeView *tree;
28+
MainWindow *mainWindow;
29+
};
30+
31+
#endif // TREE_H

‎src/MainWindow.cpp

Lines changed: 228 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,195 +1,228 @@
1-
#include "MainWindow.h"
2-
#include "Syntax.h"
3-
4-
#include <QMenuBar>
5-
#include <QFileDialog>
6-
#include <QFile>
7-
#include <QTextStream>
8-
#include <QMessageBox>
9-
#include <QStatusBar>
10-
#include <QApplication>
11-
#include <QDesktopServices>
12-
13-
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
14-
{
15-
setWindowTitle("CodeAstra ~ Code Editor");
16-
resize(800, 600);
17-
18-
editor = new CodeEditor(this);
19-
syntax = new Syntax(editor->document());
20-
21-
setCentralWidget(editor);
22-
createMenuBar();
23-
}
24-
25-
MainWindow::~MainWindow() {}
26-
27-
void MainWindow::createMenuBar()
28-
{
29-
QMenuBar *menuBar = new QMenuBar(this);
30-
31-
QMenu *fileMenu = menuBar->addMenu("File");
32-
QMenu *helpMenu = menuBar->addMenu("Help");
33-
QMenu *appMenu = menuBar->addMenu("CodeAstra");
34-
35-
createFileActions(fileMenu);
36-
createHelpActions(helpMenu);
37-
createAppActions(appMenu);
38-
39-
setMenuBar(menuBar);
40-
}
41-
42-
void MainWindow::createFileActions(QMenu *fileMenu)
43-
{
44-
QAction *newAction = createAction(QIcon::fromTheme("document-new"), tr("&New File..."), QKeySequence::New, tr("Create a new file"), &MainWindow::newFile);
45-
fileMenu->addAction(newAction);
46-
47-
QAction *openAction = createAction(QIcon::fromTheme("document-open"), tr("&Open..."), QKeySequence::Open, tr("Open an existing file"), &MainWindow::openFile);
48-
fileMenu->addAction(openAction);
49-
50-
QAction *saveAction = createAction(QIcon::fromTheme("document-save"), tr("&Save"), QKeySequence::Save, tr("Save your file"), &MainWindow::saveFile);
51-
fileMenu->addAction(saveAction);
52-
53-
QAction *saveAsAction = createAction(QIcon::fromTheme("document-saveAs"), tr("&Save As"), QKeySequence::SaveAs, tr("Save current file as..."), &MainWindow::saveFileAs);
54-
fileMenu->addAction(saveAsAction);
55-
}
56-
57-
void MainWindow::createHelpActions(QMenu *helpMenu)
58-
{
59-
QAction *helpDoc = new QAction(tr("Documentation"), this);
60-
connect(helpDoc, &QAction::triggered, this, []()
61-
{ QDesktopServices::openUrl(QUrl("https://github.com/sandbox-science/CodeAstra/wiki")); });
62-
helpDoc->setStatusTip(tr("Open Wiki"));
63-
helpMenu->addAction(helpDoc);
64-
}
65-
66-
void MainWindow::createAppActions(QMenu *appMenu)
67-
{
68-
QAction *aboutAction = new QAction("About CodeAstra", this);
69-
connect(aboutAction, &QAction::triggered, this, &MainWindow::showAbout);
70-
appMenu->addAction(aboutAction);
71-
}
72-
73-
QAction *MainWindow::createAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, const QString &statusTip, void (MainWindow::*slot)())
74-
{
75-
QAction *action = new QAction(icon, text, this);
76-
77-
action->setShortcuts(QList<QKeySequence>{shortcut});
78-
action->setStatusTip(statusTip);
79-
connect(action, &QAction::triggered, this, slot);
80-
81-
return action;
82-
}
83-
84-
void MainWindow::newFile()
85-
{
86-
// TO-DO: Implement new file function
87-
}
88-
89-
void MainWindow::showAbout()
90-
{
91-
// Extract the C++ version from the __cplusplus macro
92-
QString cppVersion;
93-
if (__cplusplus == 201103L)
94-
{
95-
cppVersion = "C++11";
96-
}
97-
else if (__cplusplus == 201402L)
98-
{
99-
cppVersion = "C++14";
100-
}
101-
else if (__cplusplus == 201703L)
102-
{
103-
cppVersion = "C++17";
104-
}
105-
else if (__cplusplus == 202002L)
106-
{
107-
cppVersion = "C++20";
108-
}
109-
else
110-
{
111-
cppVersion = "C++";
112-
}
113-
114-
// Construct the about text
115-
QString aboutText = QString(
116-
"<p style='text-align:center;'>"
117-
"<b>%1</b><br>"
118-
"Version: %2<br><br>"
119-
"Developed by %3.<br>"
120-
"Built with %4 and Qt %5.<br><br>"
121-
"© 2025 %3. All rights reserved."
122-
"</p>").arg(QApplication::applicationName().toHtmlEscaped(),
123-
QApplication::applicationVersion().toHtmlEscaped(),
124-
QApplication::organizationName().toHtmlEscaped(),
125-
cppVersion,
126-
QString::number(QT_VERSION >> 16) + "." + // Major version
127-
QString::number((QT_VERSION >> 8) & 0xFF) + "." + // Minor version
128-
QString::number(QT_VERSION & 0xFF)); // Patch version
129-
130-
QMessageBox::about(this, "About Code Astra", aboutText);
131-
}
132-
133-
void MainWindow::openFile()
134-
{
135-
QString fileName = QFileDialog::getOpenFileName(this, "Open File");
136-
if (!fileName.isEmpty())
137-
{
138-
QFile file(fileName);
139-
if (!file.open(QFile::ReadOnly | QFile::Text))
140-
{
141-
QMessageBox::warning(this, "Error", "Cannot open file: " + file.errorString());
142-
return;
143-
}
144-
145-
QTextStream in(&file);
146-
if (editor)
147-
{
148-
editor->setPlainText(in.readAll());
149-
}
150-
else
151-
{
152-
QMessageBox::critical(this, "Error", "Editor is not initialized.");
153-
}
154-
file.close();
155-
156-
currentFileName = fileName;
157-
158-
setWindowTitle("CodeAstra ~ " + QFileInfo(fileName).fileName());
159-
}
160-
}
161-
162-
void MainWindow::saveFile()
163-
{
164-
if (currentFileName.isEmpty())
165-
{
166-
saveFileAs();
167-
return;
168-
}
169-
170-
QFile file(currentFileName);
171-
if (!file.open(QFile::WriteOnly | QFile::Text))
172-
{
173-
QMessageBox::warning(this, "Error", "Cannot save file: " + file.errorString());
174-
return;
175-
}
176-
177-
QTextStream out(&file);
178-
if (editor)
179-
{
180-
out << editor->toPlainText();
181-
}
182-
file.close();
183-
184-
statusBar()->showMessage("File saved successfully.", 2000);
185-
}
186-
187-
void MainWindow::saveFileAs()
188-
{
189-
QString fileName = QFileDialog::getSaveFileName(this, "Save File As");
190-
if (!fileName.isEmpty())
191-
{
192-
currentFileName = fileName;
193-
saveFile();
194-
}
195-
}
1+
#include "MainWindow.h"
2+
#include "Syntax.h"
3+
#include "Tree.h"
4+
5+
#include <QMenuBar>
6+
#include <QFileDialog>
7+
#include <QFile>
8+
#include <QTextStream>
9+
#include <QMessageBox>
10+
#include <QStatusBar>
11+
#include <QApplication>
12+
#include <QDesktopServices>
13+
#include <QVBoxLayout>
14+
15+
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
16+
{
17+
setWindowTitle("CodeAstra ~ Code Editor");
18+
19+
editor = new CodeEditor(this);
20+
syntax = new Syntax(editor->document());
21+
22+
QFontMetrics metrics(editor->font());
23+
int spaceWidth = metrics.horizontalAdvance(" ");
24+
editor->setTabStopDistance(spaceWidth * 4);
25+
26+
QSplitter *splitter = new QSplitter(Qt::Horizontal, this);
27+
setCentralWidget(splitter);
28+
29+
tree = new Tree(splitter, this);
30+
31+
splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
32+
splitter->setHandleWidth(5);
33+
splitter->setSizes(QList<int>() << 20 << 950);
34+
splitter->addWidget(editor);
35+
36+
createMenuBar();
37+
showMaximized();
38+
}
39+
40+
MainWindow::~MainWindow() {}
41+
42+
void MainWindow::createMenuBar()
43+
{
44+
QMenuBar *menuBar = new QMenuBar(this);
45+
46+
QMenu *fileMenu = menuBar->addMenu("File");
47+
QMenu *helpMenu = menuBar->addMenu("Help");
48+
QMenu *appMenu = menuBar->addMenu("CodeAstra");
49+
50+
createFileActions(fileMenu);
51+
createHelpActions(helpMenu);
52+
createAppActions(appMenu);
53+
54+
setMenuBar(menuBar);
55+
}
56+
57+
void MainWindow::createFileActions(QMenu *fileMenu)
58+
{
59+
QAction *newAction = createAction(QIcon::fromTheme("document-new"), tr("&New File..."), QKeySequence::New, tr("Create a new file"), &MainWindow::newFile);
60+
fileMenu->addAction(newAction);
61+
62+
QAction *openAction = createAction(QIcon::fromTheme("document-open"), tr("&Open..."), QKeySequence::Open, tr("Open an existing file"), &MainWindow::openFile);
63+
fileMenu->addAction(openAction);
64+
65+
QAction *saveAction = createAction(QIcon::fromTheme("document-save"), tr("&Save"), QKeySequence::Save, tr("Save your file"), &MainWindow::saveFile);
66+
fileMenu->addAction(saveAction);
67+
68+
QAction *saveAsAction = createAction(QIcon::fromTheme("document-saveAs"), tr("&Save As"), QKeySequence::SaveAs, tr("Save current file as..."), &MainWindow::saveFileAs);
69+
fileMenu->addAction(saveAsAction);
70+
}
71+
72+
void MainWindow::createHelpActions(QMenu *helpMenu)
73+
{
74+
QAction *helpDoc = new QAction(tr("Documentation"), this);
75+
connect(helpDoc, &QAction::triggered, this, []()
76+
{ QDesktopServices::openUrl(QUrl("https://github.com/sandbox-science/CodeAstra/wiki")); });
77+
helpDoc->setStatusTip(tr("Open Wiki"));
78+
helpMenu->addAction(helpDoc);
79+
}
80+
81+
void MainWindow::createAppActions(QMenu *appMenu)
82+
{
83+
QAction *aboutAction = new QAction("About CodeAstra", this);
84+
connect(aboutAction, &QAction::triggered, this, &MainWindow::showAbout);
85+
appMenu->addAction(aboutAction);
86+
}
87+
88+
QAction *MainWindow::createAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, const QString &statusTip, void (MainWindow::*slot)())
89+
{
90+
QAction *action = new QAction(icon, text, this);
91+
92+
action->setShortcuts(QList<QKeySequence>{shortcut});
93+
action->setStatusTip(statusTip);
94+
connect(action, &QAction::triggered, this, slot);
95+
96+
return action;
97+
}
98+
99+
void MainWindow::newFile()
100+
{
101+
// TO-DO: Implement new file function
102+
}
103+
104+
void MainWindow::showAbout()
105+
{
106+
// Extract the C++ version from the __cplusplus macro
107+
QString cppVersion;
108+
if (__cplusplus == 201103L)
109+
{
110+
cppVersion = "C++11";
111+
}
112+
else if (__cplusplus == 201402L)
113+
{
114+
cppVersion = "C++14";
115+
}
116+
else if (__cplusplus == 201703L)
117+
{
118+
cppVersion = "C++17";
119+
}
120+
else if (__cplusplus == 202002L)
121+
{
122+
cppVersion = "C++20";
123+
}
124+
else
125+
{
126+
cppVersion = "C++";
127+
}
128+
129+
// Construct the about text
130+
QString aboutText = QString(
131+
"<p style='text-align:center;'>"
132+
"<b>%1</b><br>"
133+
"Version: %2<br><br>"
134+
"Developed by %3.<br>"
135+
"Built with %4 and Qt %5.<br><br>"
136+
"© 2025 %3. All rights reserved."
137+
"</p>")
138+
.arg(QApplication::applicationName().toHtmlEscaped(),
139+
QApplication::applicationVersion().toHtmlEscaped(),
140+
QApplication::organizationName().toHtmlEscaped(),
141+
cppVersion,
142+
QString::number(QT_VERSION >> 16) + "." + // Major version
143+
QString::number((QT_VERSION >> 8) & 0xFF) + "." + // Minor version
144+
QString::number(QT_VERSION & 0xFF)); // Patch version
145+
146+
QMessageBox::about(this, "About Code Astra", aboutText);
147+
}
148+
149+
void MainWindow::openFile()
150+
{
151+
QString fileName = QFileDialog::getOpenFileName(this, "Open File");
152+
if (!fileName.isEmpty())
153+
{
154+
QFile file(fileName);
155+
if (!file.open(QFile::ReadOnly | QFile::Text))
156+
{
157+
QMessageBox::warning(this, "Error", "Cannot open file: " + file.errorString());
158+
return;
159+
}
160+
161+
QTextStream in(&file);
162+
if (editor)
163+
{
164+
editor->setPlainText(in.readAll());
165+
}
166+
else
167+
{
168+
QMessageBox::critical(this, "Error", "Editor is not initialized.");
169+
}
170+
file.close();
171+
172+
currentFileName = fileName;
173+
174+
setWindowTitle("CodeAstra ~ " + QFileInfo(fileName).fileName());
175+
}
176+
}
177+
178+
void MainWindow::saveFile()
179+
{
180+
if (currentFileName.isEmpty())
181+
{
182+
saveFileAs();
183+
return;
184+
}
185+
186+
QFile file(currentFileName);
187+
if (!file.open(QFile::WriteOnly | QFile::Text))
188+
{
189+
QMessageBox::warning(this, "Error", "Cannot save file: " + file.errorString());
190+
return;
191+
}
192+
193+
QTextStream out(&file);
194+
if (editor)
195+
{
196+
out << editor->toPlainText();
197+
}
198+
file.close();
199+
200+
statusBar()->showMessage("File saved successfully.", 2000);
201+
}
202+
203+
void MainWindow::saveFileAs()
204+
{
205+
QString fileName = QFileDialog::getSaveFileName(this, "Save File As");
206+
if (!fileName.isEmpty())
207+
{
208+
currentFileName = fileName;
209+
saveFile();
210+
}
211+
}
212+
213+
void MainWindow::loadFileInEditor(const QString &filePath)
214+
{
215+
QFile file(filePath);
216+
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
217+
{
218+
QMessageBox::warning(this, "Error", "Cannot open file: " + file.errorString());
219+
return;
220+
}
221+
222+
QTextStream in(&file);
223+
editor->setPlainText(in.readAll());
224+
file.close();
225+
226+
currentFileName = filePath;
227+
setWindowTitle("CodeAstra ~ " + QFileInfo(filePath).fileName());
228+
}

‎src/Tree.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include "Tree.h"
2+
#include "MainWindow.h"
3+
#include "CodeEditor.h"
4+
5+
#include <QFileDialog>
6+
#include <QFileInfo>
7+
#include <QFileIconProvider>
8+
#include <QTreeView>
9+
10+
Tree::Tree(QSplitter *splitter, MainWindow *mainWindow) : QObject(splitter), mainWindow(mainWindow)
11+
{
12+
model = new QFileSystemModel();
13+
tree = new QTreeView(splitter);
14+
15+
setupModel();
16+
setupTree();
17+
18+
connect(tree, &QTreeView::doubleClicked, this, &Tree::openFile);
19+
}
20+
21+
Tree::~Tree() {}
22+
23+
void Tree::setupModel()
24+
{
25+
model->setRootPath(getDirectoryPath());
26+
model->setIconProvider(new QFileIconProvider);
27+
model->setFilter(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot);
28+
29+
}
30+
31+
void Tree::setupTree()
32+
{
33+
tree->setModel(model);
34+
tree->setRootIndex(model->index(model->rootPath()));
35+
tree->setRootIsDecorated(true);
36+
tree->setAnimated(true);
37+
tree->setIndentation(20);
38+
tree->setSortingEnabled(false);
39+
tree->sortByColumn(1, Qt::AscendingOrder);
40+
41+
tree->setContextMenuPolicy(Qt::CustomContextMenu);
42+
connect(tree, &QTreeView::customContextMenuRequested, this, &Tree::showContextMenu);
43+
44+
for (int i = 1; i <= 3; ++i)
45+
{
46+
tree->setColumnHidden(i, true);
47+
}
48+
}
49+
50+
QString Tree::getDirectoryPath()
51+
{
52+
return QFileDialog::getExistingDirectory(
53+
nullptr, QObject::tr("Open Directory"), QDir::homePath(),
54+
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
55+
}
56+
57+
void Tree::openFile(const QModelIndex &index)
58+
{
59+
QString filePath = model->filePath(index);
60+
QFileInfo fileInfo(filePath);
61+
62+
// Ensure it's a file, not a folder before loading
63+
if (fileInfo.isFile())
64+
{
65+
mainWindow->loadFileInEditor(filePath);
66+
}
67+
}
68+
69+
void Tree::showContextMenu(const QPoint &pos)
70+
{
71+
// TO_DO: Implement delete a file
72+
// TO_DO: Implement rename a file
73+
// TO_DO: Implement create a new file
74+
// TO_DO: Implement create a new folder
75+
76+
// use pos param for testing purpose for now
77+
tree->indexAt(pos);
78+
}

0 commit comments

Comments
 (0)
Please sign in to comment.