1/*
2 * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#ifndef PROJECT_H
18#define PROJECT_H
19
20#include <QAbstractItemModel>
21#include <QSortFilterProxyModel>
22#include <memory>
23#include "projectoptions.h"
24#include "utils.h"
25
26class Project;
27class Editor;
28class CppParser;
29class EditorList;
30class QFileSystemWatcher;
31
32
33enum ProjectSpecialFolderNode {
34 HEADERS,
35 SOURCES,
36 OTHERS,
37 NonSpecial,
38 NotFolder
39};
40
41struct ProjectModelNode;
42using PProjectModelNode = std::shared_ptr<ProjectModelNode>;
43struct ProjectModelNode {
44 QString text;
45 std::weak_ptr<ProjectModelNode> parent;
46 int unitIndex;
47 int priority;
48 QList<PProjectModelNode> children;
49 ProjectSpecialFolderNode folderNodeType;
50 int level;
51};
52
53class ProjectUnit {
54
55public:
56 explicit ProjectUnit(Project* parent);
57 Project* parent() const;
58 void setParent(Project* newParent);
59 const QString &fileName() const;
60 void setFileName(QString newFileName);
61 bool isNew() const;
62 void setNew(bool newNew);
63 const QString &folder() const;
64 void setFolder(const QString &newFolder);
65 bool compile() const;
66 void setCompile(bool newCompile);
67 bool compileCpp() const;
68 void setCompileCpp(bool newCompileCpp);
69 bool overrideBuildCmd() const;
70 void setOverrideBuildCmd(bool newOverrideBuildCmd);
71 const QString &buildCmd() const;
72 void setBuildCmd(const QString &newBuildCmd);
73 bool link() const;
74 void setLink(bool newLink);
75 int priority() const;
76 void setPriority(int newPriority);
77 const QByteArray &encoding() const;
78 void setEncoding(const QByteArray &newEncoding);
79 bool modified() const;
80 void setModified(bool value);
81 bool save();
82
83 PProjectModelNode &node();
84 void setNode(const PProjectModelNode &newNode);
85
86 bool FileMissing() const;
87 void setFileMissing(bool newDontSave);
88
89private:
90 Project* mParent;
91 QString mFileName;
92 bool mNew;
93 QString mFolder;
94 bool mCompile;
95 bool mCompileCpp;
96 bool mOverrideBuildCmd;
97 QString mBuildCmd;
98 bool mLink;
99 int mPriority;
100 QByteArray mEncoding;
101 PProjectModelNode mNode;
102 bool mFileMissing;
103};
104
105using PProjectUnit = std::shared_ptr<ProjectUnit>;
106
107class GitRepository;
108class CustomFileIconProvider;
109class ProjectModel : public QAbstractItemModel {
110 Q_OBJECT
111public:
112 explicit ProjectModel(Project* project, QObject* parent=nullptr);
113 ~ProjectModel();
114 void beginUpdate();
115 void endUpdate();
116private:
117 Project* mProject;
118 int mUpdateCount;
119 CustomFileIconProvider* mIconProvider;
120
121
122 // QAbstractItemModel interface
123public:
124 QModelIndex index(int row, int column, const QModelIndex &parent) const override;
125 QModelIndex parent(const QModelIndex &child) const override;
126 int rowCount(const QModelIndex &parent) const override;
127 int columnCount(const QModelIndex &parent) const override;
128 QVariant data(const QModelIndex &index, int role) const override;
129 Qt::ItemFlags flags(const QModelIndex &index) const override;
130 bool setData(const QModelIndex &index, const QVariant &value, int role) override;
131
132private:
133 QModelIndex getParentIndex(ProjectModelNode * node) const;
134 // QAbstractItemModel interface
135public:
136 bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override;
137 Qt::DropActions supportedDropActions() const override;
138 bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
139 QMimeData *mimeData(const QModelIndexList &indexes) const override;
140 Project *project() const;
141 CustomFileIconProvider *iconProvider() const;
142};
143
144class ProjectModelSortFilterProxy : public QSortFilterProxyModel
145{
146 Q_OBJECT
147
148public:
149 explicit ProjectModelSortFilterProxy(QObject *parent = nullptr);
150 // QSortFilterProxyModel interface
151protected:
152 bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
153};
154
155class ProjectTemplate;
156class Project : public QObject
157{
158 Q_OBJECT
159public:
160 explicit Project(const QString& filename, const QString& name,
161 EditorList* editorList,
162 QFileSystemWatcher* fileSystemWatcher,
163 QObject *parent = nullptr);
164 ~Project();
165 QString directory() const;
166 QString executable() const;
167 QString makeFileName();
168 bool modified() const;
169 void setFileName(QString value);
170 void setModified(bool value);
171
172 void addFolder(const QString& s);
173 PProjectUnit addUnit(const QString& inFileName,
174 PProjectModelNode parentNode,
175 bool rebuild);
176 QString folder();
177 void buildPrivateResource(bool forceSave=false);
178 void closeUnit(int index);
179 void doAutoOpen();
180 bool fileAlreadyExists(const QString& s);
181
182 QString getFolderPath(PProjectModelNode node);
183 int getUnitFromString(const QString& s);
184 void incrementBuildNumber();
185 int indexInUnits(const QString& fileName) const;
186 int indexInUnits(const Editor* editor) const;
187 PProjectUnit newUnit(PProjectModelNode parentNode,
188 const QString& customFileName="");
189 Editor* openUnit(int index, bool forceOpen=true);
190 Editor* unitEditor(const PProjectUnit& unit) const;
191 Editor* unitEditor(const ProjectUnit* unit) const;
192 Editor* unitEditor(int index) const {
193 if (index<0 || index>=mUnits.count())
194 return nullptr;
195 return unitEditor(mUnits[index]);
196 }
197 PProjectModelNode pointerToNode(ProjectModelNode * p, PProjectModelNode parent=PProjectModelNode());
198 void rebuildNodes();
199 bool removeUnit(int index, bool doClose, bool removeFile = false);
200 bool removeFolder(PProjectModelNode node);
201 void resetParserProjectFiles();
202 void saveAll(); // save [Project] and all [UnitX]
203 void saveLayout(); // save all [UnitX]
204 void saveOptions();
205 void saveUnitAs(int i, const QString& sFileName, bool syncEditor = true); // save single [UnitX]
206 bool saveUnits();
207
208 PProjectUnit findUnitByFilename(const QString& filename);
209 void associateEditor(Editor* editor);
210 void associateEditorToUnit(Editor* editor, PProjectUnit unit);
211 bool setCompileOption(const QString &key, const QString &value);
212 QString getCompileOption(const QString &key) const;
213
214 void updateFolders();
215 void updateNodeIndexes();
216 void setCompilerSet(int compilerSetIndex);
217
218 bool assignTemplate(const std::shared_ptr<ProjectTemplate> aTemplate, bool useCpp);
219 bool saveAsTemplate(const QString& templateFolder,
220 const QString& name,
221 const QString& description,
222 const QString& category);
223
224 std::shared_ptr<CppParser> cppParser();
225 const QString &filename() const;
226
227 const QString &name() const;
228 void setName(const QString &newName);
229
230 const PProjectModelNode &rootNode() const;
231
232 ProjectOptions &options();
233
234 ProjectModel* model() ;
235
236 const QList<PProjectUnit> &units() const;
237
238 ProjectModelType modelType() const;
239 void setModelType(ProjectModelType type);
240
241 EditorList *editorList() const;
242
243 QFileSystemWatcher *fileSystemWatcher() const;
244
245 QString fileSystemNodeFolderPath(const PProjectModelNode& node);
246
247 QStringList binDirs();
248
249signals:
250 void nodesChanged();
251 void modifyChanged(bool value);
252private:
253 void checkProjectFileForUpdate(SimpleIni& ini);
254 void createFolderNodes();
255 void createFileSystemFolderNodes();
256 void createFileSystemFolderNode(ProjectSpecialFolderNode folderType, const QString& folderName, PProjectModelNode parent, const QSet<QString>& validFolders);
257 PProjectModelNode getParentFolderNode(const QString& filename);
258 PProjectModelNode findFolderNode(const QString& folderPath, ProjectSpecialFolderNode nodeType);
259 PProjectModelNode folderNodeFromName(const QString& name);
260 void loadOptions(SimpleIni& ini);
261 void loadLayout(); // load all [UnitX]
262 void loadUnitLayout(Editor *e, int index); // load single [UnitX] cursor positions
263
264 PProjectModelNode makeNewFileNode(const QString& s, bool isFolder, PProjectModelNode newParent);
265 PProjectModelNode makeProjectNode();
266 void open();
267 void removeFolderRecurse(PProjectModelNode node);
268 void saveUnitLayout(Editor* e, int index); // save single [UnitX] cursor positions
269 void updateFolderNode(PProjectModelNode node);
270 void updateCompilerSetType();
271
272private:
273 QList<PProjectUnit> mUnits;
274 ProjectOptions mOptions;
275 QString mFilename;
276 QString mName;
277 bool mModified;
278 QStringList mFolders;
279 std::shared_ptr<CppParser> mParser;
280 QList<PProjectModelNode> mFolderNodes;
281 PProjectModelNode mRootNode;
282 QHash<ProjectSpecialFolderNode, PProjectModelNode> mSpecialNodes;
283 QHash<QString, PProjectModelNode> mFileSystemFolderNodes;
284 ProjectModel mModel;
285 EditorList *mEditorList;
286 QFileSystemWatcher* mFileSystemWatcher;
287};
288
289#endif // PROJECT_H
290