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#include "newprojectdialog.h"
18#include "ui_newprojectdialog.h"
19#include "settings.h"
20#include "systemconsts.h"
21#include "../iconsmanager.h"
22#include <QDir>
23#include <QFile>
24#include <QFileDialog>
25#include <QPainter>
26#include <QPushButton>
27
28NewProjectDialog::NewProjectDialog(QWidget *parent) :
29 QDialog(parent),
30 ui(new Ui::NewProjectDialog)
31{
32 setWindowFlag(Qt::WindowContextHelpButtonHint,false);
33 ui->setupUi(this);
34 mTemplatesTabBar = new QTabBar(this);
35 mTemplatesTabBar->setExpanding(false);
36 ui->verticalLayout->insertWidget(0,mTemplatesTabBar);
37
38 readTemplateDirs();
39
40 int i=0;
41 QString projectName;
42 QString location;
43 location = excludeTrailingPathDelimiter(pSettings->dirs().projectDir());
44 while (true) {
45 i++;
46 projectName = tr("Project%1").arg(i);
47 QString tempLocation = includeTrailingPathDelimiter(location)+projectName;
48 if (!QDir(tempLocation).exists())
49 break;
50 }
51 ui->txtProjectName->setText(projectName);
52 ui->txtLocation->setText(location);
53 resize(pSettings->ui().newProjectDialogWidth(),pSettings->ui().newProjectDialogHeight());
54
55 connect(mTemplatesTabBar,
56 &QTabBar::currentChanged,
57 this,
58 &NewProjectDialog::updateView
59 );
60 connect(ui->txtProjectName,
61 &QLineEdit::textChanged,
62 this,
63 &NewProjectDialog::updateProjectLocation);
64 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
65
66 onUpdateIcons();
67 connect(pIconsManager,&IconsManager::actionIconsUpdated,
68 this, &NewProjectDialog::onUpdateIcons);
69}
70
71NewProjectDialog::~NewProjectDialog()
72{
73 delete ui;
74}
75
76PProjectTemplate NewProjectDialog::getTemplate()
77{
78 QListWidgetItem * item = ui->lstTemplates->currentItem();
79 if (!item)
80 return PProjectTemplate();
81 int index = item->data(Qt::UserRole).toInt();
82 return mTemplates[index];
83}
84
85QString NewProjectDialog::getLocation()
86{
87 return ui->txtLocation->text();
88}
89
90QString NewProjectDialog::getProjectName()
91{
92 return ui->txtProjectName->text();
93}
94
95bool NewProjectDialog::useAsDefaultProjectDir()
96{
97 return ui->chkAsDefaultLocation->isChecked();
98}
99
100bool NewProjectDialog::isCProject()
101{
102 return ui->rdCProject->isChecked();
103}
104
105bool NewProjectDialog::isCppProject()
106{
107 return ui->rdCppProject->isChecked();
108}
109
110bool NewProjectDialog::makeDefaultLanguage()
111{
112 return ui->chkMakeDefaultLanguage->isChecked();
113}
114
115void NewProjectDialog::addTemplate(const QString &filename)
116{
117 if (!QFile(filename).exists())
118 return;
119 PProjectTemplate t = std::make_shared<ProjectTemplate>();
120 t->readTemplateFile(filename);
121 mTemplates.append(t);
122}
123
124void NewProjectDialog::readTemplateDirs()
125{
126 addTemplate(":/templates/empty.template");
127 readTemplateDir(pSettings->dirs().data(Settings::Dirs::DataType::Template));
128 readTemplateDir(pSettings->dirs().config(Settings::Dirs::DataType::Template));
129 rebuildTabs();
130 updateView();
131}
132
133void NewProjectDialog::readTemplateDir(const QString& folderPath)
134{
135
136 QString templateExt(".");
137 templateExt += TEMPLATE_EXT;
138 QDir dir(folderPath);
139 if (!dir.exists())
140 return;
141 foreach (const QFileInfo& fileInfo,dir.entryInfoList()) {
142 if (fileInfo.isFile()
143 && fileInfo.fileName().endsWith(templateExt)) {
144 addTemplate(fileInfo.absoluteFilePath());
145 } else if (fileInfo.isDir()) {
146 QDir subDir(fileInfo.absoluteFilePath());
147 if (subDir.exists(TEMPLATE_INFO_FILE)) {
148 addTemplate(subDir.absoluteFilePath(TEMPLATE_INFO_FILE));
149 }
150 }
151 }
152}
153
154void NewProjectDialog::rebuildTabs()
155{
156 while (mTemplatesTabBar->count()>0) {
157 mTemplatesTabBar->removeTab(0);
158 }
159
160 mCategories.clear();
161 foreach (const PProjectTemplate& t, mTemplates) {
162 QString category = t->category();
163 if (category.isEmpty())
164 category = tr("Default");
165 // Add a page for each unique category
166 int tabIndex = mCategories.value(category,-1);
167 if (tabIndex<0) {
168 tabIndex = mTemplatesTabBar->addTab(category);
169 mCategories.insert(category,tabIndex);
170 }
171 }
172 mTemplatesTabBar->setCurrentIndex(0);
173}
174
175void NewProjectDialog::updateView()
176{
177 int index = std::max(0,mTemplatesTabBar->currentIndex());
178 if (index>=mTemplatesTabBar->count())
179 return;
180 ui->lstTemplates->clear();
181 for (int i=0;i<mTemplates.count();i++) {
182 const PProjectTemplate& t = mTemplates[i];
183 QString category = t->category();
184 if (category.isEmpty())
185 category = tr("Default");
186 QString tabText = mTemplatesTabBar->tabText(index);
187 if (category == tabText) {
188 QListWidgetItem * item;
189 QString iconFilename = QFileInfo(t->fileName()).absoluteDir().absoluteFilePath(t->icon());
190 QIcon icon=QIcon(iconFilename);
191 if (icon.isNull()) {
192 //todo : use an default icon
193 item = new QListWidgetItem(
194 QIcon(":/icons/images/associations/template.ico"),
195 t->name());
196 } else {
197 item = new QListWidgetItem(
198 icon,
199 t->name());
200 }
201 item->setSizeHint(QSize(font().pixelSize()*6,font().pixelSize()*2+64));
202 item->setTextAlignment(Qt::AlignHCenter | Qt::AlignTop);
203 item->setData(Qt::ToolTipRole,t->name());
204 item->setData(Qt::UserRole,i);
205 ui->lstTemplates->addItem(item);
206 }
207 }
208}
209
210void NewProjectDialog::updateProjectLocation()
211{
212 QString newLocation = ui->txtLocation->text();
213
214 QListWidgetItem * current = ui->lstTemplates->currentItem();
215 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
216 current && !ui->txtProjectName->text().isEmpty()
217 );
218}
219
220void NewProjectDialog::on_lstTemplates_itemDoubleClicked(QListWidgetItem *item)
221{
222 if (item)
223 accept();
224}
225
226
227void NewProjectDialog::on_lstTemplates_currentItemChanged(QListWidgetItem *current, QListWidgetItem *)
228{
229 if (current) {
230 int index = current->data(Qt::UserRole).toInt();
231 PProjectTemplate t = mTemplates[index];
232 ui->lblDescription->setText(t->description());
233 if (t->options().isCpp) {
234 ui->rdCProject->setEnabled(false);
235 ui->rdCppProject->setChecked(true);
236 } else {
237 ui->rdCProject->setEnabled(true);
238 ui->rdCProject->setChecked(true);
239 if (pSettings->editor().defaultFileCpp()) {
240 ui->rdCppProject->setChecked(true);
241 } else {
242 ui->rdCProject->setChecked(true);
243 }
244 }
245 } else {
246 ui->lblDescription->setText("");
247 ui->rdCProject->setChecked(false);
248 ui->rdCppProject->setChecked(false);
249 ui->chkMakeDefaultLanguage->setChecked(false);
250 }
251 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
252 current && !ui->txtProjectName->text().isEmpty()
253 );
254}
255
256
257void NewProjectDialog::on_btnBrowse_clicked()
258{
259 QString dirPath = ui->txtLocation->text();
260 if (!QDir(dirPath).exists()) {
261 dirPath = pSettings->dirs().projectDir();
262 }
263 QString dir = QFileDialog::getExistingDirectory(
264 this,
265 tr("Choose directory"),
266 dirPath
267 );
268 if (!dir.isEmpty()) {
269 ui->txtLocation->setText(dir);
270 QListWidgetItem * current = ui->lstTemplates->currentItem();
271 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
272 current && !ui->txtProjectName->text().isEmpty()
273 );
274 }
275}
276
277void NewProjectDialog::onUpdateIcons()
278{
279 pIconsManager->setIcon(ui->btnBrowse, IconsManager::ACTION_FILE_OPEN_FOLDER);
280}
281
282
283void NewProjectDialog::on_btnOk_clicked()
284{
285 accept();
286}
287
288
289void NewProjectDialog::on_btnCancel_clicked()
290{
291 reject();
292}
293
294