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 | |
28 | NewProjectDialog::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 | |
71 | NewProjectDialog::~NewProjectDialog() |
72 | { |
73 | delete ui; |
74 | } |
75 | |
76 | PProjectTemplate 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 | |
85 | QString NewProjectDialog::getLocation() |
86 | { |
87 | return ui->txtLocation->text(); |
88 | } |
89 | |
90 | QString NewProjectDialog::getProjectName() |
91 | { |
92 | return ui->txtProjectName->text(); |
93 | } |
94 | |
95 | bool NewProjectDialog::useAsDefaultProjectDir() |
96 | { |
97 | return ui->chkAsDefaultLocation->isChecked(); |
98 | } |
99 | |
100 | bool NewProjectDialog::isCProject() |
101 | { |
102 | return ui->rdCProject->isChecked(); |
103 | } |
104 | |
105 | bool NewProjectDialog::isCppProject() |
106 | { |
107 | return ui->rdCppProject->isChecked(); |
108 | } |
109 | |
110 | bool NewProjectDialog::makeDefaultLanguage() |
111 | { |
112 | return ui->chkMakeDefaultLanguage->isChecked(); |
113 | } |
114 | |
115 | void 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 | |
124 | void 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 | |
133 | void 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 | |
154 | void 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 | |
175 | void 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 | |
210 | void 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 | |
220 | void NewProjectDialog::on_lstTemplates_itemDoubleClicked(QListWidgetItem *item) |
221 | { |
222 | if (item) |
223 | accept(); |
224 | } |
225 | |
226 | |
227 | void 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 | |
257 | void 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 | |
277 | void NewProjectDialog::onUpdateIcons() |
278 | { |
279 | pIconsManager->setIcon(ui->btnBrowse, IconsManager::ACTION_FILE_OPEN_FOLDER); |
280 | } |
281 | |
282 | |
283 | void NewProjectDialog::on_btnOk_clicked() |
284 | { |
285 | accept(); |
286 | } |
287 | |
288 | |
289 | void NewProjectDialog::on_btnCancel_clicked() |
290 | { |
291 | reject(); |
292 | } |
293 | |
294 | |