filenamevalidatinglineedit.cpp 6.3 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
**
10
** GNU Lesser General Public License Usage
11
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
con's avatar
con committed
30
**
31
**************************************************************************/
hjk's avatar
hjk committed
32

con's avatar
con committed
33
#include "filenamevalidatinglineedit.h"
hjk's avatar
hjk committed
34
#include "qtcassert.h"
con's avatar
con committed
35

36
37
#include <QRegExp>
#include <QDebug>
38

39
40
41
42
43
44
45
/*!
  \class Utils::FileNameValidatingLineEdit

  \brief A control that let's the user choose a (base) file name, based on a QLineEdit. Has
   some validation logic for embedding into QWizardPage.
*/

con's avatar
con committed
46
47
namespace Utils {

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
48
49
#define WINDOWS_DEVICES "CON|AUX|PRN|COM1|COM2|LPT1|LPT2|NUL"

50
51
52
53
54
// Naming a file like a device name will break on Windows, even if it is
// "com1.txt". Since we are cross-platform, we generally disallow such file
//  names.
static const QRegExp &windowsDeviceNoSubDirPattern()
{
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
55
    static const QRegExp rc(QLatin1String(WINDOWS_DEVICES),
56
                      Qt::CaseInsensitive);
hjk's avatar
hjk committed
57
    QTC_ASSERT(rc.isValid(), return rc);
58
59
60
61
62
    return rc;
}

static const QRegExp &windowsDeviceSubDirPattern()
{
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
63
    static const QRegExp rc(QLatin1String(".*[/\\\\](" WINDOWS_DEVICES ")"), Qt::CaseInsensitive);
hjk's avatar
hjk committed
64
    QTC_ASSERT(rc.isValid(), return rc);
65
66
67
68
    return rc;
}

// ----------- FileNameValidatingLineEdit
con's avatar
con committed
69
FileNameValidatingLineEdit::FileNameValidatingLineEdit(QWidget *parent) :
70
    BaseValidatingLineEdit(parent),
71
    m_allowDirectories(false)
72
73
74
75
{
}

bool FileNameValidatingLineEdit::allowDirectories() const
con's avatar
con committed
76
{
77
78
    return m_allowDirectories;
}
con's avatar
con committed
79

80
81
82
void FileNameValidatingLineEdit::setAllowDirectories(bool v)
{
    m_allowDirectories = v;
con's avatar
con committed
83
84
85
86
}

/* Validate a file base name, check for forbidden characters/strings. */

87
88
89
90
91
#ifdef Q_OS_WIN
#  define SLASHES "/\\"
#else
#  define SLASHES "/"
#endif
con's avatar
con committed
92

93
94
static const char notAllowedCharsSubDir[]   = "={}[]~!?:&*\"|#%<>$\"'();`' ";
static const char notAllowedCharsNoSubDir[] = "={}[]~!?:&*\"|#%<>$\"'();`' "SLASHES;
con's avatar
con committed
95

96
97
98
99
100
static const char *notAllowedSubStrings[] = {".."};

bool FileNameValidatingLineEdit::validateFileName(const QString &name,
                                                  bool allowDirectories,
                                                  QString *errorMessage /* = 0*/)
con's avatar
con committed
101
102
103
{
    if (name.isEmpty()) {
        if (errorMessage)
104
            *errorMessage = tr("Name is empty.");
con's avatar
con committed
105
106
107
        return false;
    }
    // Characters
108
    const char *notAllowedChars = allowDirectories ? notAllowedCharsSubDir : notAllowedCharsNoSubDir;
con's avatar
con committed
109
110
    for (const char *c = notAllowedChars; *c; c++)
        if (name.contains(QLatin1Char(*c))) {
111
            if (errorMessage) {
112
113
                const QChar qc = QLatin1Char(*c);
                if (qc.isSpace()) {
114
115
                    *errorMessage = tr("Name contains white space.");
                } else {
116
                    *errorMessage = tr("Invalid character '%1'.").arg(qc);
117
118
                }
            }
con's avatar
con committed
119
120
121
122
123
124
125
126
            return false;
        }
    // Substrings
    const int notAllowedSubStringCount = sizeof(notAllowedSubStrings)/sizeof(const char *);
    for (int s = 0; s < notAllowedSubStringCount; s++) {
        const QLatin1String notAllowedSubString(notAllowedSubStrings[s]);
        if (name.contains(notAllowedSubString)) {
            if (errorMessage)
127
                *errorMessage = tr("Invalid characters '%1'.").arg(QString(notAllowedSubString));
con's avatar
con committed
128
129
130
            return false;
        }
    }
131
132
133
134
135
136
    // Windows devices
    bool matchesWinDevice = windowsDeviceNoSubDirPattern().exactMatch(name);
    if (!matchesWinDevice && allowDirectories)
        matchesWinDevice = windowsDeviceSubDirPattern().exactMatch(name);
    if (matchesWinDevice) {
        if (errorMessage)
137
            *errorMessage = tr("Name matches MS Windows device. (%1).").
138
139
                            arg(windowsDeviceNoSubDirPattern().pattern().replace(QLatin1Char('|'), QLatin1Char(',')));
        return false;
con's avatar
con committed
140
141
142
143
144
145
    }
    return true;
}

bool  FileNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
{
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
    return validateFileNameExtension(value, requiredExtensions(), errorMessage)
            && validateFileName(value, allowDirectories(), errorMessage);
}


bool FileNameValidatingLineEdit::validateFileNameExtension(const QString &fileName,
                                                           const QStringList &requiredExtensions,
                                                           QString *errorMessage)
{
    // file extension
    if (!requiredExtensions.isEmpty()) {
        foreach (const QString &requiredExtension, requiredExtensions) {
            QString extension = QLatin1String(".") + requiredExtension;
            if (fileName.endsWith(extension, Qt::CaseSensitive) && extension.count() < fileName.count()) {
                return true;
            }
        }

        if (errorMessage) {
            if (requiredExtensions.count() == 1) {
                *errorMessage = tr("File extension %1 is required:").arg(requiredExtensions.first());
            } else {
168
                *errorMessage = tr("File extensions %1 are required:").arg(requiredExtensions.join(QLatin1String(", ")));
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
            }
        }

        return false;
    }

    return true;
}

QStringList FileNameValidatingLineEdit::requiredExtensions() const
{
    return m_requiredExtensionList;
}

void FileNameValidatingLineEdit::setRequiredExtensions(const QStringList &extensions)
{
    m_requiredExtensionList = extensions;
con's avatar
con committed
186
187
}

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