1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "newclasswidget.h"
27 #include "ui_newclasswidget.h"
28
29 #include <QFileDialog>
30 #include <QDebug>
31
32 enum { debugNewClassWidget = 0 };
33
34 /*! \class Utils::NewClassWidget
35
36 \brief The NewClassWidget class is a utility widget for 'New Class' wizards.
37
38 This widget prompts the user
39 to enter a class name (optionally derived from some base class) and file
40 names for header, source and form files. Has some smart logic to derive
41 the file names from the class name. */
42
43 namespace Designer {
44 namespace Internal {
45
46 struct NewClassWidgetPrivate {
47 NewClassWidgetPrivate();
48
49 Ui::NewClassWidget m_ui;
50 QString m_headerExtension;
51 QString m_sourceExtension;
52 QString m_formExtension;
53 bool m_valid = false;
54 bool m_classEdited = false;
55 };
56
NewClassWidgetPrivate()57 NewClassWidgetPrivate:: NewClassWidgetPrivate() :
58 m_headerExtension(QLatin1Char('h')),
59 m_sourceExtension(QLatin1String("cpp")),
60 m_formExtension(QLatin1String("ui"))
61 {
62 }
63
64 // --------------------- NewClassWidget
NewClassWidget(QWidget * parent)65 NewClassWidget::NewClassWidget(QWidget *parent) :
66 QWidget(parent),
67 d(new NewClassWidgetPrivate)
68 {
69 d->m_ui.setupUi(this);
70
71 d->m_ui.baseClassLabel->setVisible(false);
72 d->m_ui.baseClassComboBox->setVisible(false);
73 d->m_ui.classTypeLabel->setVisible(false);
74 d->m_ui.classTypeComboBox->setVisible(false);
75
76 d->m_ui.classLineEdit->setNamespacesEnabled(true);
77 setNamesDelimiter(QLatin1String("::"));
78
79 connect(d->m_ui.classLineEdit, &Utils::ClassNameValidatingLineEdit::updateFileName,
80 this, &NewClassWidget::slotUpdateFileNames);
81 connect(d->m_ui.classLineEdit, &QLineEdit::textEdited,
82 this, &NewClassWidget::classNameEdited);
83 connect(d->m_ui.baseClassComboBox,
84 QOverload<int>::of(&QComboBox::currentIndexChanged),
85 this, &NewClassWidget::suggestClassNameFromBase);
86 connect(d->m_ui.baseClassComboBox, &QComboBox::editTextChanged,
87 this, &NewClassWidget::slotValidChanged);
88 connect(d->m_ui.classLineEdit, &Utils::FancyLineEdit::validChanged,
89 this, &NewClassWidget::slotValidChanged);
90 connect(d->m_ui.headerFileLineEdit, &Utils::FancyLineEdit::validChanged,
91 this, &NewClassWidget::slotValidChanged);
92 connect(d->m_ui.sourceFileLineEdit, &Utils::FancyLineEdit::validChanged,
93 this, &NewClassWidget::slotValidChanged);
94 connect(d->m_ui.formFileLineEdit, &Utils::FancyLineEdit::validChanged,
95 this, &NewClassWidget::slotValidChanged);
96 connect(d->m_ui.pathChooser, &Utils::PathChooser::validChanged,
97 this, &NewClassWidget::slotValidChanged);
98
99 connect(d->m_ui.classLineEdit, &Utils::FancyLineEdit::validReturnPressed,
100 this, &NewClassWidget::slotActivated);
101 connect(d->m_ui.headerFileLineEdit, &Utils::FancyLineEdit::validReturnPressed,
102 this, &NewClassWidget::slotActivated);
103 connect(d->m_ui.sourceFileLineEdit, &Utils::FancyLineEdit::validReturnPressed,
104 this, &NewClassWidget::slotActivated);
105 connect(d->m_ui.formFileLineEdit, &Utils::FancyLineEdit::validReturnPressed,
106 this, &NewClassWidget::slotActivated);
107 connect(d->m_ui.formFileLineEdit, &Utils::FancyLineEdit::validReturnPressed,
108 this, &NewClassWidget::slotActivated);
109 connect(d->m_ui.pathChooser, &Utils::PathChooser::returnPressed,
110 this, &NewClassWidget::slotActivated);
111
112 setClassType(NoClassType);
113 }
114
~NewClassWidget()115 NewClassWidget::~NewClassWidget()
116 {
117 delete d;
118 }
119
classNameEdited()120 void NewClassWidget::classNameEdited()
121 {
122 if (debugNewClassWidget)
123 qDebug() << Q_FUNC_INFO << d->m_headerExtension << d->m_sourceExtension;
124 d->m_classEdited = true;
125 }
126
suggestClassNameFromBase()127 void NewClassWidget::suggestClassNameFromBase()
128 {
129 if (debugNewClassWidget)
130 qDebug() << Q_FUNC_INFO << d->m_headerExtension << d->m_sourceExtension;
131 if (d->m_classEdited)
132 return;
133 // Suggest a class unless edited ("QMainWindow"->"MainWindow")
134 QString base = baseClassName();
135 if (base.startsWith(QLatin1Char('Q'))) {
136 base.remove(0, 1);
137 setClassName(base);
138 }
139 }
140
setClassName(const QString & suggestedName)141 void NewClassWidget::setClassName(const QString &suggestedName)
142 {
143 if (debugNewClassWidget)
144 qDebug() << Q_FUNC_INFO << suggestedName << d->m_headerExtension << d->m_sourceExtension;
145 d->m_ui.classLineEdit->setText(
146 Utils::ClassNameValidatingLineEdit::createClassName(suggestedName));
147 }
148
className() const149 QString NewClassWidget::className() const
150 {
151 return d->m_ui.classLineEdit->text();
152 }
153
baseClassName() const154 QString NewClassWidget::baseClassName() const
155 {
156 return d->m_ui.baseClassComboBox->currentText();
157 }
158
sourceFileName() const159 QString NewClassWidget::sourceFileName() const
160 {
161 return d->m_ui.sourceFileLineEdit->text();
162 }
163
headerFileName() const164 QString NewClassWidget::headerFileName() const
165 {
166 return d->m_ui.headerFileLineEdit->text();
167 }
168
formFileName() const169 QString NewClassWidget::formFileName() const
170 {
171 return d->m_ui.formFileLineEdit->text();
172 }
173
path() const174 QString NewClassWidget::path() const
175 {
176 return d->m_ui.pathChooser->filePath().toString();
177 }
178
setPath(const QString & path)179 void NewClassWidget::setPath(const QString &path)
180 {
181 d->m_ui.pathChooser->setPath(path);
182 }
183
sourceExtension() const184 QString NewClassWidget::sourceExtension() const
185 {
186 return d->m_sourceExtension;
187 }
188
setSourceExtension(const QString & e)189 void NewClassWidget::setSourceExtension(const QString &e)
190 {
191 if (debugNewClassWidget)
192 qDebug() << Q_FUNC_INFO << e;
193 d->m_sourceExtension = fixSuffix(e);
194 }
195
headerExtension() const196 QString NewClassWidget::headerExtension() const
197 {
198 return d->m_headerExtension;
199 }
200
setHeaderExtension(const QString & e)201 void NewClassWidget::setHeaderExtension(const QString &e)
202 {
203 if (debugNewClassWidget)
204 qDebug() << Q_FUNC_INFO << e;
205 d->m_headerExtension = fixSuffix(e);
206 }
207
formExtension() const208 QString NewClassWidget::formExtension() const
209 {
210 return d->m_formExtension;
211 }
212
213
setLowerCaseFiles(bool v)214 void NewClassWidget::setLowerCaseFiles(bool v)
215 {
216 d->m_ui.classLineEdit->setLowerCaseFileName(v);
217 }
218
setClassType(ClassType ct)219 void NewClassWidget::setClassType(ClassType ct)
220 {
221 d->m_ui.classTypeComboBox->setCurrentIndex(ct);
222 }
223
setNamesDelimiter(const QString & delimiter)224 void NewClassWidget::setNamesDelimiter(const QString &delimiter)
225 {
226 d->m_ui.classLineEdit->setNamespaceDelimiter(delimiter);
227 }
228
slotValidChanged()229 void NewClassWidget::slotValidChanged()
230 {
231 const bool newValid = isValid();
232 if (newValid != d->m_valid) {
233 d->m_valid = newValid;
234 emit validChanged();
235 }
236 }
237
isValid(QString * error) const238 bool NewClassWidget::isValid(QString *error) const
239 {
240 if (!d->m_ui.classLineEdit->isValid()) {
241 if (error)
242 *error = d->m_ui.classLineEdit->errorMessage();
243 return false;
244 }
245
246 if (!d->m_ui.headerFileLineEdit->isValid()) {
247 if (error)
248 *error = tr("Invalid header file name: \"%1\"").arg(d->m_ui.headerFileLineEdit->errorMessage());
249 return false;
250 }
251
252 if (!d->m_ui.sourceFileLineEdit->isValid()) {
253 if (error)
254 *error = tr("Invalid source file name: \"%1\"").arg(d->m_ui.sourceFileLineEdit->errorMessage());
255 return false;
256 }
257
258 if (!d->m_ui.formFileLineEdit->isValid()) {
259 if (error)
260 *error = tr("Invalid form file name: \"%1\"").arg(d->m_ui.formFileLineEdit->errorMessage());
261 return false;
262 }
263
264 if (!d->m_ui.pathChooser->isValid()) {
265 if (error)
266 *error = d->m_ui.pathChooser->errorMessage();
267 return false;
268 }
269 return true;
270 }
271
slotUpdateFileNames(const QString & baseName)272 void NewClassWidget::slotUpdateFileNames(const QString &baseName)
273 {
274 if (debugNewClassWidget)
275 qDebug() << Q_FUNC_INFO << baseName << d->m_headerExtension << d->m_sourceExtension;
276 const QChar dot = QLatin1Char('.');
277 d->m_ui.sourceFileLineEdit->setText(baseName + dot + d->m_sourceExtension);
278 d->m_ui.headerFileLineEdit->setText(baseName + dot + d->m_headerExtension);
279 d->m_ui.formFileLineEdit->setText(baseName + dot + d->m_formExtension);
280 }
281
slotActivated()282 void NewClassWidget::slotActivated()
283 {
284 if (d->m_valid)
285 emit activated();
286 }
287
fixSuffix(const QString & suffix)288 QString NewClassWidget::fixSuffix(const QString &suffix)
289 {
290 QString s = suffix;
291 if (s.startsWith(QLatin1Char('.')))
292 s.remove(0, 1);
293 return s;
294 }
295
296 // Utility to add a suffix to a file unless the user specified one
ensureSuffix(QString f,const QString & extension)297 static QString ensureSuffix(QString f, const QString &extension)
298 {
299 const QChar dot = QLatin1Char('.');
300 if (f.contains(dot))
301 return f;
302 f += dot;
303 f += extension;
304 return f;
305 }
306
307 // If a non-empty name was passed, expand to directory and suffix
expandFileName(const QDir & dir,const QString & name,const QString & extension)308 static QString expandFileName(const QDir &dir, const QString &name, const QString &extension)
309 {
310 if (name.isEmpty())
311 return QString();
312 return dir.absoluteFilePath(ensureSuffix(name, extension));
313 }
314
files() const315 QStringList NewClassWidget::files() const
316 {
317 QStringList rc;
318 const QDir dir = QDir(path());
319 rc.push_back(expandFileName(dir, headerFileName(), headerExtension()));
320 rc.push_back(expandFileName(dir, sourceFileName(), sourceExtension()));
321 rc.push_back(expandFileName(dir, formFileName(), formExtension()));
322 return rc;
323 }
324
325 } // namespace Internal
326 } // namespace Designer
327