QGCFileDialog.cc 7.06 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 12

#include "QGCFileDialog.h"
#include "QGCApplication.h"
13
#include "MainWindow.h"
14

15
#ifdef QT_DEBUG
dogmaphobic's avatar
dogmaphobic committed
16
#ifndef __mobile__
17 18
#include "UnitTest.h"
#endif
dogmaphobic's avatar
dogmaphobic committed
19
#endif
20

Don Gagne's avatar
Don Gagne committed
21 22
#include <QRegularExpression>
#include <QMessageBox>
23
#include <QPushButton>
Don Gagne's avatar
Don Gagne committed
24

25 26 27 28 29
QString QGCFileDialog::getExistingDirectory(
    QWidget* parent,
    const QString& caption,
    const QString& dir,
    Options options)
30
{
31
    _validate(options);
32 33
    
#ifdef QT_DEBUG
dogmaphobic's avatar
dogmaphobic committed
34
#ifndef __mobile__
35 36 37
    if (qgcApp()->runningUnitTests()) {
        return UnitTest::_getExistingDirectory(parent, caption, dir, options);
    } else
dogmaphobic's avatar
dogmaphobic committed
38
#endif
39 40 41 42 43 44
#endif
    {
        return QFileDialog::getExistingDirectory(parent, caption, dir, options);
    }
}

45 46 47 48 49 50
QString QGCFileDialog::getOpenFileName(
    QWidget* parent,
    const QString& caption,
    const QString& dir,
    const QString& filter,
    Options options)
51
{
52
    _validate(options);
53 54
    
#ifdef QT_DEBUG
dogmaphobic's avatar
dogmaphobic committed
55
#ifndef __mobile__
56
    if (qgcApp()->runningUnitTests()) {
57
        return UnitTest::_getOpenFileName(parent, caption, dir, filter, options);
58
    } else
dogmaphobic's avatar
dogmaphobic committed
59
#endif
60 61
#endif
    {
62
        return QFileDialog::getOpenFileName(parent, caption, dir, filter, NULL, options);
63 64 65
    }
}

66 67 68 69 70 71
QStringList QGCFileDialog::getOpenFileNames(
    QWidget* parent,
    const QString& caption,
    const QString& dir,
    const QString& filter,
    Options options)
72
{
73
    _validate(options);
74 75
    
#ifdef QT_DEBUG
dogmaphobic's avatar
dogmaphobic committed
76
#ifndef __mobile__
77
    if (qgcApp()->runningUnitTests()) {
78
        return UnitTest::_getOpenFileNames(parent, caption, dir, filter, options);
79
    } else
dogmaphobic's avatar
dogmaphobic committed
80
#endif
81 82
#endif
    {
83
        return QFileDialog::getOpenFileNames(parent, caption, dir, filter, NULL, options);
84 85 86
    }
}

87 88
QString QGCFileDialog::getSaveFileName(
    QWidget* parent,
89 90 91
    const QString& caption,
    const QString& dir,
    const QString& filter,
92
    const QString& defaultSuffix,
93
    bool strict,
94
    Options options)
95
{
96
    _validate(options);
97

98
#ifdef QT_DEBUG
dogmaphobic's avatar
dogmaphobic committed
99
#ifndef __mobile__
100
    if (qgcApp()->runningUnitTests()) {
101
        return UnitTest::_getSaveFileName(parent, caption, dir, filter, defaultSuffix, options);
102
    } else
dogmaphobic's avatar
dogmaphobic committed
103
#endif
104 105
#endif
    {
106
        QString defaultSuffixCopy(defaultSuffix);
107
        QFileDialog dlg(parent, caption, dir, filter);
108
        dlg.setAcceptMode(QFileDialog::AcceptSave);
109
        if (options) {
110
            dlg.setOptions(options);
111
        }
112
        if (!defaultSuffixCopy.isEmpty()) {
113
            //-- Make sure dot is not present
114 115
            if (defaultSuffixCopy.startsWith(".")) {
                defaultSuffixCopy.remove(0,1);
116
            }
117
            dlg.setDefaultSuffix(defaultSuffixCopy);
118
        }
119 120 121
        while (true) {
            if (dlg.exec()) {
                if (dlg.selectedFiles().count()) {
122 123 124 125 126 127 128 129 130 131 132 133
                    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?
134
                        if (defaultSuffixCopy.isEmpty()) {
135
                            //-- We don't, so get the first one in the filter
136
                            defaultSuffixCopy = _getFirstExtensionInFilter(filter);
137
                        }
138 139
                        //-- If this is set to strict, we have to have a default extension
                        Q_ASSERT(defaultSuffixCopy.isEmpty() == false);
140 141
                        //-- Forcefully append our desired extension
                        result += ".";
142
                        result += defaultSuffixCopy;
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
                        //-- 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;
164 165
                        }
                    }
166
                }
167
            }
168
            break;
169
        }
170
        return QString("");
171 172 173
    }
}

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/// @brief Make sure filename is using one of the valid extensions defined in the filter
bool QGCFileDialog::_validateExtension(const QString& filter, const QString& extension) {
    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
QString QGCFileDialog::_getFirstExtensionInFilter(const QString& filter) {
    QRegularExpression re("(\\*\\.\\w+)");
    QRegularExpressionMatchIterator i = re.globalMatch(filter);
    while (i.hasNext()) {
        QRegularExpressionMatch match = i.next();
        if (match.hasMatch()) {
197 198
            //-- Return "foo" from "*.foo"
            return match.captured(0).mid(2);
199 200 201 202 203
        }
    }
    return QString("");
}

204
/// @brief Validates and updates the parameters for the file dialog calls
205
void QGCFileDialog::_validate(Options& options)
206 207 208 209
{
    // You can't use QGCFileDialog if QGCApplication is not created yet.
    Q_ASSERT(qgcApp());
    
210
    Q_ASSERT_X(QThread::currentThread() == qgcApp()->thread(), "Threading issue", "QGCFileDialog can only be called from main thread");
dogmaphobic's avatar
dogmaphobic committed
211
#ifdef __mobile__
dogmaphobic's avatar
dogmaphobic committed
212 213
    Q_UNUSED(options)
#else
214
    // On OSX native dialog can hang so we always use Qt dialogs
Don Gagne's avatar
Don Gagne committed
215
    options |= DontUseNativeDialog;
dogmaphobic's avatar
dogmaphobic committed
216
#endif
217 218
    if (MainWindow::instance()) {
    }
219
}