QGCQFileDialog.cc 6.93 KB
Newer Older
1 2 3 4 5 6 7 8 9
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

10

11
#include "QGCQFileDialog.h"
12
#include "QGCApplication.h"
13

14 15
#ifdef UNITTEST_BUILD
    #include "UnitTest.h"
dogmaphobic's avatar
dogmaphobic committed
16
#endif
17

Don Gagne's avatar
Don Gagne committed
18 19
#include <QRegularExpression>
#include <QMessageBox>
20
#include <QPushButton>
Don Gagne's avatar
Don Gagne committed
21

22
QString QGCQFileDialog::getExistingDirectory(
23 24 25 26
    QWidget* parent,
    const QString& caption,
    const QString& dir,
    Options options)
27
{
28
    _validate(options);
29
    
30
#ifdef UNITTEST_BUILD
31 32 33 34 35 36 37 38 39
    if (qgcApp()->runningUnitTests()) {
        return UnitTest::_getExistingDirectory(parent, caption, dir, options);
    } else
#endif
    {
        return QFileDialog::getExistingDirectory(parent, caption, dir, options);
    }
}

40
QString QGCQFileDialog::getOpenFileName(
41 42 43 44 45
    QWidget* parent,
    const QString& caption,
    const QString& dir,
    const QString& filter,
    Options options)
46
{
47
    _validate(options);
48
    
49
#ifdef UNITTEST_BUILD
50
    if (qgcApp()->runningUnitTests()) {
51
        return UnitTest::_getOpenFileName(parent, caption, dir, filter, options);
52 53 54
    } else
#endif
    {
55
        return QFileDialog::getOpenFileName(parent, caption, dir, filter, NULL, options);
56 57 58
    }
}

59
QStringList QGCQFileDialog::getOpenFileNames(
60 61 62 63 64
    QWidget* parent,
    const QString& caption,
    const QString& dir,
    const QString& filter,
    Options options)
65
{
66
    _validate(options);
67
    
68
#ifdef UNITTEST_BUILD
69
    if (qgcApp()->runningUnitTests()) {
70
        return UnitTest::_getOpenFileNames(parent, caption, dir, filter, options);
71 72 73
    } else
#endif
    {
74
        return QFileDialog::getOpenFileNames(parent, caption, dir, filter, NULL, options);
75 76 77
    }
}

78
QString QGCQFileDialog::getSaveFileName(
79
    QWidget* parent,
80 81 82
    const QString& caption,
    const QString& dir,
    const QString& filter,
83
    const QString& defaultSuffix,
84
    bool strict,
85
    Options options)
86
{
87
    _validate(options);
88

89
#ifdef UNITTEST_BUILD
90
    if (qgcApp()->runningUnitTests()) {
91
        return UnitTest::_getSaveFileName(parent, caption, dir, filter, defaultSuffix, options);
92 93 94
    } else
#endif
    {
95
        QString defaultSuffixCopy(defaultSuffix);
96
        QFileDialog dlg(parent, caption, dir, filter);
97
        dlg.setAcceptMode(QFileDialog::AcceptSave);
98
        if (options) {
99
            dlg.setOptions(options);
100
        }
101
        if (!defaultSuffixCopy.isEmpty()) {
102
            //-- Make sure dot is not present
103 104
            if (defaultSuffixCopy.startsWith(".")) {
                defaultSuffixCopy.remove(0,1);
105
            }
106
            dlg.setDefaultSuffix(defaultSuffixCopy);
107
        }
108 109 110
        while (true) {
            if (dlg.exec()) {
                if (dlg.selectedFiles().count()) {
111 112 113 114 115 116 117 118 119 120 121 122
                    QString result = dlg.selectedFiles().first();
                    //-- If we don't care about the extension, just return it
                    if (!strict) {
                        return result;
                    } else {
                        //-- We must enforce the file extension
                        QFileInfo fi(result);
                        QString userSuffix(fi.suffix());
                        if (_validateExtension(filter, userSuffix)) {
                            return result;
                        }
                        //-- Do we have a default extension?
123
                        if (defaultSuffixCopy.isEmpty()) {
124
                            //-- We don't, so get the first one in the filter
125
                            defaultSuffixCopy = _getFirstExtensionInFilter(filter);
126
                        }
127
                        //-- If this is set to strict, we have to have a default extension
DonLakeFlyer's avatar
DonLakeFlyer committed
128 129 130
                        if (defaultSuffixCopy.isEmpty()) {
                            qWarning() << "Internal error";
                        }
131 132
                        //-- Forcefully append our desired extension
                        result += ".";
133
                        result += defaultSuffixCopy;
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
                        //-- Check and see if this new file already exists
                        fi.setFile(result);
                        if (fi.exists()) {
                            //-- Ask user what to do
                            QMessageBox msgBox(
                                QMessageBox::Warning,
                                tr("File Exists"),
                                tr("%1 already exists.\nDo you want to replace it?").arg(fi.fileName()),
                                QMessageBox::Cancel,
                                parent);
                            msgBox.addButton(QMessageBox::Retry);
                            QPushButton *overwriteButton = msgBox.addButton(tr("Replace"), QMessageBox::ActionRole);
                            msgBox.setDefaultButton(QMessageBox::Retry);
                            msgBox.setWindowModality(Qt::ApplicationModal);
                            if (msgBox.exec() == QMessageBox::Retry) {
                                continue;
                            } else if (msgBox.clickedButton() == overwriteButton) {
                                return result;
                            }
                        } else {
                            return result;
155 156
                        }
                    }
157
                }
158
            }
159
            break;
160
        }
161
        return {};
162 163 164
    }
}

165
/// @brief Make sure filename is using one of the valid extensions defined in the filter
166
bool QGCQFileDialog::_validateExtension(const QString& filter, const QString& extension) {
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    QRegularExpression re("(\\*\\.\\w+)");
    QRegularExpressionMatchIterator i = re.globalMatch(filter);
    while (i.hasNext()) {
        QRegularExpressionMatch match = i.next();
        if (match.hasMatch()) {
            //-- Compare "foo" with "*.foo"
            if(extension == match.captured(0).mid(2)) {
                return true;
            }
        }
    }
    return false;
}

/// @brief Returns first extension found in filter
182
QString QGCQFileDialog::_getFirstExtensionInFilter(const QString& filter) {
183 184 185 186 187
    QRegularExpression re("(\\*\\.\\w+)");
    QRegularExpressionMatchIterator i = re.globalMatch(filter);
    while (i.hasNext()) {
        QRegularExpressionMatch match = i.next();
        if (match.hasMatch()) {
188 189
            //-- Return "foo" from "*.foo"
            return match.captured(0).mid(2);
190 191
        }
    }
192
    return {};
193 194
}

195
/// @brief Validates and updates the parameters for the file dialog calls
196
void QGCQFileDialog::_validate(Options& options)
197
{
198 199
    Q_UNUSED(options)

200
    // You can't use QGCQFileDialog if QGCApplication is not created yet.
DonLakeFlyer's avatar
DonLakeFlyer committed
201 202 203 204
    if (!qgcApp()) {
        qWarning() << "Internal error";
        return;
    }
205
    
DonLakeFlyer's avatar
DonLakeFlyer committed
206 207 208
    if (QThread::currentThread() != qgcApp()->thread()) {
        qWarning() << "Threading issue: QGCQFileDialog can only be called from main thread";
        return;
209
    }
210
}