Warning, file /office/calligra/libs/widgetutils/KoFileDialog.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 Copyright (C) 2013 - 2014 Yue Liu <yue.liu@mail.com> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KoFileDialog.h" 0021 #include <QDebug> 0022 #include <QFileDialog> 0023 #include <QApplication> 0024 #include <QImageReader> 0025 #include <QClipboard> 0026 0027 #include <kconfiggroup.h> 0028 #include <ksharedconfig.h> 0029 #include <klocalizedstring.h> 0030 0031 #include <QUrl> 0032 #include <QMimeDatabase> 0033 #include <QMimeType> 0034 0035 class Q_DECL_HIDDEN KoFileDialog::Private 0036 { 0037 public: 0038 Private(QWidget *parent_, 0039 KoFileDialog::DialogType dialogType_, 0040 const QString caption_, 0041 const QString defaultDir_, 0042 const QString dialogName_) 0043 : parent(parent_) 0044 , type(dialogType_) 0045 , dialogName(dialogName_) 0046 , caption(caption_) 0047 , defaultDirectory(defaultDir_) 0048 , filterList(QStringList()) 0049 , defaultFilter(QString()) 0050 , useStaticForNative(false) 0051 , hideDetails(false) 0052 , swapExtensionOrder(false) 0053 { 0054 // Force the native file dialogs on Windows. Except for KDE, the native file dialogs are only possible 0055 // using the static methods. The Qt documentation is wrong here, if it means what it says " By default, 0056 // the native file dialog is used unless you use a subclass of QFileDialog that contains the Q_OBJECT 0057 // macro." 0058 #ifdef Q_OS_WIN 0059 useStaticForNative = true; 0060 #endif 0061 // Non-static KDE file is broken when called with QFileDialog::AcceptSave: 0062 // then the directory above defaultdir is opened, and defaultdir is given as the default file name... 0063 // 0064 // So: in X11, use static methods inside KDE, which give working native dialogs, but non-static outside 0065 // KDE, which gives working Qt dialogs. 0066 // 0067 // Only show the GTK dialog in Gnome, where people deserve it 0068 #ifdef HAVE_X11 0069 if (qgetenv("KDE_FULL_SESSION").size() > 0) { 0070 useStaticForNative = true; 0071 } 0072 if (qgetenv("XDG_CURRENT_DESKTOP") == "GNOME") { 0073 useStaticForNative = true; 0074 QClipboard *cb = QApplication::clipboard(); 0075 cb->blockSignals(true); 0076 swapExtensionOrder = true; 0077 } 0078 0079 #endif 0080 } 0081 0082 ~Private() 0083 { 0084 if (qgetenv("XDG_CURRENT_DESKTOP") == "GNOME") { 0085 useStaticForNative = true; 0086 QClipboard *cb = QApplication::clipboard(); 0087 cb->blockSignals(false); 0088 } 0089 } 0090 0091 QWidget *parent; 0092 KoFileDialog::DialogType type; 0093 QString dialogName; 0094 QString caption; 0095 QString defaultDirectory; 0096 QStringList filterList; 0097 QString defaultFilter; 0098 QScopedPointer<QFileDialog> fileDialog; 0099 QMimeType mimeType; 0100 bool useStaticForNative; 0101 bool hideDetails; 0102 bool swapExtensionOrder; 0103 }; 0104 0105 KoFileDialog::KoFileDialog(QWidget *parent, 0106 KoFileDialog::DialogType type, 0107 const QString &dialogName) 0108 : d(new Private(parent, type, "", getUsedDir(dialogName), dialogName)) 0109 { 0110 } 0111 0112 KoFileDialog::~KoFileDialog() 0113 { 0114 delete d; 0115 } 0116 0117 void KoFileDialog::setCaption(const QString &caption) 0118 { 0119 d->caption = caption; 0120 } 0121 0122 void KoFileDialog::setDefaultDir(const QString &defaultDir, bool override) 0123 { 0124 if (override || d->defaultDirectory.isEmpty() || !QFile(d->defaultDirectory).exists()) { 0125 QFileInfo f(defaultDir); 0126 d->defaultDirectory = f.absoluteFilePath(); 0127 } 0128 } 0129 0130 void KoFileDialog::setOverrideDir(const QString &overrideDir) 0131 { 0132 d->defaultDirectory = overrideDir; 0133 } 0134 0135 void KoFileDialog::setImageFilters() 0136 { 0137 QStringList imageMimeTypes; 0138 foreach(const QByteArray &mimeType, QImageReader::supportedMimeTypes()) { 0139 imageMimeTypes << QLatin1String(mimeType); 0140 } 0141 setMimeTypeFilters(imageMimeTypes); 0142 } 0143 0144 void KoFileDialog::setNameFilter(const QString &filter) 0145 { 0146 d->filterList.clear(); 0147 if (d->type == KoFileDialog::SaveFile) { 0148 QStringList mimeList; 0149 d->filterList << splitNameFilter(filter, &mimeList); 0150 d->defaultFilter = d->filterList.first(); 0151 } 0152 else { 0153 d->filterList << filter; 0154 } 0155 } 0156 0157 void KoFileDialog::setNameFilters(const QStringList &filterList, 0158 QString defaultFilter) 0159 { 0160 d->filterList.clear(); 0161 0162 if (d->type == KoFileDialog::SaveFile) { 0163 QStringList mimeList; 0164 foreach(const QString &filter, filterList) { 0165 d->filterList << splitNameFilter(filter, &mimeList); 0166 } 0167 0168 if (!defaultFilter.isEmpty()) { 0169 mimeList.clear(); 0170 QStringList defaultFilters = splitNameFilter(defaultFilter, &mimeList); 0171 if (defaultFilters.size() > 0) { 0172 defaultFilter = defaultFilters.first(); 0173 } 0174 } 0175 } 0176 else { 0177 d->filterList = filterList; 0178 } 0179 d->defaultFilter = defaultFilter; 0180 0181 } 0182 0183 void KoFileDialog::setMimeTypeFilters(const QStringList &filterList, 0184 QString defaultFilter) 0185 { 0186 d->filterList = getFilterStringListFromMime(filterList, true); 0187 0188 if (!defaultFilter.isEmpty()) { 0189 QStringList defaultFilters = getFilterStringListFromMime(QStringList() << defaultFilter, false); 0190 if (defaultFilters.size() > 0) { 0191 defaultFilter = defaultFilters.first(); 0192 } 0193 } 0194 d->defaultFilter = defaultFilter; 0195 } 0196 0197 void KoFileDialog::setHideNameFilterDetailsOption() 0198 { 0199 d->hideDetails = true; 0200 } 0201 0202 QStringList KoFileDialog::nameFilters() const 0203 { 0204 return d->filterList; 0205 } 0206 0207 QString KoFileDialog::selectedNameFilter() const 0208 { 0209 if (!d->useStaticForNative) { 0210 return d->fileDialog->selectedNameFilter(); 0211 } 0212 else { 0213 return d->defaultFilter; 0214 } 0215 } 0216 0217 QString KoFileDialog::selectedMimeType() const 0218 { 0219 if (d->mimeType.isValid()) { 0220 return d->mimeType.name(); 0221 } 0222 else { 0223 return ""; 0224 } 0225 } 0226 0227 void KoFileDialog::createFileDialog() 0228 { 0229 d->fileDialog.reset(new QFileDialog(d->parent, d->caption, d->defaultDirectory)); 0230 0231 if (d->type == SaveFile) { 0232 d->fileDialog->setAcceptMode(QFileDialog::AcceptSave); 0233 d->fileDialog->setFileMode(QFileDialog::AnyFile); 0234 } 0235 else { // open / import 0236 0237 d->fileDialog->setAcceptMode(QFileDialog::AcceptOpen); 0238 0239 if (d->type == ImportDirectory 0240 || d->type == OpenDirectory) 0241 { 0242 d->fileDialog->setFileMode(QFileDialog::Directory); 0243 d->fileDialog->setOption(QFileDialog::ShowDirsOnly, true); 0244 } 0245 else { // open / import file(s) 0246 if (d->type == OpenFile 0247 || d->type == ImportFile) 0248 { 0249 d->fileDialog->setFileMode(QFileDialog::ExistingFile); 0250 } 0251 else { // files 0252 d->fileDialog->setFileMode(QFileDialog::ExistingFiles); 0253 } 0254 } 0255 } 0256 0257 d->fileDialog->setNameFilters(d->filterList); 0258 if (!d->defaultFilter.isEmpty()) { 0259 d->fileDialog->selectNameFilter(d->defaultFilter); 0260 } 0261 0262 if (d->type == ImportDirectory || 0263 d->type == ImportFile || d->type == ImportFiles || 0264 d->type == SaveFile) { 0265 d->fileDialog->setWindowModality(Qt::WindowModal); 0266 } 0267 0268 if (d->hideDetails) { 0269 d->fileDialog->setOption(QFileDialog::HideNameFilterDetails); 0270 } 0271 0272 connect(d->fileDialog.data(), SIGNAL(filterSelected(QString)), this, SLOT(filterSelected(QString))); 0273 } 0274 0275 QString KoFileDialog::filename() 0276 { 0277 QString url; 0278 if (!d->useStaticForNative) { 0279 0280 if (!d->fileDialog) { 0281 createFileDialog(); 0282 } 0283 0284 if (d->fileDialog->exec() == QDialog::Accepted) { 0285 url = d->fileDialog->selectedFiles().first(); 0286 } 0287 } 0288 else { 0289 switch (d->type) { 0290 case OpenFile: 0291 { 0292 url = QFileDialog::getOpenFileName(d->parent, 0293 d->caption, 0294 d->defaultDirectory, 0295 d->filterList.join(";;"), 0296 &d->defaultFilter); 0297 break; 0298 } 0299 case OpenDirectory: 0300 { 0301 url = QFileDialog::getExistingDirectory(d->parent, 0302 d->caption, 0303 d->defaultDirectory, 0304 QFileDialog::ShowDirsOnly); 0305 break; 0306 } 0307 case ImportFile: 0308 { 0309 url = QFileDialog::getOpenFileName(d->parent, 0310 d->caption, 0311 d->defaultDirectory, 0312 d->filterList.join(";;"), 0313 &d->defaultFilter); 0314 break; 0315 } 0316 case ImportDirectory: 0317 { 0318 url = QFileDialog::getExistingDirectory(d->parent, 0319 d->caption, 0320 d->defaultDirectory, 0321 QFileDialog::ShowDirsOnly); 0322 break; 0323 } 0324 case SaveFile: 0325 { 0326 url = QFileDialog::getSaveFileName(d->parent, 0327 d->caption, 0328 d->defaultDirectory, 0329 d->filterList.join(";;"), 0330 &d->defaultFilter); 0331 break; 0332 } 0333 default: 0334 ; 0335 } 0336 } 0337 0338 if (!url.isEmpty()) { 0339 0340 if (d->type == SaveFile && QFileInfo(url).suffix().isEmpty()) { 0341 int start = d->defaultFilter.lastIndexOf("*.") + 1; 0342 int end = d->defaultFilter.lastIndexOf(" )"); 0343 int n = end - start; 0344 QString extension = d->defaultFilter.mid(start, n); 0345 url.append(extension); 0346 } 0347 0348 QMimeDatabase db; 0349 d->mimeType = db.mimeTypeForFile(url); 0350 saveUsedDir(url, d->dialogName); 0351 } 0352 return url; 0353 } 0354 0355 QStringList KoFileDialog::filenames() 0356 { 0357 QStringList urls; 0358 0359 if (!d->useStaticForNative) { 0360 if (!d->fileDialog) { 0361 createFileDialog(); 0362 } 0363 if (d->fileDialog->exec() == QDialog::Accepted) { 0364 urls = d->fileDialog->selectedFiles(); 0365 } 0366 } 0367 else { 0368 switch (d->type) { 0369 case OpenFiles: 0370 case ImportFiles: 0371 { 0372 urls = QFileDialog::getOpenFileNames(d->parent, 0373 d->caption, 0374 d->defaultDirectory, 0375 d->filterList.join(";;"), 0376 &d->defaultFilter); 0377 break; 0378 } 0379 default: 0380 ; 0381 } 0382 } 0383 if (urls.size() > 0) { 0384 saveUsedDir(urls.first(), d->dialogName); 0385 } 0386 return urls; 0387 } 0388 0389 void KoFileDialog::filterSelected(const QString &filter) 0390 { 0391 // "Windows BMP image ( *.bmp )"; 0392 int start = filter.lastIndexOf("*.") + 2; 0393 int end = filter.lastIndexOf(" )"); 0394 int n = end - start; 0395 QString extension = filter.mid(start, n); 0396 d->defaultFilter = filter; 0397 d->fileDialog->setDefaultSuffix(extension); 0398 } 0399 0400 QStringList KoFileDialog::splitNameFilter(const QString &nameFilter, QStringList *mimeList) 0401 { 0402 Q_ASSERT(mimeList); 0403 0404 QStringList filters; 0405 QString description; 0406 0407 if (nameFilter.contains("(")) { 0408 description = nameFilter.left(nameFilter.indexOf("(") -1).trimmed(); 0409 } 0410 0411 QStringList entries = nameFilter.mid(nameFilter.indexOf("(") + 1).split(" ",QString::SkipEmptyParts ); 0412 0413 foreach(QString entry, entries) { 0414 0415 entry = entry.remove("*"); 0416 entry = entry.remove(")"); 0417 0418 QMimeDatabase db; 0419 QMimeType mime = db.mimeTypeForName("bla" + entry); 0420 if (mime.name() != "application/octet-stream") { 0421 if (!mimeList->contains(mime.name())) { 0422 mimeList->append(mime.name()); 0423 filters.append(mime.comment() + " ( *" + entry + " )"); 0424 } 0425 } 0426 else { 0427 filters.append(entry.remove(".").toUpper() + " " + description + " ( *." + entry + " )"); 0428 } 0429 } 0430 0431 return filters; 0432 } 0433 0434 const QStringList KoFileDialog::getFilterStringListFromMime(const QStringList &mimeList, 0435 bool withAllSupportedEntry) 0436 { 0437 QStringList mimeSeen; 0438 0439 QStringList ret; 0440 if (withAllSupportedEntry) { 0441 ret << QString(); 0442 } 0443 0444 for (QStringList::ConstIterator 0445 it = mimeList.begin(); it != mimeList.end(); ++it) { 0446 QMimeDatabase db; 0447 QMimeType mimeType = db.mimeTypeForName(*it); 0448 if (!mimeType.isValid()) { 0449 continue; 0450 } 0451 if (!mimeSeen.contains(mimeType.name())) { 0452 QString oneFilter; 0453 QStringList patterns = mimeType.globPatterns(); 0454 QStringList::ConstIterator jt; 0455 for (jt = patterns.constBegin(); jt != patterns.constEnd(); ++jt) { 0456 if (d->swapExtensionOrder) { 0457 oneFilter.prepend(*jt + " "); 0458 if (withAllSupportedEntry) { 0459 ret[0].prepend(*jt + " "); 0460 } 0461 } 0462 else { 0463 oneFilter.append(*jt + " "); 0464 if (withAllSupportedEntry) { 0465 ret[0].append(*jt + " "); 0466 } 0467 } 0468 } 0469 oneFilter = mimeType.comment() + " ( " + oneFilter + ")"; 0470 ret << oneFilter; 0471 mimeSeen << mimeType.name(); 0472 } 0473 } 0474 0475 if (withAllSupportedEntry) { 0476 ret[0] = i18n("All supported formats") + " ( " + ret[0] + (")"); 0477 } 0478 return ret; 0479 } 0480 0481 QString KoFileDialog::getUsedDir(const QString &dialogName) 0482 { 0483 if (dialogName.isEmpty()) return ""; 0484 0485 KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); 0486 QString dir = group.readEntry(dialogName); 0487 0488 return dir; 0489 } 0490 0491 void KoFileDialog::saveUsedDir(const QString &fileName, 0492 const QString &dialogName) 0493 { 0494 0495 if (dialogName.isEmpty()) return; 0496 0497 QFileInfo fileInfo(fileName); 0498 KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); 0499 group.writeEntry(dialogName, fileInfo.absolutePath()); 0500 0501 }