projectintropage.cpp 9.47 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3
4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12
13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25
26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
hjk's avatar
hjk committed
30

con's avatar
con committed
31
32
33
#include "projectintropage.h"
#include "ui_projectintropage.h"

34
#include "filenamevalidatinglineedit.h"
35
36
#include "wizard.h"

37
#include <QDir>
38
39
40
41

/*!
    \class Utils::ProjectIntroPage

42
43
    \brief The ProjectIntroPage class is the standard wizard page for a project,
    letting the user choose its name
44
45
46
47
48
    and path.

    Looks similar to FileWizardPage, but provides additional
    functionality:
    \list
Leena Miettinen's avatar
Leena Miettinen committed
49
50
51
    \li Contains a description label at the top for displaying introductory text.
    \li Does on the fly validation (connected to changed()) and displays
       warnings and errors in a status label at the bottom (the page is complete
52
53
54
       when fully validated, validatePage() is thus not implemented).
    \endlist

Leena Miettinen's avatar
Leena Miettinen committed
55
    \note Careful when changing projectintropage.ui. It must have main
56
57
58
59
60
    geometry cleared and QLayout::SetMinimumSize constraint on the main
    layout, otherwise, QWizard will squeeze it due to its strange expanding
    hacks.
*/

con's avatar
con committed
61
62
63
64
65
66
67
68
69
70
71
namespace Utils {

struct ProjectIntroPagePrivate
{
    ProjectIntroPagePrivate();
    Ui::ProjectIntroPage m_ui;
    bool m_complete;
    // Status label style sheets
    const QString m_errorStyleSheet;
    const QString m_warningStyleSheet;
    const QString m_hintStyleSheet;
72
73
    bool m_forceSubProject;
    QStringList m_projectDirectories;
con's avatar
con committed
74
75
76
77
78
79
};

ProjectIntroPagePrivate::  ProjectIntroPagePrivate() :
    m_complete(false),
    m_errorStyleSheet(QLatin1String("background : red;")),
    m_warningStyleSheet(QLatin1String("background : yellow;")),
80
81
    m_hintStyleSheet(),
    m_forceSubProject(false)
con's avatar
con committed
82
83
84
85
{
}

ProjectIntroPage::ProjectIntroPage(QWidget *parent) :
86
    WizardPage(parent),
hjk's avatar
hjk committed
87
    d(new ProjectIntroPagePrivate)
con's avatar
con committed
88
{
hjk's avatar
hjk committed
89
    d->m_ui.setupUi(this);
con's avatar
con committed
90
    hideStatusLabel();
hjk's avatar
hjk committed
91
92
    d->m_ui.nameLineEdit->setInitialText(tr("<Enter_Name>"));
    d->m_ui.nameLineEdit->setFocus();
93
94
95
    d->m_ui.nameLineEdit->setValidationFunction([this](FancyLineEdit *edit, QString *errorString) {
        return ProjectIntroPage::validateProjectName(edit->text(), errorString);
    });
96
97
98
99
    d->m_ui.projectLabel->setVisible(d->m_forceSubProject);
    d->m_ui.projectComboBox->setVisible(d->m_forceSubProject);
    d->m_ui.pathChooser->setDisabled(d->m_forceSubProject);
    d->m_ui.projectsDirectoryCheckBox->setDisabled(d->m_forceSubProject);
Orgad Shaneh's avatar
Orgad Shaneh committed
100
101
102
103
104
105
106
107
108
109
110
111
112
    connect(d->m_ui.pathChooser, &PathChooser::changed,
            this, &ProjectIntroPage::slotChanged);
    connect(d->m_ui.nameLineEdit, &QLineEdit::textChanged,
            this, &ProjectIntroPage::slotChanged);
    connect(d->m_ui.pathChooser, &PathChooser::validChanged,
            this, &ProjectIntroPage::slotChanged);
    connect(d->m_ui.pathChooser, &PathChooser::returnPressed,
            this, &ProjectIntroPage::slotActivated);
    connect(d->m_ui.nameLineEdit, &FancyLineEdit::validReturnPressed,
            this, &ProjectIntroPage::slotActivated);
    connect(d->m_ui.projectComboBox,
            static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            this, &ProjectIntroPage::slotChanged);
113
114

    setProperty(SHORT_TITLE_PROPERTY, tr("Location"));
115
116
    registerFieldWithName(QLatin1String("Path"), d->m_ui.pathChooser, "path", SIGNAL(pathChanged(QString)));
    registerFieldWithName(QLatin1String("ProjectName"), d->m_ui.nameLineEdit);
con's avatar
con committed
117
118
119
120
}

void ProjectIntroPage::insertControl(int row, QWidget *label, QWidget *control)
{
hjk's avatar
hjk committed
121
    d->m_ui.formLayout->insertRow(row, label, control);
con's avatar
con committed
122
123
124
125
}

ProjectIntroPage::~ProjectIntroPage()
{
hjk's avatar
hjk committed
126
    delete d;
con's avatar
con committed
127
128
}

129
QString ProjectIntroPage::projectName() const
con's avatar
con committed
130
{
hjk's avatar
hjk committed
131
    return d->m_ui.nameLineEdit->text();
con's avatar
con committed
132
133
134
135
}

QString ProjectIntroPage::path() const
{
hjk's avatar
hjk committed
136
    return d->m_ui.pathChooser->path();
con's avatar
con committed
137
138
139
140
}

void ProjectIntroPage::setPath(const QString &path)
{
hjk's avatar
hjk committed
141
    d->m_ui.pathChooser->setPath(path);
con's avatar
con committed
142
143
}

144
void ProjectIntroPage::setProjectName(const QString &name)
con's avatar
con committed
145
{
hjk's avatar
hjk committed
146
147
    d->m_ui.nameLineEdit->setText(name);
    d->m_ui.nameLineEdit->selectAll();
con's avatar
con committed
148
149
150
151
}

QString ProjectIntroPage::description() const
{
hjk's avatar
hjk committed
152
    return d->m_ui.descriptionLabel->text();
con's avatar
con committed
153
154
155
156
}

void ProjectIntroPage::setDescription(const QString &description)
{
hjk's avatar
hjk committed
157
    d->m_ui.descriptionLabel->setText(description);
con's avatar
con committed
158
159
160
161
}

bool ProjectIntroPage::isComplete() const
{
hjk's avatar
hjk committed
162
    return d->m_complete;
con's avatar
con committed
163
164
165
166
}

bool ProjectIntroPage::validate()
{
167
168
169
170
171
172
    if (d->m_forceSubProject) {
        int index = d->m_ui.projectComboBox->currentIndex();
        if (index == 0)
            return false;
        d->m_ui.pathChooser->setPath(d->m_projectDirectories.at(index));
    }
con's avatar
con committed
173
    // Validate and display status
hjk's avatar
hjk committed
174
175
    if (!d->m_ui.pathChooser->isValid()) {
        displayStatusMessage(Error, d->m_ui.pathChooser->errorMessage());
con's avatar
con committed
176
177
178
179
180
        return false;
    }

    // Name valid? Ignore 'DisplayingInitialText' state.
    bool nameValid = false;
hjk's avatar
hjk committed
181
    switch (d->m_ui.nameLineEdit->state()) {
182
    case FancyLineEdit::Invalid:
hjk's avatar
hjk committed
183
        displayStatusMessage(Error, d->m_ui.nameLineEdit->errorMessage());
con's avatar
con committed
184
        return false;
185
    case FancyLineEdit::DisplayingInitialText:
con's avatar
con committed
186
        break;
187
    case FancyLineEdit::Valid:
con's avatar
con committed
188
189
190
191
192
        nameValid = true;
        break;
    }

    // Check existence of the directory
193
194
    const QFileInfo projectDirFile(path() + QLatin1Char('/')
                                   + QDir::fromNativeSeparators(d->m_ui.nameLineEdit->text()));
con's avatar
con committed
195
196
197
198
199
200
201
    if (!projectDirFile.exists()) { // All happy
        hideStatusLabel();
        return nameValid;
    }

    if (projectDirFile.isDir()) {
        displayStatusMessage(Warning, tr("The project already exists."));
Nikolai Kosjar's avatar
Nikolai Kosjar committed
202
        return nameValid;
con's avatar
con committed
203
204
205
206
207
208
209
210
211
    }
    // Not a directory, but something else, likely causing directory creation to fail
    displayStatusMessage(Error, tr("A file with that name already exists."));
    return false;
}

void ProjectIntroPage::slotChanged()
{
    const bool newComplete = validate();
hjk's avatar
hjk committed
212
213
    if (newComplete != d->m_complete) {
        d->m_complete = newComplete;
con's avatar
con committed
214
215
216
217
218
219
        emit completeChanged();
    }
}

void ProjectIntroPage::slotActivated()
{
hjk's avatar
hjk committed
220
    if (d->m_complete)
con's avatar
con committed
221
222
223
        emit activated();
}

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
bool ProjectIntroPage::forceSubProject() const
{
    return d->m_forceSubProject;
}

void ProjectIntroPage::setForceSubProject(bool force)
{
    d->m_forceSubProject = force;
    d->m_ui.projectLabel->setVisible(d->m_forceSubProject);
    d->m_ui.projectComboBox->setVisible(d->m_forceSubProject);
    d->m_ui.pathChooser->setDisabled(d->m_forceSubProject);
    d->m_ui.projectsDirectoryCheckBox->setDisabled(d->m_forceSubProject);
}

void ProjectIntroPage::setProjectList(const QStringList &projectList)
{
    d->m_ui.projectComboBox->clear();
    d->m_ui.projectComboBox->addItems(projectList);
}

void ProjectIntroPage::setProjectDirectories(const QStringList &directoryList)
{
    d->m_projectDirectories = directoryList;
}

int ProjectIntroPage::projectIndex() const
{
    return d->m_ui.projectComboBox->currentIndex();
}

254
255
256
257
258
259
260
261
262
263
264
265
266
267
bool ProjectIntroPage::validateProjectName(const QString &name, QString *errorMessage /* = 0*/)
{
    // Validation is file name + checking for dots
    if (!FileNameValidatingLineEdit::validateFileName(name, false, errorMessage))
        return false;

    int pos = FileUtils::indexOfQmakeUnfriendly(name);
    if (pos >= 0) {
        if (errorMessage)
            *errorMessage = tr("Invalid character \"%1\" found.").arg(name.at(pos));
        return false;
    }
    if (name.contains(QLatin1Char('.'))) {
        if (errorMessage)
268
            *errorMessage = tr("Invalid character \".\".");
269
270
271
272
273
        return false;
    }
    return true;
}

con's avatar
con committed
274
275
276
277
void ProjectIntroPage::displayStatusMessage(StatusLabelMode m, const QString &s)
{
    switch (m) {
    case Error:
hjk's avatar
hjk committed
278
        d->m_ui.stateLabel->setStyleSheet(d->m_errorStyleSheet);
con's avatar
con committed
279
280
        break;
    case Warning:
hjk's avatar
hjk committed
281
        d->m_ui.stateLabel->setStyleSheet(d->m_warningStyleSheet);
con's avatar
con committed
282
283
        break;
    case Hint:
hjk's avatar
hjk committed
284
        d->m_ui.stateLabel->setStyleSheet(d->m_hintStyleSheet);
con's avatar
con committed
285
286
        break;
    }
hjk's avatar
hjk committed
287
    d->m_ui.stateLabel->setText(s);
con's avatar
con committed
288
289
290
291
292
293
294
}

void ProjectIntroPage::hideStatusLabel()
{
    displayStatusMessage(Hint, QString());
}

295
296
bool ProjectIntroPage::useAsDefaultPath() const
{
hjk's avatar
hjk committed
297
    return d->m_ui.projectsDirectoryCheckBox->isChecked();
298
299
300
301
}

void ProjectIntroPage::setUseAsDefaultPath(bool u)
{
hjk's avatar
hjk committed
302
    d->m_ui.projectsDirectoryCheckBox->setChecked(u);
303
304
}

hjk's avatar
hjk committed
305
} // namespace Utils