FileDialog.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <QApplication>
00027 # include <QButtonGroup>
00028 # include <QComboBox>
00029 # include <QGridLayout>
00030 # include <QGroupBox>
00031 # include <QLineEdit>
00032 # include <QPushButton>
00033 # include <QRadioButton>
00034 #endif
00035 
00036 #include <Base/Parameter.h>
00037 #include <App/Application.h>
00038 
00039 #include "FileDialog.h"
00040 #include "MainWindow.h"
00041 #include "BitmapFactory.h"
00042 
00043 using namespace Gui;
00044 
00045 
00046 /* TRANSLATOR Gui::FileDialog */
00047 
00051 QString FileDialog::getSaveFileName (QWidget * parent, const QString & caption, const QString & dir, 
00052                                      const QString & filter, QString * selectedFilter, Options options)
00053 {
00054     QString dirName = dir;
00055     if (dirName.isEmpty()) {
00056         dirName = getWorkingDirectory();
00057     } else {
00058         QFileInfo fi(dir);
00059         if (fi.isRelative()) {
00060             dirName = getWorkingDirectory();
00061             dirName += QLatin1String("/");
00062             dirName += fi.fileName();
00063         }
00064     
00065         // get the suffix for the filter
00066         QRegExp rx;
00067         rx.setPattern(QLatin1String("\\s(\\(\\*\\.\\w{1,})\\W"));
00068         int index = rx.indexIn(filter);
00069         if (index != -1) {
00070             // get the suffix with the leading dot
00071             QString suffix = filter.mid(index+3, rx.matchedLength()-4);
00072             if (fi.suffix().isEmpty())
00073                 dirName += suffix;
00074         }
00075     }
00076 
00077     QString windowTitle = caption;
00078     if (windowTitle.isEmpty())
00079         windowTitle = FileDialog::tr("Save as");
00080 
00081 #if defined(FC_OS_MACOSX)
00082     options |= QFileDialog::DontUseNativeDialog;
00083 #endif
00084     // NOTE: We must not change the specified file name afterwards as we may return the name of an already
00085     // existing file. Hence we must extract the first matching suffix from the filter list and append it 
00086     // before showing the file dialog.
00087     QString file = QFileDialog::getSaveFileName(parent, windowTitle, dirName, filter, selectedFilter, options);
00088     if (!file.isEmpty()) {
00089         setWorkingDirectory(file);
00090         return file;
00091     } else {
00092         return QString::null;
00093     }
00094 }
00095 
00099 QString FileDialog::getExistingDirectory( QWidget * parent, const QString & caption, const QString & dir, Options options )
00100 {
00101 #if defined(FC_OS_MACOSX)
00102     options |= QFileDialog::DontUseNativeDialog;
00103 #endif
00104     QString path = QFileDialog::getExistingDirectory(parent, caption, dir, options);
00105     // valid path was selected
00106     if ( !path.isEmpty() ) {
00107         QDir d(path);
00108         path = d.path(); // get path in Qt manner
00109     }
00110 
00111     return path;
00112 }
00113 
00118 QString FileDialog::getOpenFileName(QWidget * parent, const QString & caption, const QString & dir, 
00119                                     const QString & filter, QString * selectedFilter, Options options)
00120 {
00121     QString dirName = dir;
00122     if (dirName.isEmpty()) {
00123         dirName = getWorkingDirectory();
00124     }
00125 
00126     QString windowTitle = caption;
00127     if (windowTitle.isEmpty())
00128         windowTitle = FileDialog::tr("Open");
00129 #if defined(FC_OS_MACOSX)
00130     options |= QFileDialog::DontUseNativeDialog;
00131 #endif
00132     QString file = QFileDialog::getOpenFileName(parent, windowTitle, dirName, filter, selectedFilter, options);
00133     if (!file.isEmpty()) {
00134         setWorkingDirectory(file);
00135         return file;
00136     } else {
00137         return QString::null;
00138     }
00139 }
00140 
00144 QStringList FileDialog::getOpenFileNames (QWidget * parent, const QString & caption, const QString & dir,
00145                                           const QString & filter, QString * selectedFilter, Options options)
00146 {
00147     QString dirName = dir;
00148     if (dirName.isEmpty()) {
00149         dirName = getWorkingDirectory();
00150     }
00151 
00152     QString windowTitle = caption;
00153     if (windowTitle.isEmpty())
00154         windowTitle = FileDialog::tr("Open");
00155 #if defined(FC_OS_MACOSX)
00156     options |= QFileDialog::DontUseNativeDialog;
00157 #endif
00158     QStringList files = QFileDialog::getOpenFileNames(parent, windowTitle, dirName, filter, selectedFilter, options);
00159     if (!files.isEmpty()) {
00160         setWorkingDirectory(files.front());
00161     }
00162     
00163     return files;
00164 }
00165 
00171 QString FileDialog::getWorkingDirectory()
00172 {
00173     std::string path = App::GetApplication().Config()["UserHomePath"];
00174     Base::Reference<ParameterGrp> hPath = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
00175                                ->GetGroup("Preferences")->GetGroup("General");
00176     std::string dir = hPath->GetASCII("FileOpenSavePath", path.c_str());
00177     QFileInfo fi(QString::fromUtf8(dir.c_str()));
00178     if (!fi.exists())
00179         dir = path;
00180     return QString::fromUtf8(dir.c_str());
00181 }
00182 
00188 void FileDialog::setWorkingDirectory(const QString& dir)
00189 {
00190     QString dirName = dir;
00191     if (!dir.isEmpty()) {
00192         QFileInfo info(dir);
00193         dirName = info.absolutePath();
00194     }
00195 
00196     Base::Reference<ParameterGrp> hPath = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
00197                                ->GetGroup("Preferences")->GetGroup("General");
00198     hPath->SetASCII("FileOpenSavePath", dirName.toUtf8());
00199 }
00200 
00201 // ======================================================================
00202 
00203 /* TRANSLATOR Gui::FileOptionsDialog */
00204 
00205 FileOptionsDialog::FileOptionsDialog( QWidget* parent, Qt::WFlags fl )
00206   : QFileDialog( parent, fl )
00207 {
00208     extensionButton = new QPushButton( this );
00209     extensionButton->setText( tr( "Extended" ) );
00210 
00211     //search for the grid layout and add the new button
00212     QGridLayout* grid = this->findChild<QGridLayout*>();
00213 #if QT_VERSION >= 0x040500
00214     grid->addWidget(extensionButton, 4, 2, Qt::AlignLeft);
00215 #else
00216     grid->addWidget(extensionButton, 4, 5, Qt::AlignLeft);
00217 #endif
00218 
00219     connect(extensionButton, SIGNAL(clicked()), this, SLOT(toggleExtension()));
00220 
00221     // get the filter combobox to connect its activated() signal with our filterSelected() signal
00222     QComboBox* box = this->findChildren<QComboBox*>().last();
00223     connect(box, SIGNAL(activated(const QString&)), this, SIGNAL(filterSelected(const QString&)));
00224 }
00225 
00226 FileOptionsDialog::~FileOptionsDialog()
00227 {
00228 }
00229 
00230 void FileOptionsDialog::accept()
00231 {
00232     // Fixes a bug of the default implementation when entering an asterik
00233     QLineEdit* filename = this->findChild<QLineEdit*>();
00234     QString fn = filename->text();
00235     if (fn.startsWith(QLatin1String("*"))) {
00236         QFileInfo fi(fn);
00237         QString ext = fi.suffix();
00238         ext.prepend(QLatin1String("*."));
00239         QStringList filters = this->filters();
00240         bool ok=false;
00241         // Compare the given suffix with the suffixes of all filters
00242         QString filter;
00243         for (QStringList::ConstIterator it = filters.begin(); it != filters.end(); ++it) {
00244             if ((*it).contains(ext)) {
00245                 filter = *it;
00246                 ok = true;
00247                 break;
00248             }
00249         }
00250 
00251         // if no appropriate filter was found the add the 'All files' filter
00252         if (!ok) {
00253             filter = tr("All files (*.*)");
00254             filters << filter;
00255             setFilters(filters);
00256         }
00257 
00258         // empty the line edit
00259         filename->blockSignals(true);
00260         filename->clear();
00261         filename->blockSignals(false);
00262         selectFilter(filter);
00263 
00264         return;
00265     }
00266     else if (!fn.isEmpty()) {
00267         QFileInfo fi(fn);
00268         QString ext = fi.completeSuffix();
00269         QRegExp rx(QLatin1String("\\(\\*.(\\w+)"));
00270         QString suf = selectedFilter();
00271         if (rx.indexIn(suf) >= 0)
00272             suf = rx.cap(1);
00273         if (ext.isEmpty())
00274             setDefaultSuffix(suf);
00275         else if (ext.toLower() != suf.toLower()) {
00276             fn = QString::fromAscii("%1.%2").arg(fn).arg(suf);
00277             selectFile(fn);
00278         }
00279     }
00280 
00281     QFileDialog::accept();
00282 }
00283 
00284 void FileOptionsDialog::toggleExtension()
00285 {
00286     QWidget* w = extension();
00287     if (w)
00288         showExtension(!w->isVisible());
00289 }
00290 
00291 void FileOptionsDialog::setOptionsWidget(FileOptionsDialog::ExtensionPosition pos, QWidget* w, bool show)
00292 {
00293     if (pos == ExtensionRight) {
00294         setExtension(w);
00295         setOrientation(Qt::Horizontal);
00296     }
00297     else if (pos == ExtensionBottom) {
00298         setExtension(w);
00299         setOrientation(Qt::Vertical);
00300     }
00301 
00302     w->hide();
00303     if (show)
00304         toggleExtension();
00305 }
00306 
00307 QWidget* FileOptionsDialog::getOptionsWidget() const
00308 {
00309     return this->extension();
00310 }
00311 
00312 // ======================================================================
00313 
00317 FileIconProvider::FileIconProvider()
00318 {
00319 }
00320 
00321 FileIconProvider::~FileIconProvider()
00322 {
00323 }
00324 
00325 QIcon FileIconProvider::icon ( IconType type ) const
00326 {
00327     return QFileIconProvider::icon(type);
00328 }
00329 
00330 QIcon FileIconProvider::icon ( const QFileInfo & info ) const
00331 {
00332     return QFileIconProvider::icon(info);
00333 }
00334 
00335 QString FileIconProvider::type ( const QFileInfo & info ) const
00336 {
00337     return QFileIconProvider::type(info);
00338 }
00339 
00340 // --------------------------------------------------------------------
00341 
00342 /* TRANSLATOR Gui::FileChooser */
00343 
00347 FileChooser::FileChooser ( QWidget * parent )
00348   : QWidget(parent), md( File ), _filter( QString::null )
00349 {
00350     QHBoxLayout *layout = new QHBoxLayout( this );
00351     layout->setMargin( 0 );
00352     layout->setSpacing( 6 );
00353 
00354     lineEdit = new QLineEdit( this );
00355     layout->addWidget( lineEdit );
00356 
00357     connect(lineEdit, SIGNAL(textChanged(const QString &)),
00358             this, SIGNAL(fileNameChanged(const QString &)));
00359 
00360     button = new QPushButton(QLatin1String("..."), this);
00361     button->setFixedWidth(2*button->fontMetrics().width(QLatin1String(" ... ")));
00362     layout->addWidget(button);
00363 
00364     connect( button, SIGNAL(clicked()), this, SLOT(chooseFile()));
00365 
00366     setFocusProxy(lineEdit);
00367 }
00368 
00369 FileChooser::~FileChooser()
00370 {
00371 }
00372 
00381 QString FileChooser::fileName() const
00382 {
00383     return lineEdit->text();
00384 }
00385 
00389 void FileChooser::setFileName( const QString& s )
00390 {
00391     lineEdit->setText( s );
00392 }
00393 
00398 void FileChooser::chooseFile()
00399 {
00400     QString fn;
00401     if ( mode() == File )
00402         fn = QFileDialog::getOpenFileName( this, tr( "Select a file" ), lineEdit->text(), _filter );
00403     else
00404         fn = QFileDialog::getExistingDirectory( this, tr( "Select a directory" ), lineEdit->text() );
00405 
00406     if ( !fn.isEmpty() ) {
00407         lineEdit->setText( fn );
00408         fileNameSelected( fn );
00409     }
00410 }
00411 
00420 FileChooser::Mode FileChooser::mode() const
00421 {
00422     return md;
00423 }
00424 
00429 void FileChooser::setMode( FileChooser::Mode m )
00430 {
00431     md = m;
00432 }
00433 
00442 QString FileChooser::filter() const
00443 {
00444     return _filter;
00445 }
00446 
00450 void FileChooser::setFilter ( const QString& filter )
00451 {
00452     _filter = filter;
00453 }
00454 
00458 void FileChooser::setButtonText( const QString& txt )
00459 {
00460     button->setText( txt );
00461     int w1 = 2*button->fontMetrics().width(txt);
00462     int w2 = 2*button->fontMetrics().width(QLatin1String(" ... "));
00463     button->setFixedWidth( (w1 > w2 ? w1 : w2) );
00464 }
00465 
00469 QString FileChooser::buttonText() const
00470 {
00471     return button->text();
00472 }
00473 
00474 // ----------------------------------------------------------------------
00475 
00476 /* TRANSLATOR Gui::SelectModule */
00477 
00478 SelectModule::SelectModule (const QString& type, const SelectModule::Dict& types, QWidget * parent)
00479   : QDialog(parent, Qt::WindowTitleHint)
00480 {
00481     setWindowTitle(tr("Select module"));
00482     groupBox = new QGroupBox(this);
00483     groupBox->setTitle(tr("Open %1 as").arg(type));
00484 
00485     group = new QButtonGroup(this);
00486     gridLayout = new QGridLayout(this);
00487     gridLayout->setSpacing(6);
00488     gridLayout->setMargin(9);
00489 
00490     gridLayout1 = new QGridLayout(groupBox);
00491     gridLayout1->setSpacing(6);
00492     gridLayout1->setMargin(9);
00493 
00494     int index = 0;
00495     for (SelectModule::Dict::const_iterator it = types.begin(); it != types.end(); ++it) {
00496         QRadioButton* button = new QRadioButton(groupBox);
00497 
00498         QRegExp rx;
00499         QString filter = it.key();
00500         QString module = it.value();
00501 
00502         // ignore file types in (...)
00503         rx.setPattern(QLatin1String("\\s+\\([\\w\\*\\s\\.]+\\)$"));
00504         int pos = rx.indexIn(filter);
00505         if (pos != -1) {
00506             filter = filter.left(pos);
00507         }
00508 
00509         // ignore Gui suffix in module name
00510         rx.setPattern(QLatin1String("Gui$"));
00511         pos = rx.indexIn(module);
00512         if (pos != -1) {
00513             module = module.left(pos);
00514         }
00515 
00516         button->setText(QString::fromAscii("%1 (%2)").arg(filter).arg(module));
00517         button->setObjectName(it.value());
00518         gridLayout1->addWidget(button, index, 0, 1, 1);
00519         group->addButton(button, index);
00520         index++;
00521     }
00522 
00523     gridLayout->addWidget(groupBox, 0, 0, 1, 1);
00524     spacerItem = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
00525     gridLayout->addItem(spacerItem, 1, 0, 1, 1);
00526 
00527     hboxLayout = new QHBoxLayout();
00528     hboxLayout->setSpacing(6);
00529     hboxLayout->setMargin(0);
00530     spacerItem1 = new QSpacerItem(131, 31, QSizePolicy::Expanding, QSizePolicy::Minimum);
00531     hboxLayout->addItem(spacerItem1);
00532 
00533     okButton = new QPushButton(this);
00534     okButton->setObjectName(QString::fromUtf8("okButton"));
00535     okButton->setText(tr("Select"));
00536     okButton->setEnabled(false);
00537 
00538     hboxLayout->addWidget(okButton);
00539     gridLayout->addLayout(hboxLayout, 2, 0, 1, 1);
00540 
00541     // connections
00542     connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
00543     connect(group, SIGNAL(buttonClicked(int)), this, SLOT(onButtonClicked()));
00544 }
00545 
00546 SelectModule::~SelectModule()
00547 {
00548 }
00549 
00550 void SelectModule::accept()
00551 {
00552     if (group->checkedButton())
00553         QDialog::accept();
00554 }
00555 
00556 void SelectModule::reject()
00557 {
00558     if (group->checkedButton())
00559         QDialog::reject();
00560 }
00561 
00562 void SelectModule::onButtonClicked()
00563 {
00564     if (group->checkedButton())
00565         okButton->setEnabled(true);
00566     else
00567         okButton->setEnabled(false);
00568 }
00569 
00570 QString SelectModule::getModule() const
00571 {
00572     QAbstractButton* button = group->checkedButton();
00573     return (button ? button->objectName() : QString());
00574 }
00575 
00576 SelectModule::Dict SelectModule::exportHandler(const QString& fileName, const QString& filter)
00577 {
00578     return exportHandler(QStringList() << fileName, filter);
00579 }
00580 
00581 SelectModule::Dict SelectModule::exportHandler(const QStringList& fileNames, const QString& filter)
00582 {
00583     // first check if there is a certain filter selected
00584     SelectModule::Dict dict;
00585     if (!filter.isEmpty()) {
00586         // If an export filter is specified search directly for the module
00587         std::map<std::string, std::string> filterList = App::GetApplication().getExportFilters();
00588         std::map<std::string, std::string>::const_iterator it;
00589         it = filterList.find((const char*)filter.toUtf8());
00590         if (it != filterList.end()) {
00591             QString module = QString::fromAscii(it->second.c_str());
00592             for (QStringList::const_iterator it = fileNames.begin(); it != fileNames.end(); ++it) {
00593                 dict[*it] = module;
00594             }
00595             return dict;
00596         }
00597     }
00598 
00599     // the global filter (or no filter) was selected. We now try to sort filetypes that are
00600     // handled by more than one module and ask to the user to select one.
00601     QMap<QString, SelectModule::Dict> filetypeHandler;
00602     QMap<QString, QStringList > fileExtension;
00603     for (QStringList::const_iterator it = fileNames.begin(); it != fileNames.end(); ++it) {
00604         QFileInfo fi(*it);
00605         QString ext = fi.completeSuffix().toLower();
00606         std::map<std::string, std::string> filters = App::GetApplication().getExportFilters(ext.toAscii());
00607         
00608         if (filters.empty()) {
00609             ext = fi.suffix().toLower();
00610             filters = App::GetApplication().getExportFilters(ext.toAscii());
00611         }
00612 
00613         fileExtension[ext].push_back(*it);
00614         for (std::map<std::string, std::string>::iterator jt = filters.begin(); jt != filters.end(); ++jt)
00615             filetypeHandler[ext][QString::fromUtf8(jt->first.c_str())] = QString::fromAscii(jt->second.c_str());
00616         // set the default module handler
00617         if (!filters.empty())
00618             dict[*it] = QString::fromAscii(filters.begin()->second.c_str());
00619     }
00620 
00621     for (QMap<QString, SelectModule::Dict>::const_iterator it = filetypeHandler.begin(); 
00622         it != filetypeHandler.end(); ++it) {
00623         if (it.value().size() > 1) {
00624             SelectModule dlg(it.key(),it.value(), getMainWindow());
00625             QApplication::beep();
00626             if (dlg.exec()) {
00627                 QString mod = dlg.getModule();
00628                 const QStringList& files = fileExtension[it.key()];
00629                 for (QStringList::const_iterator jt = files.begin(); jt != files.end(); ++jt)
00630                     dict[*jt] = mod;
00631             }
00632         }
00633     }
00634 
00635     return dict;
00636 }
00637 
00638 SelectModule::Dict SelectModule::importHandler(const QString& fileName, const QString& filter)
00639 {
00640     return importHandler(QStringList() << fileName, filter);
00641 }
00642 
00643 SelectModule::Dict SelectModule::importHandler(const QStringList& fileNames, const QString& filter)
00644 {
00645     // first check if there is a certain filter selected
00646     SelectModule::Dict dict;
00647     if (!filter.isEmpty()) {
00648         // If an import filter is specified search directly for the module
00649         std::map<std::string, std::string> filterList = App::GetApplication().getImportFilters();
00650         std::map<std::string, std::string>::const_iterator it;
00651         it = filterList.find((const char*)filter.toUtf8());
00652         if (it != filterList.end()) {
00653             QString module = QString::fromAscii(it->second.c_str());
00654             for (QStringList::const_iterator it = fileNames.begin(); it != fileNames.end(); ++it) {
00655                 dict[*it] = module;
00656             }
00657             return dict;
00658         }
00659     }
00660 
00661     // the global filter (or no filter) was selected. We now try to sort filetypes that are
00662     // handled by more than one module and ask to the user to select one.
00663     QMap<QString, SelectModule::Dict> filetypeHandler;
00664     QMap<QString, QStringList > fileExtension;
00665     for (QStringList::const_iterator it = fileNames.begin(); it != fileNames.end(); ++it) {
00666         QFileInfo fi(*it);
00667         QString ext = fi.completeSuffix().toLower();
00668         std::map<std::string, std::string> filters = App::GetApplication().getImportFilters(ext.toAscii());
00669         
00670         if (filters.empty()) {
00671             ext = fi.suffix().toLower();
00672             filters = App::GetApplication().getImportFilters(ext.toAscii());
00673         }
00674 
00675         fileExtension[ext].push_back(*it);
00676         for (std::map<std::string, std::string>::iterator jt = filters.begin(); jt != filters.end(); ++jt)
00677             filetypeHandler[ext][QString::fromUtf8(jt->first.c_str())] = QString::fromAscii(jt->second.c_str());
00678         // set the default module handler
00679         if (!filters.empty())
00680             dict[*it] = QString::fromAscii(filters.begin()->second.c_str());
00681     }
00682 
00683     for (QMap<QString, SelectModule::Dict>::const_iterator it = filetypeHandler.begin(); 
00684         it != filetypeHandler.end(); ++it) {
00685         if (it.value().size() > 1) {
00686             SelectModule dlg(it.key(),it.value(), getMainWindow());
00687             QApplication::beep();
00688             if (dlg.exec()) {
00689                 QString mod = dlg.getModule();
00690                 const QStringList& files = fileExtension[it.key()];
00691                 for (QStringList::const_iterator jt = files.begin(); jt != files.end(); ++jt)
00692                     dict[*jt] = mod;
00693             }
00694         }
00695     }
00696 
00697     return dict;
00698 }
00699 
00700 
00701 #include "moc_FileDialog.cpp"
00702 

Generated on Wed Nov 23 19:00:14 2011 for FreeCAD by  doxygen 1.6.1