• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KFile

kfilewidget.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 /* This file is part of the KDE libraries
00003     Copyright (C) 1997, 1998 Richard Moore <rich@kde.org>
00004                   1998 Stephan Kulow <coolo@kde.org>
00005                   1998 Daniel Grana <grana@ie.iwi.unibe.ch>
00006                   1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
00007                   2003 Clarence Dang <dang@kde.org>
00008                   2007 David Faure <faure@kde.org>
00009                   2008 Rafael Fernández López <ereslibre@kde.org>
00010 
00011     This library is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU Library General Public
00013     License as published by the Free Software Foundation; either
00014     version 2 of the License, or (at your option) any later version.
00015 
00016     This library is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019     Library General Public License for more details.
00020 
00021     You should have received a copy of the GNU Library General Public License
00022     along with this library; see the file COPYING.LIB.  If not, write to
00023     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00024     Boston, MA 02110-1301, USA.
00025 */
00026 
00027 #include "kfilewidget.h"
00028 
00029 #include "kfileplacesview.h"
00030 #include "kfileplacesmodel.h"
00031 #include "kfilebookmarkhandler_p.h"
00032 #include "kurlcombobox.h"
00033 #include "kurlnavigator.h"
00034 #include "kfilepreviewgenerator.h"
00035 #include <config-kfile.h>
00036 
00037 #include <kactioncollection.h>
00038 #include <kdiroperator.h>
00039 #include <kdirselectdialog.h>
00040 #include <kfilefiltercombo.h>
00041 #include <kimagefilepreview.h>
00042 #include <kmenu.h>
00043 #include <kmimetype.h>
00044 #include <kpushbutton.h>
00045 #include <krecentdocument.h>
00046 #include <ktoolbar.h>
00047 #include <kurlcompletion.h>
00048 #include <kuser.h>
00049 #include <kprotocolmanager.h>
00050 #include <kio/job.h>
00051 #include <kio/jobuidelegate.h>
00052 #include <kio/netaccess.h>
00053 #include <kio/scheduler.h>
00054 #include <krecentdirs.h>
00055 #include <kdebug.h>
00056 #include <kio/kfileitemdelegate.h>
00057 
00058 #include <QtGui/QCheckBox>
00059 #include <QtGui/QDockWidget>
00060 #include <QtGui/QLayout>
00061 #include <QtGui/QLabel>
00062 #include <QtGui/QLineEdit>
00063 #include <QtGui/QSplitter>
00064 #include <QtGui/QAbstractProxyModel>
00065 #include <QtGui/QHelpEvent>
00066 #include <QtGui/QApplication>
00067 #include <QtCore/QFSFileEngine>
00068 #include <kshell.h>
00069 #include <kmessagebox.h>
00070 #include <kauthorized.h>
00071 
00072 class KFileWidgetPrivate
00073 {
00074 public:
00075     KFileWidgetPrivate(KFileWidget *widget)
00076         : q(widget),
00077           boxLayout(0),
00078           placesDock(0),
00079           placesView(0),
00080           placesViewSplitter(0),
00081           placesViewWidth(-1),
00082           labeledCustomWidget(0),
00083           bottomCustomWidget(0),
00084           autoSelectExtCheckBox(0),
00085           operationMode(KFileWidget::Opening),
00086           bookmarkHandler(0),
00087           toolbar(0),
00088           locationEdit(0),
00089           ops(0),
00090           filterWidget(0),
00091           autoSelectExtChecked(false),
00092           keepLocation(false),
00093           hasView(false),
00094           hasDefaultFilter(false),
00095           inAccept(false),
00096           dummyAdded(false),
00097           confirmOverwrite(false),
00098           differentHierarchyLevelItemsEntered(false),
00099           previewGenerator(0),
00100           iconSizeSlider(0)
00101     {
00102     }
00103 
00104     ~KFileWidgetPrivate()
00105     {
00106         delete bookmarkHandler; // Should be deleted before ops!
00107         delete ops;
00108     }
00109 
00110     void updateLocationWhatsThis();
00111     void updateAutoSelectExtension();
00112     void initSpeedbar();
00113     void initGUI();
00114     void readConfig(KConfigGroup &configGroup);
00115     void writeConfig(KConfigGroup &configGroup);
00116     void setNonExtSelection();
00117     void setLocationText(const KUrl&);
00118     void setLocationText(const KUrl::List&);
00119     void appendExtension(KUrl &url);
00120     void updateLocationEditExtension(const QString &);
00121     void updateFilter();
00122     KUrl::List& parseSelectedUrls();
00129     KUrl::List tokenize(const QString& line) const;
00133     void readRecentFiles(KConfigGroup &cg);
00137     void saveRecentFiles(KConfigGroup &cg);
00142     void multiSelectionChanged();
00143 
00147     KUrl getCompleteUrl(const QString&) const;
00148 
00153     void setDummyHistoryEntry(const QString& text, const QPixmap& icon = QPixmap(),
00154                               bool usePreviousPixmapIfNull = true);
00155 
00159     void removeDummyHistoryEntry();
00160 
00167     bool toOverwrite(const KUrl&);
00168 
00169     // private slots
00170     void _k_slotLocationChanged( const QString& );
00171     void _k_urlEntered( const KUrl& );
00172     void _k_enterUrl( const KUrl& );
00173     void _k_enterUrl( const QString& );
00174     void _k_locationAccepted( const QString& );
00175     void _k_slotFilterChanged();
00176     void _k_fileHighlighted( const KFileItem& );
00177     void _k_fileSelected( const KFileItem& );
00178     void _k_slotLoadingFinished();
00179     void _k_fileCompletion( const QString& );
00180     void _k_toggleSpeedbar( bool );
00181     void _k_toggleBookmarks( bool );
00182     void _k_slotAutoSelectExtClicked();
00183     void _k_placesViewSplitterMoved(int, int);
00184     void _k_activateUrlNavigator();
00185     void _k_zoomOutIconsSize();
00186     void _k_zoomInIconsSize();
00187     void _k_slotIconSizeSliderMoved(int);
00188     void _k_slotIconSizeChanged(int);
00189     void _k_slotViewDoubleClicked(const QModelIndex&);
00190 
00191     void addToRecentDocuments();
00192 
00193     QString locationEditCurrentText() const;
00194 
00200     static KUrl mostLocalUrl(const KUrl &url);
00201 
00202     void setInlinePreviewShown(bool show);
00203 
00204     KFileWidget* q;
00205 
00206     // the last selected url
00207     KUrl url;
00208 
00209     // the selected filenames in multiselection mode -- FIXME
00210     QString filenames;
00211 
00212     // now following all kind of widgets, that I need to rebuild
00213     // the geometry management
00214     QBoxLayout *boxLayout;
00215     QGridLayout *lafBox;
00216     QVBoxLayout *vbox;
00217 
00218     QLabel *locationLabel;
00219     QWidget *opsWidget;
00220     QWidget *pathSpacer;
00221 
00222     QLabel *filterLabel;
00223     KUrlNavigator *urlNavigator;
00224     KPushButton *okButton, *cancelButton;
00225     QDockWidget *placesDock;
00226     KFilePlacesView *placesView;
00227     QSplitter *placesViewSplitter;
00228     // caches the places view width. This value will be updated when the splitter
00229     // is moved. This allows us to properly set a value when the dialog itself
00230     // is resized
00231     int placesViewWidth;
00232 
00233     QWidget *labeledCustomWidget;
00234     QWidget *bottomCustomWidget;
00235 
00236     // Automatically Select Extension stuff
00237     QCheckBox *autoSelectExtCheckBox;
00238     QString extension; // current extension for this filter
00239 
00240     QList<KIO::StatJob*> statJobs;
00241 
00242     KUrl::List urlList; //the list of selected urls
00243 
00244     KFileWidget::OperationMode operationMode;
00245 
00246     // The file class used for KRecentDirs
00247     QString fileClass;
00248 
00249     KFileBookmarkHandler *bookmarkHandler;
00250 
00251     KActionMenu* bookmarkButton;
00252 
00253     KToolBar *toolbar;
00254     KUrlComboBox *locationEdit;
00255     KDirOperator *ops;
00256     KFileFilterCombo *filterWidget;
00257 
00258     KFilePlacesModel *model;
00259 
00260     // whether or not the _user_ has checked the above box
00261     bool autoSelectExtChecked : 1;
00262 
00263     // indicates if the location edit should be kept or cleared when changing
00264     // directories
00265     bool keepLocation : 1;
00266 
00267     // the KDirOperators view is set in KFileWidget::show(), so to avoid
00268     // setting it again and again, we have this nice little boolean :)
00269     bool hasView : 1;
00270 
00271     bool hasDefaultFilter : 1; // necessary for the operationMode
00272     bool autoDirectoryFollowing : 1;
00273     bool inAccept : 1; // true between beginning and end of accept()
00274     bool dummyAdded : 1; // if the dummy item has been added. This prevents the combo from having a
00275                      // blank item added when loaded
00276     bool confirmOverwrite : 1;
00277     bool differentHierarchyLevelItemsEntered;
00278 
00279     KFilePreviewGenerator *previewGenerator;
00280     QSlider *iconSizeSlider;
00281 };
00282 
00283 K_GLOBAL_STATIC(KUrl, lastDirectory) // to set the start path
00284 
00285 static const char autocompletionWhatsThisText[] = I18N_NOOP("<qt>While typing in the text area, you may be presented "
00286                                                   "with possible matches. "
00287                                                   "This feature can be controlled by clicking with the right mouse button "
00288                                                   "and selecting a preferred mode from the <b>Text Completion</b> menu.</qt>");
00289 
00290 // returns true if the string contains "<a>:/" sequence, where <a> is at least 2 alpha chars
00291 static bool containsProtocolSection( const QString& string )
00292 {
00293     int len = string.length();
00294     static const char prot[] = ":/";
00295     for (int i=0; i < len;) {
00296         i = string.indexOf( QLatin1String(prot), i );
00297         if (i == -1)
00298             return false;
00299         int j=i-1;
00300         for (; j >= 0; j--) {
00301             const QChar& ch( string[j] );
00302             if (ch.toAscii() == 0 || !ch.isLetter())
00303                 break;
00304             if (ch.isSpace() && (i-j-1) >= 2)
00305                 return true;
00306         }
00307         if (j < 0 && i >= 2)
00308             return true; // at least two letters before ":/"
00309         i += 3; // skip : and / and one char
00310     }
00311     return false;
00312 }
00313 
00314 KFileWidget::KFileWidget( const KUrl& _startDir, QWidget *parent )
00315     : QWidget(parent), KAbstractFileWidget(), d(new KFileWidgetPrivate(this))
00316 {
00317     KUrl startDir(_startDir);
00318     kDebug(kfile_area) << "startDir" << startDir;
00319     QString filename;
00320 
00321     d->okButton = new KPushButton(KStandardGuiItem::ok(), this);
00322     d->okButton->setDefault(true);
00323     d->cancelButton = new KPushButton(KStandardGuiItem::cancel(), this);
00324     // The dialog shows them
00325     d->okButton->hide();
00326     d->cancelButton->hide();
00327 
00328     d->opsWidget = new QWidget(this);
00329     QVBoxLayout *opsWidgetLayout = new QVBoxLayout(d->opsWidget);
00330     opsWidgetLayout->setMargin(0);
00331     opsWidgetLayout->setSpacing(0);
00332     //d->toolbar = new KToolBar(this, true);
00333     d->toolbar = new KToolBar(d->opsWidget, true);
00334     d->toolbar->setObjectName("KFileWidget::toolbar");
00335     d->toolbar->setMovable(false);
00336     opsWidgetLayout->addWidget(d->toolbar);
00337 
00338     d->model = new KFilePlacesModel(this);
00339 
00340     // Resolve this now so that a 'kfiledialog:' URL, if specified,
00341     // does not get inserted into the urlNavigator history.
00342     d->url = getStartUrl( startDir, d->fileClass, filename );
00343     startDir = d->url;
00344 
00345     d->urlNavigator = new KUrlNavigator(d->model, startDir, d->opsWidget); //d->toolbar);
00346     d->urlNavigator->setPlacesSelectorVisible(false);
00347     opsWidgetLayout->addWidget(d->urlNavigator);
00348 
00349     KUrl u;
00350     KUrlComboBox *pathCombo = d->urlNavigator->editor();
00351 #ifdef Q_WS_WIN
00352     foreach( const QFileInfo &drive,QFSFileEngine::drives() )
00353     {
00354         u.setPath( drive.filePath() );
00355         pathCombo->addDefaultUrl(u,
00356                                  KIO::pixmapForUrl( u, 0, KIconLoader::Small ),
00357                                  i18n("Drive: %1",  u.toLocalFile()));
00358     }
00359 #else
00360     u.setPath(QDir::rootPath());
00361     pathCombo->addDefaultUrl(u,
00362                              KIO::pixmapForUrl(u, 0, KIconLoader::Small),
00363                              u.toLocalFile());
00364 #endif
00365 
00366     u.setPath(QDir::homePath());
00367     pathCombo->addDefaultUrl(u, KIO::pixmapForUrl(u, 0, KIconLoader::Small),
00368                              u.path(KUrl::AddTrailingSlash));
00369 
00370     KUrl docPath;
00371     docPath.setPath( KGlobalSettings::documentPath() );
00372     if ( (u.path(KUrl::AddTrailingSlash) != docPath.path(KUrl::AddTrailingSlash)) &&
00373           QDir(docPath.path(KUrl::AddTrailingSlash)).exists() )
00374     {
00375         pathCombo->addDefaultUrl( docPath,
00376                                   KIO::pixmapForUrl( docPath, 0, KIconLoader::Small ),
00377                                   docPath.path(KUrl::AddTrailingSlash));
00378     }
00379 
00380     u.setPath( KGlobalSettings::desktopPath() );
00381     pathCombo->addDefaultUrl(u,
00382                              KIO::pixmapForUrl(u, 0, KIconLoader::Small),
00383                              u.path(KUrl::AddTrailingSlash));
00384 
00385     d->ops = new KDirOperator(KUrl(), d->opsWidget);
00386     d->ops->setObjectName( "KFileWidget::ops" );
00387     d->ops->setIsSaving(d->operationMode == Saving);
00388     opsWidgetLayout->addWidget(d->ops);
00389     connect(d->ops, SIGNAL(urlEntered(const KUrl&)),
00390             SLOT(_k_urlEntered(const KUrl&)));
00391     connect(d->ops, SIGNAL(fileHighlighted(const KFileItem &)),
00392             SLOT(_k_fileHighlighted(const KFileItem &)));
00393     connect(d->ops, SIGNAL(fileSelected(const KFileItem &)),
00394             SLOT(_k_fileSelected(const KFileItem &)));
00395     connect(d->ops, SIGNAL(finishedLoading()),
00396             SLOT(_k_slotLoadingFinished()));
00397 
00398     d->ops->setupMenu(KDirOperator::SortActions |
00399                    KDirOperator::FileActions |
00400                    KDirOperator::ViewActions);
00401     KActionCollection *coll = d->ops->actionCollection();
00402 
00403     // add nav items to the toolbar
00404     //
00405     // NOTE:  The order of the button icons here differs from that
00406     // found in the file manager and web browser, but has been discussed
00407     // and agreed upon on the kde-core-devel mailing list:
00408     //
00409     // http://lists.kde.org/?l=kde-core-devel&m=116888382514090&w=2
00410 
00411     coll->action( "up" )->setWhatsThis(i18n("<qt>Click this button to enter the parent folder.<br /><br />"
00412                                             "For instance, if the current location is file:/home/%1 clicking this "
00413                                             "button will take you to file:/home.</qt>",  KUser().loginName() ));
00414 
00415     coll->action( "back" )->setWhatsThis(i18n("Click this button to move backwards one step in the browsing history."));
00416     coll->action( "forward" )->setWhatsThis(i18n("Click this button to move forward one step in the browsing history."));
00417 
00418     coll->action( "reload" )->setWhatsThis(i18n("Click this button to reload the contents of the current location."));
00419     coll->action( "mkdir" )->setShortcut( QKeySequence(Qt::Key_F10) );
00420     coll->action( "mkdir" )->setWhatsThis(i18n("Click this button to create a new folder."));
00421 
00422     KAction *goToNavigatorAction = coll->addAction( "gotonavigator", this, SLOT( _k_activateUrlNavigator() ) );
00423     goToNavigatorAction->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_L) );
00424 
00425     KToggleAction *showSidebarAction =
00426         new KToggleAction(i18n("Show Places Navigation Panel"), this);
00427     coll->addAction("toggleSpeedbar", showSidebarAction);
00428     showSidebarAction->setShortcut( QKeySequence(Qt::Key_F9) );
00429     connect( showSidebarAction, SIGNAL( toggled( bool ) ),
00430              SLOT( _k_toggleSpeedbar( bool )) );
00431 
00432     KToggleAction *showBookmarksAction =
00433         new KToggleAction(i18n("Show Bookmarks"), this);
00434     coll->addAction("toggleBookmarks", showBookmarksAction);
00435     connect( showBookmarksAction, SIGNAL( toggled( bool ) ),
00436              SLOT( _k_toggleBookmarks( bool )) );
00437 
00438     KActionMenu *menu = new KActionMenu( KIcon("configure"), i18n("Options"), this);
00439     coll->addAction("extra menu", menu);
00440     menu->setWhatsThis(i18n("<qt>This is the preferences menu for the file dialog. "
00441                             "Various options can be accessed from this menu including: <ul>"
00442                             "<li>how files are sorted in the list</li>"
00443                             "<li>types of view, including icon and list</li>"
00444                             "<li>showing of hidden files</li>"
00445                             "<li>the Places navigation panel</li>"
00446                             "<li>file previews</li>"
00447                             "<li>separating folders from files</li></ul></qt>"));
00448     menu->addAction(coll->action("sorting menu"));
00449     menu->addAction(coll->action("view menu"));
00450     menu->addSeparator();
00451     menu->addAction(coll->action("decoration menu"));
00452     menu->addSeparator();
00453     KAction * showHidden = qobject_cast<KAction*>(coll->action( "show hidden" ));
00454     if (showHidden) {
00455         showHidden->setShortcut(
00456                     KShortcut( QKeySequence(Qt::ALT + Qt::Key_Period), QKeySequence(Qt::Key_F8) ) );
00457     }
00458     menu->addAction( showHidden );
00459     menu->addAction( showSidebarAction );
00460     menu->addAction( showBookmarksAction );
00461     coll->action( "inline preview" )->setShortcut( QKeySequence(Qt::Key_F11) );
00462     menu->addAction( coll->action( "preview" ));
00463 
00464     menu->setDelayed( false );
00465     connect( menu->menu(), SIGNAL( aboutToShow() ),
00466              d->ops, SLOT( updateSelectionDependentActions() ));
00467 
00468     d->iconSizeSlider = new QSlider(this);
00469     d->iconSizeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
00470     d->iconSizeSlider->setOrientation(Qt::Horizontal);
00471     d->iconSizeSlider->setMinimum(0);
00472     d->iconSizeSlider->setMaximum(100);
00473     d->iconSizeSlider->installEventFilter(this);
00474     connect(d->iconSizeSlider, SIGNAL(valueChanged(int)),
00475             d->ops, SLOT(setIconsZoom(int)));
00476     connect(d->iconSizeSlider, SIGNAL(valueChanged(int)),
00477             this, SLOT(_k_slotIconSizeChanged(int)));
00478     connect(d->iconSizeSlider, SIGNAL(sliderMoved(int)),
00479             this, SLOT(_k_slotIconSizeSliderMoved(int)));
00480     connect(d->ops, SIGNAL(currentIconSizeChanged(int)),
00481             d->iconSizeSlider, SLOT(setValue(int)));
00482 
00483     KAction *furtherAction = new KAction(KIcon("zoom-out"), i18n("Zoom out"), this);
00484     connect(furtherAction, SIGNAL(triggered()), SLOT(_k_zoomOutIconsSize()));
00485     KAction *closerAction = new KAction(KIcon("zoom-in"), i18n("Zoom in"), this);
00486     connect(closerAction, SIGNAL(triggered()), SLOT(_k_zoomInIconsSize()));
00487 
00488     QWidget *midSpacer = new QWidget(this);
00489     midSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00490 
00491     QAction *separator = new QAction(this);
00492     separator->setSeparator(true);
00493 
00494     QAction *separator2 = new QAction(this);
00495     separator2->setSeparator(true);
00496 
00497     d->toolbar->addAction(coll->action("back" ));
00498     d->toolbar->addAction(coll->action("forward"));
00499     d->toolbar->addAction(coll->action("up"));
00500     d->toolbar->addAction(coll->action("reload"));
00501     d->toolbar->addAction(separator);
00502     d->toolbar->addAction(coll->action("inline preview"));
00503     d->toolbar->addWidget(midSpacer);
00504     d->toolbar->addAction(furtherAction);
00505     d->toolbar->addWidget(d->iconSizeSlider);
00506     d->toolbar->addAction(closerAction);
00507     d->toolbar->addAction(separator2);
00508     d->toolbar->addAction(coll->action("mkdir"));
00509     d->toolbar->addAction(menu);
00510 
00511     d->toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
00512     d->toolbar->setMovable(false);
00513 
00514     KUrlCompletion *pathCompletionObj = new KUrlCompletion( KUrlCompletion::DirCompletion );
00515     pathCombo->setCompletionObject( pathCompletionObj );
00516     pathCombo->setAutoDeleteCompletionObject( true );
00517 
00518     connect( d->urlNavigator, SIGNAL( urlChanged( const KUrl&  )),
00519              this,  SLOT( _k_enterUrl( const KUrl& ) ));
00520     connect( d->urlNavigator, SIGNAL( returnPressed() ),
00521              d->ops,  SLOT( setFocus() ));
00522 
00523     QString whatsThisText;
00524 
00525     // the Location label/edit
00526     d->locationLabel = new QLabel(i18n("&Name:"), this);
00527     d->locationEdit = new KUrlComboBox(KUrlComboBox::Files, true, this);
00528     d->locationEdit->installEventFilter(this);
00529     // Properly let the dialog be resized (to smaller). Otherwise we could have
00530     // huge dialogs that can't be resized to smaller (it would be as big as the longest
00531     // item in this combo box). (ereslibre)
00532     d->locationEdit->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
00533     connect( d->locationEdit, SIGNAL( editTextChanged( const QString& ) ),
00534              SLOT( _k_slotLocationChanged( const QString& )) );
00535 
00536     d->updateLocationWhatsThis();
00537     d->locationLabel->setBuddy(d->locationEdit);
00538 
00539     KUrlCompletion *fileCompletionObj = new KUrlCompletion( KUrlCompletion::FileCompletion );
00540     d->locationEdit->setCompletionObject( fileCompletionObj );
00541     d->locationEdit->setAutoDeleteCompletionObject( true );
00542     connect( fileCompletionObj, SIGNAL( match( const QString& ) ),
00543              SLOT( _k_fileCompletion( const QString& )) );
00544 
00545     connect(d->locationEdit, SIGNAL( returnPressed( const QString&  )),
00546             this,  SLOT( _k_locationAccepted( const QString& ) ));
00547 
00548     // the Filter label/edit
00549     whatsThisText = i18n("<qt>This is the filter to apply to the file list. "
00550                          "File names that do not match the filter will not be shown.<p>"
00551                          "You may select from one of the preset filters in the "
00552                          "drop down menu, or you may enter a custom filter "
00553                          "directly into the text area.</p><p>"
00554                          "Wildcards such as * and ? are allowed.</p></qt>");
00555     d->filterLabel = new QLabel(i18n("&Filter:"), this);
00556     d->filterLabel->setWhatsThis(whatsThisText);
00557     d->filterWidget = new KFileFilterCombo(this);
00558     // Properly let the dialog be resized (to smaller). Otherwise we could have
00559     // huge dialogs that can't be resized to smaller (it would be as big as the longest
00560     // item in this combo box). (ereslibre)
00561     d->filterWidget->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
00562     d->filterWidget->setWhatsThis(whatsThisText);
00563     d->filterLabel->setBuddy(d->filterWidget);
00564     connect(d->filterWidget, SIGNAL(filterChanged()), SLOT(_k_slotFilterChanged()));
00565 
00566     // the Automatically Select Extension checkbox
00567     // (the text, visibility etc. is set in updateAutoSelectExtension(), which is called by readConfig())
00568     d->autoSelectExtCheckBox = new QCheckBox (this);
00569     d->autoSelectExtCheckBox->setStyleSheet(QString("QCheckBox { padding-top: %1px; }").arg(KDialog::spacingHint()));
00570     connect(d->autoSelectExtCheckBox, SIGNAL(clicked()), SLOT(_k_slotAutoSelectExtClicked()));
00571 
00572     d->initGUI(); // activate GM
00573 
00574     // read our configuration
00575     KSharedConfig::Ptr config = KGlobal::config();
00576     KConfigGroup viewConfigGroup(config, ConfigGroup);
00577     d->readConfig(viewConfigGroup);
00578 
00579     coll->action("inline preview")->setChecked(d->ops->isInlinePreviewShown());
00580     d->iconSizeSlider->setValue(d->ops->iconsZoom());
00581 
00582     KFilePreviewGenerator *pg = d->ops->previewGenerator();
00583     if (pg) {
00584         coll->action("inline preview")->setChecked(pg->isPreviewShown());
00585     }
00586 
00587     bool statRes = false;
00588     if ( filename.isEmpty() ) {
00589         KIO::StatJob *statJob = KIO::stat(startDir, KIO::HideProgressInfo);
00590         statRes = KIO::NetAccess::synchronousRun(statJob, 0);
00591         if (!statRes || !statJob->statResult().isDir()) {
00592             filename = startDir.fileName();
00593             startDir.setPath(startDir.directory());
00594         }
00595         kDebug(kfile_area) << "statJob found filename" << filename;
00596     }
00597 
00598     d->ops->setUrl(startDir, true);
00599     d->urlNavigator->setUrl(startDir);
00600     if (d->placesView) {
00601         d->placesView->setUrl(startDir);
00602     }
00603 
00604     // We have a file name either explicitly specified, or have checked that
00605     // we could stat it and it is not a directory.  Set it.
00606     if (!filename.isEmpty()) {
00607         kDebug(kfile_area) << "selecting filename" << filename;
00608         if (statRes) {
00609             d->setLocationText(filename);
00610         } else {
00611             d->locationEdit->lineEdit()->setText(filename);
00612         }
00613         d->locationEdit->lineEdit()->selectAll();
00614     }
00615 
00616     d->locationEdit->setFocus();
00617 }
00618 
00619 KFileWidget::~KFileWidget()
00620 {
00621     KSharedConfig::Ptr config = KGlobal::config();
00622     config->sync();
00623 
00624     delete d;
00625 }
00626 
00627 void KFileWidget::setLocationLabel(const QString& text)
00628 {
00629     d->locationLabel->setText(text);
00630 }
00631 
00632 void KFileWidget::setFilter(const QString& filter)
00633 {
00634     int pos = filter.indexOf('/');
00635 
00636     // Check for an un-escaped '/', if found
00637     // interpret as a MIME filter.
00638 
00639     if (pos > 0 && filter[pos - 1] != '\\') {
00640         QStringList filters = filter.split(' ', QString::SkipEmptyParts);
00641         setMimeFilter( filters );
00642         return;
00643     }
00644 
00645     // Strip the escape characters from
00646     // escaped '/' characters.
00647 
00648     QString copy (filter);
00649     for (pos = 0; (pos = copy.indexOf("\\/", pos)) != -1; ++pos)
00650         copy.remove(pos, 1);
00651 
00652     d->ops->clearFilter();
00653     d->filterWidget->setFilter(copy);
00654     d->ops->setNameFilter(d->filterWidget->currentFilter());
00655     d->ops->updateDir();
00656     d->hasDefaultFilter = false;
00657     d->filterWidget->setEditable( true );
00658 
00659     d->updateAutoSelectExtension ();
00660 }
00661 
00662 QString KFileWidget::currentFilter() const
00663 {
00664     return d->filterWidget->currentFilter();
00665 }
00666 
00667 void KFileWidget::setMimeFilter( const QStringList& mimeTypes,
00668                                  const QString& defaultType )
00669 {
00670     d->filterWidget->setMimeFilter( mimeTypes, defaultType );
00671 
00672     QStringList types = d->filterWidget->currentFilter().split(' ', QString::SkipEmptyParts); //QStringList::split(" ", d->filterWidget->currentFilter());
00673     types.append( QLatin1String( "inode/directory" ));
00674     d->ops->clearFilter();
00675     d->ops->setMimeFilter( types );
00676     d->hasDefaultFilter = !defaultType.isEmpty();
00677     d->filterWidget->setEditable( !d->hasDefaultFilter ||
00678                                d->operationMode != Saving );
00679 
00680     d->updateAutoSelectExtension ();
00681 }
00682 
00683 void KFileWidget::clearFilter()
00684 {
00685     d->filterWidget->setFilter( QString() );
00686     d->ops->clearFilter();
00687     d->hasDefaultFilter = false;
00688     d->filterWidget->setEditable( true );
00689 
00690     d->updateAutoSelectExtension ();
00691 }
00692 
00693 QString KFileWidget::currentMimeFilter() const
00694 {
00695     int i = d->filterWidget->currentIndex();
00696     if (d->filterWidget->showsAllTypes() && i == 0)
00697         return QString(); // The "all types" item has no mimetype
00698 
00699     return d->filterWidget->filters()[i];
00700 }
00701 
00702 KMimeType::Ptr KFileWidget::currentFilterMimeType()
00703 {
00704     return KMimeType::mimeType( currentMimeFilter() );
00705 }
00706 
00707 void KFileWidget::setPreviewWidget(KPreviewWidgetBase *w) {
00708     d->ops->setPreviewWidget(w);
00709     d->ops->clearHistory();
00710     d->hasView = true;
00711 }
00712 
00713 KUrl KFileWidgetPrivate::getCompleteUrl(const QString &_url) const
00714 {
00715 //     kDebug(kfile_area) << "got url " << _url;
00716 
00717     const QString url = KShell::tildeExpand(_url);
00718     KUrl u;
00719 
00720     if (QDir::isAbsolutePath(url)) {
00721         u = url;
00722     } else {
00723         KUrl relativeUrlTest(ops->url());
00724         relativeUrlTest.addPath(url);
00725         if (!ops->dirLister()->findByUrl(relativeUrlTest).isNull() ||
00726             !KProtocolInfo::isKnownProtocol(relativeUrlTest)) {
00727             u = relativeUrlTest;
00728         } else {
00729             u = url;
00730         }
00731     }
00732 
00733     return u;
00734 }
00735 
00736 // Called by KFileDialog
00737 void KFileWidget::slotOk()
00738 {
00739 //     kDebug(kfile_area) << "slotOk\n";
00740 
00741     const KFileItemList items = d->ops->selectedItems();
00742     const QString locationEditCurrentText(KShell::tildeExpand(d->locationEditCurrentText()));
00743 
00744     KUrl::List locationEditCurrentTextList(d->tokenize(locationEditCurrentText));
00745     KFile::Modes mode = d->ops->mode();
00746 
00747     // if there is nothing to do, just return from here
00748     if (!locationEditCurrentTextList.count()) {
00749         return;
00750     }
00751 
00752     // Make sure that one of the modes was provided
00753     if (!((mode & KFile::File) || (mode & KFile::Directory) || (mode & KFile::Files))) {
00754         mode |= KFile::File;
00755         kDebug(kfile_area) << "No mode() provided";
00756     }
00757 
00758     // if we are on file mode, and the list of provided files/folder is greater than one, inform
00759     // the user about it
00760     if (locationEditCurrentTextList.count() > 1) {
00761         if (mode & KFile::File) {
00762             KMessageBox::sorry(this,
00763                                i18n("You can only select one file"),
00764                                i18n("More than one file provided"));
00765             return;
00766         }
00767 
00788         if (!d->differentHierarchyLevelItemsEntered) {     // avoid infinite recursion. running this
00789             KUrl::List urlList;                            // one time is always enough.
00790             int start = 0;
00791             KUrl topMostUrl;
00792             KIO::StatJob *statJob = 0;
00793             bool res = false;
00794 
00795             // we need to check for a valid first url, so in theory we only iterate one time over
00796             // this loop. However it can happen that the user did
00797             // "home/foo/nonexistantfile" "boot/grub/menu.lst", so we look for a good first
00798             // candidate.
00799             while (!res && start < locationEditCurrentTextList.count()) {
00800                 topMostUrl = locationEditCurrentTextList.at(start);
00801                 statJob = KIO::stat(topMostUrl, KIO::HideProgressInfo);
00802                 res = KIO::NetAccess::synchronousRun(statJob, 0);
00803                 start++;
00804             }
00805 
00806             Q_ASSERT(statJob);
00807 
00808             // if this is not a dir, strip the filename. after this we have an existent and valid
00809             // dir (if we stated correctly the file, setting a null filename won't make any bad).
00810             if (!statJob->statResult().isDir()) {
00811                 topMostUrl.setFileName(QString());
00812             }
00813 
00814             // now the funny part. for the rest of filenames, go and look for the closest ancestor
00815             // of all them.
00816             for (int i = start; i < locationEditCurrentTextList.count(); ++i) {
00817                 KUrl currUrl = locationEditCurrentTextList.at(i);
00818                 KIO::StatJob *statJob = KIO::stat(currUrl, KIO::HideProgressInfo);
00819                 bool res = KIO::NetAccess::synchronousRun(statJob, 0);
00820                 if (res) {
00821                     // again, we don't care about filenames
00822                     if (!statJob->statResult().isDir()) {
00823                         currUrl.setFileName(QString());
00824                     }
00825 
00826                     // iterate while this item is contained on the top most url
00827                     while (!topMostUrl.isParentOf(currUrl)) {
00828                         topMostUrl = topMostUrl.upUrl();
00829                     }
00830                 }
00831             }
00832 
00833             // now recalculate all paths for them being relative in base of the top most url
00834             for (int i = 0; i < locationEditCurrentTextList.count(); ++i) {
00835                 locationEditCurrentTextList[i] = KUrl::relativeUrl(topMostUrl, locationEditCurrentTextList[i]);
00836             }
00837 
00838             d->ops->setUrl(topMostUrl, true);
00839             const bool signalsBlocked = d->locationEdit->lineEdit()->blockSignals(true);
00840             QStringList stringList;
00841             foreach (const KUrl &url, locationEditCurrentTextList) {
00842                 stringList << url.prettyUrl();
00843             }
00844             d->locationEdit->lineEdit()->setText(QString("\"%1\"").arg(stringList.join("\" \"")));
00845             d->locationEdit->lineEdit()->blockSignals(signalsBlocked);
00846 
00847             d->differentHierarchyLevelItemsEntered = true;
00848             slotOk();
00849             return;
00850         }
00854     } else if (locationEditCurrentTextList.count()) {
00855         // if we are on file or files mode, and we have an absolute url written by
00856         // the user, convert it to relative
00857         if (!locationEditCurrentText.isEmpty() && !(mode & KFile::Directory) &&
00858             (QDir::isAbsolutePath(locationEditCurrentText) ||
00859              containsProtocolSection(locationEditCurrentText))) {
00860 
00861             QString fileName;
00862             KUrl url(locationEditCurrentText);
00863             if (d->operationMode == Opening) {
00864                 KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo);
00865                 bool res = KIO::NetAccess::synchronousRun(statJob, 0);
00866                 if (res) {
00867                     if (!statJob->statResult().isDir()) {
00868                         url.adjustPath(KUrl::RemoveTrailingSlash);
00869                         fileName = url.fileName();
00870                         url.setFileName(QString());
00871                     } else {
00872                         url.adjustPath(KUrl::AddTrailingSlash);
00873                     }
00874                 }
00875             } else {
00876                 KUrl directory = url;
00877                 directory.setFileName(QString());
00878                 //Check if the folder exists
00879                 KIO::StatJob * statJob = KIO::stat(directory, KIO::HideProgressInfo);
00880                 bool res = KIO::NetAccess::synchronousRun(statJob, 0);
00881                 if (res) { 
00882                     if (statJob->statResult().isDir()) {
00883                         url.adjustPath(KUrl::RemoveTrailingSlash);
00884                         fileName = url.fileName();
00885                         url.setFileName(QString());
00886                     }
00887                 }
00888             }
00889             d->ops->setUrl(url, true);
00890             const bool signalsBlocked = d->locationEdit->lineEdit()->blockSignals(true);
00891             d->locationEdit->lineEdit()->setText(fileName);
00892             d->locationEdit->lineEdit()->blockSignals(signalsBlocked);
00893             slotOk();
00894             return;
00895         }
00896     }
00897 
00898     // restore it
00899     d->differentHierarchyLevelItemsEntered = false;
00900 
00901     // locationEditCurrentTextList contains absolute paths
00902     // this is the general loop for the File and Files mode. Obviously we know
00903     // that the File mode will iterate only one time here
00904     bool directoryMode = (mode & KFile::Directory);
00905     bool onlyDirectoryMode = directoryMode && !(mode & KFile::File) && !(mode & KFile::Files);
00906     KUrl::List::ConstIterator it = locationEditCurrentTextList.constBegin();
00907     bool filesInList = false;
00908     while (it != locationEditCurrentTextList.constEnd()) {
00909         KUrl url(*it);
00910 
00911         if (d->operationMode == Saving && !directoryMode) {
00912             d->appendExtension(url);
00913         }
00914 
00915         d->url = url;
00916         KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo);
00917         bool res = KIO::NetAccess::synchronousRun(statJob, 0);
00918 
00919         if (!KAuthorized::authorizeUrlAction("open", KUrl(), url)) {
00920             QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, d->url.prettyUrl());
00921             KMessageBox::error(this, msg);
00922             return;
00923         }
00924 
00925         // if we are on local mode, make sure we haven't got a remote base url
00926         if ((mode & KFile::LocalOnly) && !d->mostLocalUrl(d->url).isLocalFile()) {
00927             KMessageBox::sorry(this,
00928                             i18n("You can only select local files"),
00929                             i18n("Remote files not accepted"));
00930             return;
00931         }
00932         
00933         if ((d->operationMode == Saving) && d->confirmOverwrite && !d->toOverwrite(url)) {
00934             return;
00935         }
00936 
00937         // if we are given a folder when not on directory mode, let's get into it
00938         if (res && !directoryMode && statJob->statResult().isDir()) {
00939             // check if we were given more than one folder, in that case we don't know to which one
00940             // cd
00941             ++it;
00942             while (it != locationEditCurrentTextList.constEnd()) {
00943                 KUrl checkUrl(*it);
00944                 KIO::StatJob *checkStatJob = KIO::stat(checkUrl, KIO::HideProgressInfo);
00945                 bool res = KIO::NetAccess::synchronousRun(checkStatJob, 0);
00946                 if (res && checkStatJob->statResult().isDir()) {
00947                     KMessageBox::sorry(this, i18n("More than one folder has been selected and this dialog does not accept folders, so it is not possible to decide which one to enter. Please select only one folder to list it."), i18n("More than one folder provided"));
00948                     return;
00949                 } else if (res) {
00950                     filesInList = true;
00951                 }
00952                 ++it;
00953             }
00954             if (filesInList) {
00955                 KMessageBox::information(this, i18n("At least one folder and one file has been selected. Selected files will be ignored and the selected folder will be listed"), i18n("Files and folders selected"));
00956             }
00957             d->ops->setUrl(url, true);
00958             const bool signalsBlocked = d->locationEdit->lineEdit()->blockSignals(true);
00959             d->locationEdit->lineEdit()->setText(QString());
00960             d->locationEdit->lineEdit()->blockSignals(signalsBlocked);
00961             return;
00962         } else if (!(mode & KFile::ExistingOnly) || res) {
00963             // if we don't care about ExistingOnly flag, add the file even if
00964             // it doesn't exist. If we care about it, don't add it to the list
00965             if (!onlyDirectoryMode || (res && statJob->statResult().isDir())) {
00966                 d->urlList << url;
00967             }
00968             filesInList = true;
00969         } else {
00970             KMessageBox::sorry(this, i18n("The file %1 could not be found", url.url()), i18n("Cannot open file"));
00971             return; // do not emit accepted() if we had ExistingOnly flag and stat failed
00972         }
00973         ++it;
00974     }
00975 
00976     // if we have reached this point and we didn't return before, that is because
00977     // we want this dialog to be accepted
00978     emit accepted();
00979 }
00980 
00981 void KFileWidget::accept()
00982 {
00983     d->inAccept = true; // parseSelectedUrls() checks that
00984 
00985     *lastDirectory = d->ops->url();
00986     if (!d->fileClass.isEmpty())
00987        KRecentDirs::add(d->fileClass, d->ops->url().url());
00988 
00989     // clear the topmost item, we insert it as full path later on as item 1
00990     d->locationEdit->setItemText( 0, QString() );
00991 
00992     const KUrl::List list = selectedUrls();
00993     QList<KUrl>::const_iterator it = list.begin();
00994     int atmost = d->locationEdit->maxItems(); //don't add more items than necessary
00995     for ( ; it != list.end() && atmost > 0; ++it ) {
00996         const KUrl& url = *it;
00997         // we strip the last slash (-1) because KUrlComboBox does that as well
00998         // when operating in file-mode. If we wouldn't , dupe-finding wouldn't
00999         // work.
01000         QString file = url.isLocalFile() ? url.toLocalFile(KUrl::RemoveTrailingSlash) : url.prettyUrl(KUrl::RemoveTrailingSlash);
01001 
01002         // remove dupes
01003         for ( int i = 1; i < d->locationEdit->count(); i++ ) {
01004             if ( d->locationEdit->itemText( i ) == file ) {
01005                 d->locationEdit->removeItem( i-- );
01006                 break;
01007             }
01008         }
01009         //FIXME I don't think this works correctly when the KUrlComboBox has some default urls.
01010         //KUrlComboBox should provide a function to add an url and rotate the existing ones, keeping
01011         //track of maxItems, and we shouldn't be able to insert items as we please.
01012         d->locationEdit->insertItem( 1,file);
01013         atmost--;
01014     }
01015 
01016     KSharedConfig::Ptr config = KGlobal::config();
01017     KConfigGroup grp(config,ConfigGroup);
01018     d->writeConfig(grp);
01019     d->saveRecentFiles(grp);
01020 
01021     d->addToRecentDocuments();
01022 
01023     if (!(mode() & KFile::Files)) { // single selection
01024         emit fileSelected(d->url.url());
01025     }
01026 
01027     d->ops->close();
01028 }
01029 
01030 
01031 void KFileWidgetPrivate::_k_fileHighlighted(const KFileItem &i)
01032 {
01033     const bool modified = locationEdit->lineEdit()->isModified();
01034     locationEdit->lineEdit()->setModified( false );
01035 
01036     if ((!i.isNull() && i.isDir() ) ||
01037         (locationEdit->hasFocus() && !locationEdit->currentText().isEmpty())) // don't disturb
01038         return;
01039 
01040     if (!(ops->mode() & KFile::Files)) {
01041         if (i.isNull()) {
01042             if (!modified) {
01043                 setLocationText(KUrl());
01044             }
01045             return;
01046         }
01047 
01048         url = i.url();
01049 
01050         if (!locationEdit->hasFocus()) { // don't disturb while editing
01051             setLocationText( url );
01052         }
01053 
01054         emit q->fileHighlighted(url.url());
01055     } else {
01056         multiSelectionChanged();
01057         emit q->selectionChanged();
01058     }
01059 
01060     locationEdit->lineEdit()->selectAll();
01061 }
01062 
01063 void KFileWidgetPrivate::_k_fileSelected(const KFileItem &i)
01064 {
01065     if (!i.isNull() && i.isDir()) {
01066         return;
01067     }
01068 
01069     if (!(ops->mode() & KFile::Files)) {
01070         if (i.isNull()) {
01071             setLocationText(KUrl());
01072             return;
01073         }
01074         setLocationText(i.url());
01075     } else {
01076         multiSelectionChanged();
01077         emit q->selectionChanged();
01078     }
01079 
01080     // if we are saving, let another chance to the user before accepting the dialog (or trying to
01081     // accept). This way the user can choose a file and add a "_2" for instance to the filename
01082     if (operationMode != KFileWidget::Saving) {
01083         q->slotOk();
01084     }
01085 }
01086 
01087 
01088 // I know it's slow to always iterate thru the whole filelist
01089 // (d->ops->selectedItems()), but what can we do?
01090 void KFileWidgetPrivate::multiSelectionChanged()
01091 {
01092     if (locationEdit->hasFocus() && !locationEdit->currentText().isEmpty()) { // don't disturb
01093         return;
01094     }
01095 
01096     const KFileItemList list = ops->selectedItems();
01097 
01098     if (list.isEmpty()) {
01099         setLocationText(KUrl());
01100         return;
01101     }
01102 
01103     KUrl::List urlList;
01104     foreach (const KFileItem &fileItem, list) {
01105         urlList << fileItem.url();
01106     }
01107 
01108     setLocationText(urlList);
01109 }
01110 
01111 void KFileWidgetPrivate::setDummyHistoryEntry( const QString& text, const QPixmap& icon,
01112                                                bool usePreviousPixmapIfNull )
01113 {
01114     // setCurrentItem() will cause textChanged() being emitted,
01115     // so slotLocationChanged() will be called. Make sure we don't clear
01116     // the KDirOperator's view-selection in there
01117     QObject::disconnect( locationEdit, SIGNAL( editTextChanged( const QString& ) ),
01118                         q, SLOT( _k_slotLocationChanged( const QString& ) ) );
01119 
01120     bool dummyExists = dummyAdded;
01121 
01122     int cursorPosition = locationEdit->lineEdit()->cursorPosition();
01123 
01124     if ( dummyAdded ) {
01125         if ( !icon.isNull() ) {
01126             locationEdit->setItemIcon( 0, icon );
01127             locationEdit->setItemText( 0, text );
01128         } else {
01129             if ( !usePreviousPixmapIfNull ) {
01130                 locationEdit->setItemIcon( 0, QPixmap() );
01131             }
01132             locationEdit->setItemText( 0, text );
01133         }
01134     } else {
01135         if ( !text.isEmpty() ) {
01136             if ( !icon.isNull() ) {
01137                 locationEdit->insertItem( 0, icon, text );
01138             } else {
01139                 if ( !usePreviousPixmapIfNull ) {
01140                     locationEdit->insertItem( 0, QPixmap(), text );
01141                 } else {
01142                     locationEdit->insertItem( 0, text );
01143                 }
01144             }
01145             dummyAdded = true;
01146             dummyExists = true;
01147         }
01148     }
01149 
01150     if ( dummyExists && !text.isEmpty() ) {
01151         locationEdit->setCurrentIndex( 0 );
01152     }
01153 
01154     locationEdit->lineEdit()->setCursorPosition( cursorPosition );
01155 
01156     QObject::connect( locationEdit, SIGNAL( editTextChanged ( const QString& ) ),
01157                     q, SLOT( _k_slotLocationChanged( const QString& )) );
01158 }
01159 
01160 void KFileWidgetPrivate::removeDummyHistoryEntry()
01161 {
01162     if ( !dummyAdded ) {
01163         return;
01164     }
01165 
01166     // setCurrentItem() will cause textChanged() being emitted,
01167     // so slotLocationChanged() will be called. Make sure we don't clear
01168     // the KDirOperator's view-selection in there
01169     QObject::disconnect( locationEdit, SIGNAL( editTextChanged( const QString& ) ),
01170                         q, SLOT( _k_slotLocationChanged( const QString& ) ) );
01171 
01172     locationEdit->removeItem( 0 );
01173     locationEdit->setCurrentIndex( -1 );
01174     dummyAdded = false;
01175 
01176     QObject::connect( locationEdit, SIGNAL( editTextChanged ( const QString& ) ),
01177                     q, SLOT( _k_slotLocationChanged( const QString& )) );
01178 }
01179 
01180 void KFileWidgetPrivate::setLocationText(const KUrl& url)
01181 {
01182     if (!url.isEmpty()) {
01183         QPixmap mimeTypeIcon = KIconLoader::global()->loadMimeTypeIcon( KMimeType::iconNameForUrl( url ), KIconLoader::Small );
01184         if (url.hasPath()) {
01185             if (!url.directory().isEmpty())
01186             {
01187                 KUrl u(url);
01188                 u.setPath(u.directory());
01189                 q->setUrl(u, false);
01190             }
01191             else {
01192                 q->setUrl(url.path(), false);
01193             }
01194         }
01195         setDummyHistoryEntry(url.fileName() , mimeTypeIcon );
01196     } else {
01197         removeDummyHistoryEntry();
01198     }
01199 
01200     // don't change selection when user has clicked on an item
01201     if (operationMode == KFileWidget::Saving && !locationEdit->isVisible()) {
01202        setNonExtSelection();
01203     }
01204 }
01205 
01206 void KFileWidgetPrivate::setLocationText( const KUrl::List& urlList )
01207 {
01208     const KUrl currUrl = ops->url();
01209 
01210     if ( urlList.count() > 1 ) {
01211         QString urls;
01212         foreach (const KUrl &url, urlList) {
01213             urls += QString( "\"%1\"" ).arg( KUrl::relativeUrl(currUrl, url) ) + ' ';
01214         }
01215         urls = urls.left( urls.size() - 1 );
01216 
01217         setDummyHistoryEntry( urls, QPixmap(), false );
01218     } else if ( urlList.count() ) {
01219         const QPixmap mimeTypeIcon = KIconLoader::global()->loadMimeTypeIcon( KMimeType::iconNameForUrl( urlList[0] ),  KIconLoader::Small );
01220         setDummyHistoryEntry( KUrl::relativeUrl(currUrl, urlList[0]), mimeTypeIcon );
01221     } else {
01222         removeDummyHistoryEntry();
01223     }
01224 
01225     // don't change selection when user has clicked on an item
01226     if ( operationMode == KFileWidget::Saving && !locationEdit->isVisible())
01227        setNonExtSelection();
01228 }
01229 
01230 void KFileWidgetPrivate::updateLocationWhatsThis()
01231 {
01232     QString whatsThisText;
01233     if (operationMode == KFileWidget::Saving)
01234     {
01235         whatsThisText = "<qt>" + i18n("This is the name to save the file as.") +
01236                              i18n (autocompletionWhatsThisText);
01237     }
01238     else if (ops->mode() & KFile::Files)
01239     {
01240         whatsThisText = "<qt>" + i18n("This is the list of files to open. More than "
01241                              "one file can be specified by listing several "
01242                              "files, separated by spaces.") +
01243                               i18n (autocompletionWhatsThisText);
01244     }
01245     else
01246     {
01247         whatsThisText = "<qt>" + i18n("This is the name of the file to open.") +
01248                              i18n (autocompletionWhatsThisText);
01249     }
01250 
01251     locationLabel->setWhatsThis(whatsThisText);
01252     locationEdit->setWhatsThis(whatsThisText);
01253 }
01254 
01255 void KFileWidgetPrivate::initSpeedbar()
01256 {
01257     if (placesDock) {
01258         return;
01259     }
01260 
01261     placesDock = new QDockWidget(i18n("Places"), q);
01262     placesDock->setFeatures(QDockWidget::DockWidgetClosable);
01263 
01264     placesView = new KFilePlacesView(placesDock);
01265     placesView->setModel(model);
01266     placesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
01267 
01268     placesView->setObjectName(QLatin1String("url bar"));
01269     QObject::connect(placesView, SIGNAL(urlChanged(KUrl)),
01270                      q, SLOT(_k_enterUrl(KUrl)));
01271 
01272     // need to set the current url of the urlbar manually (not via urlEntered()
01273     // here, because the initial url of KDirOperator might be the same as the
01274     // one that will be set later (and then urlEntered() won't be emitted).
01275     // TODO: KDE5 ### REMOVE THIS when KDirOperator's initial URL (in the c'tor) is gone.
01276     placesView->setUrl(url);
01277 
01278     placesDock->setWidget(placesView);
01279     placesViewSplitter->insertWidget(0, placesDock);
01280 
01281     // initialize the size of the splitter
01282     KConfigGroup configGroup(KGlobal::config(), ConfigGroup);
01283     placesViewWidth = configGroup.readEntry(SpeedbarWidth, placesView->sizeHint().width());
01284 
01285     QList<int> sizes = placesViewSplitter->sizes();
01286     if (placesViewWidth > 0) {
01287         sizes[0] = placesViewWidth + 1;
01288         sizes[1] = q->width() - placesViewWidth -1;
01289         placesViewSplitter->setSizes(sizes);
01290     }
01291 
01292     QObject::connect(placesDock, SIGNAL(visibilityChanged(bool)),
01293                      q, SLOT(_k_toggleSpeedbar(bool)));
01294 }
01295 
01296 void KFileWidgetPrivate::initGUI()
01297 {
01298     delete boxLayout; // deletes all sub layouts
01299 
01300     boxLayout = new QVBoxLayout( q);
01301     boxLayout->setMargin(0); // no additional margin to the already existing
01302 
01303     placesViewSplitter = new QSplitter(q);
01304     placesViewSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
01305     placesViewSplitter->setChildrenCollapsible(false);
01306     boxLayout->addWidget(placesViewSplitter);
01307 
01308     QObject::connect(placesViewSplitter, SIGNAL(splitterMoved(int,int)),
01309                      q, SLOT(_k_placesViewSplitterMoved(int,int)));
01310     placesViewSplitter->insertWidget(0, opsWidget);
01311 
01312     vbox = new QVBoxLayout();
01313     vbox->setMargin(0);
01314     boxLayout->addLayout(vbox);
01315 
01316     lafBox = new QGridLayout();
01317 
01318     lafBox->addWidget(locationLabel, 0, 0, Qt::AlignVCenter | Qt::AlignRight);
01319     lafBox->addWidget(locationEdit, 0, 1, Qt::AlignVCenter);
01320     lafBox->addWidget(okButton, 0, 2, Qt::AlignVCenter);
01321 
01322     lafBox->addWidget(filterLabel, 1, 0, Qt::AlignVCenter | Qt::AlignRight);
01323     lafBox->addWidget(filterWidget, 1, 1, Qt::AlignVCenter);
01324     lafBox->addWidget(cancelButton, 1, 2, Qt::AlignVCenter);
01325 
01326     lafBox->setColumnStretch(1, 4);
01327 
01328     vbox->addLayout(lafBox);
01329 
01330     // add the Automatically Select Extension checkbox
01331     vbox->addWidget(autoSelectExtCheckBox);
01332 
01333     q->setTabOrder(ops, autoSelectExtCheckBox);
01334     q->setTabOrder(autoSelectExtCheckBox, locationEdit);
01335     q->setTabOrder(locationEdit, filterWidget);
01336     q->setTabOrder(filterWidget, okButton);
01337     q->setTabOrder(okButton, cancelButton);
01338     q->setTabOrder(cancelButton, urlNavigator);
01339     q->setTabOrder(urlNavigator, ops);
01340     q->setTabOrder(cancelButton, urlNavigator);
01341     q->setTabOrder(urlNavigator, ops);
01342 
01343 }
01344 
01345 void KFileWidgetPrivate::_k_slotFilterChanged()
01346 {
01347 //     kDebug(kfile_area);
01348 
01349     QString filter = filterWidget->currentFilter();
01350     ops->clearFilter();
01351 
01352     if ( filter.indexOf( '/' ) > -1 ) {
01353         QStringList types = filter.split(' ', QString::SkipEmptyParts);
01354         types.prepend("inode/directory");
01355         ops->setMimeFilter( types );
01356     }
01357     else
01358         ops->setNameFilter( filter );
01359 
01360     ops->updateDir();
01361 
01362     updateAutoSelectExtension();
01363 
01364     emit q->filterChanged(filter);
01365 }
01366 
01367 
01368 void KFileWidget::setUrl(const KUrl& url, bool clearforward)
01369 {
01370 //     kDebug(kfile_area);
01371 
01372     d->ops->setUrl(url, clearforward);
01373 }
01374 
01375 // Protected
01376 void KFileWidgetPrivate::_k_urlEntered(const KUrl& url)
01377 {
01378 //     kDebug(kfile_area);
01379 
01380     QString filename = locationEditCurrentText();
01381 
01382     KUrlComboBox* pathCombo = urlNavigator->editor();
01383     if (pathCombo->count() != 0) { // little hack
01384         pathCombo->setUrl(url);
01385     }
01386 
01387     bool blocked = locationEdit->blockSignals(true);
01388     if (keepLocation) {
01389         locationEdit->changeUrl(0, KIcon(KMimeType::iconNameForUrl(filename)), filename);
01390         locationEdit->lineEdit()->setModified(true);
01391     }
01392 
01393     locationEdit->blockSignals( blocked );
01394 
01395     urlNavigator->setUrl(url);
01396 
01397     // is trigged in ctor before completion object is set
01398     KUrlCompletion *completion = dynamic_cast<KUrlCompletion*>(locationEdit->completionObject());
01399     if (completion) {
01400         completion->setDir( url.path() );
01401     }
01402 
01403     if (placesView) {
01404         placesView->setUrl( url );
01405     }
01406 }
01407 
01408 void KFileWidgetPrivate::_k_locationAccepted(const QString &url)
01409 {
01410     Q_UNUSED(url);
01411 //     kDebug(kfile_area);
01412     q->slotOk();
01413 }
01414 
01415 void KFileWidgetPrivate::_k_enterUrl( const KUrl& url )
01416 {
01417 //     kDebug(kfile_area);
01418 
01419     KUrl fixedUrl( url );
01420     // append '/' if needed: url combo does not add it
01421     // tokenize() expects it because uses KUrl::setFileName()
01422     fixedUrl.adjustPath( KUrl::AddTrailingSlash );
01423     q->setUrl( fixedUrl );
01424     if (!locationEdit->hasFocus())
01425         ops->setFocus();
01426 }
01427 
01428 void KFileWidgetPrivate::_k_enterUrl( const QString& url )
01429 {
01430 //     kDebug(kfile_area);
01431 
01432     _k_enterUrl( KUrl( KUrlCompletion::replacedPath( url, true, true )) );
01433 }
01434 
01435 bool KFileWidgetPrivate::toOverwrite(const KUrl &url)
01436 {
01437 //     kDebug(kfile_area);
01438 
01439     KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo);
01440     bool res = KIO::NetAccess::synchronousRun(statJob, 0);
01441 
01442     if (res) {
01443         int ret = KMessageBox::warningContinueCancel( q,
01444             i18n( "The file \"%1\" already exists. Do you wish to overwrite it?" ,
01445             url.fileName() ), i18n( "Overwrite File?" ), KStandardGuiItem::overwrite(),
01446             KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous);
01447 
01448         if (ret != KMessageBox::Continue) {
01449             return false;
01450         }
01451         return true;
01452     }
01453 
01454     return true;
01455 }
01456 
01457 void KFileWidget::setSelection(const QString& url)
01458 {
01459 //     kDebug(kfile_area) << "setSelection " << url;
01460 
01461     if (url.isEmpty()) {
01462         return;
01463     }
01464 
01465     KUrl u = d->getCompleteUrl(url);
01466     if (!u.isValid()) { // if it still is
01467         kWarning() << url << " is not a correct argument for setSelection!";
01468         return;
01469     }
01470 
01471     // Honor protocols that do not support directory listing
01472     if (!u.isRelative() && !KProtocolManager::supportsListing(u))
01473         return;
01474 
01475     d->setLocationText(url);
01476 }
01477 
01478 void KFileWidgetPrivate::_k_slotLoadingFinished()
01479 {
01480     if (locationEdit->currentText().isEmpty()) {
01481         return;
01482     }
01483 
01484     ops->blockSignals(true);
01485     KUrl url = ops->url();
01486     url.adjustPath(KUrl::AddTrailingSlash);
01487     url.setFileName(locationEdit->currentText());
01488     ops->setCurrentItem(url.url());
01489     ops->blockSignals(false);
01490 }
01491 
01492 void KFileWidgetPrivate::_k_fileCompletion( const QString& match )
01493 {
01494 //     kDebug(kfile_area);
01495 
01496     if (match.isEmpty() || locationEdit->currentText().contains('"')) {
01497         return;
01498     }
01499 
01500     setDummyHistoryEntry(locationEdit->currentText(), KIconLoader::global()->loadMimeTypeIcon( KMimeType::iconNameForUrl( match ), KIconLoader::Small), !locationEdit->currentText().isEmpty());
01501 }
01502 
01503 void KFileWidgetPrivate::_k_slotLocationChanged( const QString& text )
01504 {
01505 //     kDebug(kfile_area);
01506 
01507     locationEdit->lineEdit()->setModified(true);
01508 
01509     if (text.isEmpty() && ops->view()) {
01510         ops->view()->clearSelection();
01511     }
01512 
01513     if (text.isEmpty()) {
01514         removeDummyHistoryEntry();
01515     } else {
01516         setDummyHistoryEntry( text );
01517     }
01518 
01519     if (!locationEdit->lineEdit()->text().isEmpty()) {
01520         const KUrl::List urlList(tokenize(text));
01521         QStringList stringList;
01522         foreach (const KUrl &url, urlList) {
01523             stringList << url.url();
01524         }
01525         ops->setCurrentItems(stringList);
01526     }
01527 
01528     updateFilter();
01529 }
01530 
01531 KUrl KFileWidget::selectedUrl() const
01532 {
01533 //     kDebug(kfile_area);
01534 
01535     if ( d->inAccept )
01536         return d->url;
01537     else
01538         return KUrl();
01539 }
01540 
01541 KUrl::List KFileWidget::selectedUrls() const
01542 {
01543 //     kDebug(kfile_area);
01544 
01545     KUrl::List list;
01546     if ( d->inAccept ) {
01547         if (d->ops->mode() & KFile::Files)
01548             list = d->parseSelectedUrls();
01549         else
01550             list.append( d->url );
01551     }
01552     return list;
01553 }
01554 
01555 
01556 KUrl::List& KFileWidgetPrivate::parseSelectedUrls()
01557 {
01558 //     kDebug(kfile_area);
01559 
01560     if ( filenames.isEmpty() ) {
01561         return urlList;
01562     }
01563 
01564     urlList.clear();
01565     if ( filenames.contains( '/' )) { // assume _one_ absolute filename
01566         KUrl u;
01567         if ( containsProtocolSection( filenames ) )
01568             u = filenames;
01569         else
01570             u.setPath( filenames );
01571 
01572         if ( u.isValid() )
01573             urlList.append( u );
01574         else
01575             KMessageBox::error( q,
01576                                 i18n("The chosen filenames do not\n"
01577                                      "appear to be valid."),
01578                                 i18n("Invalid Filenames") );
01579     }
01580 
01581     else
01582         urlList = tokenize( filenames );
01583 
01584     filenames.clear(); // indicate that we parsed that one
01585 
01586     return urlList;
01587 }
01588 
01589 
01590 // FIXME: current implementation drawback: a filename can't contain quotes
01591 KUrl::List KFileWidgetPrivate::tokenize( const QString& line ) const
01592 {
01593 //     kDebug(kfile_area);
01594 
01595     KUrl::List urls;
01596     KUrl u( ops->url() );
01597     u.adjustPath(KUrl::AddTrailingSlash);
01598     QString name;
01599 
01600     const int count = line.count( QLatin1Char( '"' ) );
01601     if ( count == 0 ) { // no " " -> assume one single file
01602         if (!QDir::isAbsolutePath(line)) {
01603             u.setFileName( line );
01604             if ( u.isValid() )
01605                 urls.append( u );
01606         } else {
01607             urls << KUrl(line);
01608         }
01609 
01610         return urls;
01611     }
01612 
01613     int start = 0;
01614     int index1 = -1, index2 = -1;
01615     while ( true ) {
01616         index1 = line.indexOf( '"', start );
01617         index2 = line.indexOf( '"', index1 + 1 );
01618 
01619         if ( index1 < 0 || index2 < 0 )
01620             break;
01621 
01622         // get everything between the " "
01623         name = line.mid( index1 + 1, index2 - index1 - 1 );
01624 
01625         // since we use setFileName we need to do this under a temporary url
01626         KUrl _u( u );
01627         KUrl currUrl( name );
01628 
01629         if ( !QDir::isAbsolutePath(currUrl.url()) ) {
01630             _u.setFileName( name );
01631         } else {
01632             // we allow to insert various absolute paths like:
01633             // "/home/foo/bar.txt" "/boot/grub/menu.lst"
01634             _u = currUrl;
01635         }
01636 
01637         if ( _u.isValid() ) {
01638             urls.append( _u );
01639         }
01640 
01641         start = index2 + 1;
01642     }
01643 
01644     return urls;
01645 }
01646 
01647 
01648 QString KFileWidget::selectedFile() const
01649 {
01650 //     kDebug(kfile_area);
01651 
01652     if ( d->inAccept ) {
01653         const KUrl url = d->mostLocalUrl(d->url);
01654         if (url.isLocalFile())
01655             return url.toLocalFile();
01656         else {
01657             KMessageBox::sorry( const_cast<KFileWidget*>(this),
01658                                 i18n("You can only select local files."),
01659                                 i18n("Remote Files Not Accepted") );
01660         }
01661     }
01662     return QString();
01663 }
01664 
01665 QStringList KFileWidget::selectedFiles() const
01666 {
01667 //     kDebug(kfile_area);
01668 
01669     QStringList list;
01670 
01671     if (d->inAccept) {
01672         if (d->ops->mode() & KFile::Files) {
01673             const KUrl::List urls = d->parseSelectedUrls();
01674             QList<KUrl>::const_iterator it = urls.begin();
01675             while (it != urls.end()) {
01676                 KUrl url = d->mostLocalUrl(*it);
01677                 if (url.isLocalFile())
01678                     list.append(url.toLocalFile());
01679                 ++it;
01680             }
01681         }
01682 
01683         else { // single-selection mode
01684             if ( d->url.isLocalFile() )
01685                 list.append( d->url.toLocalFile() );
01686         }
01687     }
01688 
01689     return list;
01690 }
01691 
01692 KUrl KFileWidget::baseUrl() const
01693 {
01694     return d->ops->url();
01695 }
01696 
01697 void KFileWidget::resizeEvent(QResizeEvent* event)
01698 {
01699     QWidget::resizeEvent(event);
01700 
01701     if (d->placesDock) {
01702         // we don't want our places dock actually changing size when we resize
01703         // and qt doesn't make it easy to enforce such a thing with QSplitter
01704         QList<int> sizes = d->placesViewSplitter->sizes();
01705         sizes[0] = d->placesViewWidth + 1; // without this pixel, our places view is reduced 1 pixel each time is shown.
01706         sizes[1] = width() - d->placesViewWidth - 1;
01707         d->placesViewSplitter->setSizes( sizes );
01708     }
01709 }
01710 
01711 void KFileWidget::showEvent(QShowEvent* event)
01712 {
01713     if ( !d->hasView ) { // delayed view-creation
01714         Q_ASSERT( d );
01715         Q_ASSERT( d->ops );
01716         d->ops->setView( KFile::Default );
01717         d->ops->view()->setSizePolicy( QSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum ) );
01718         d->hasView = true;
01719 
01720         connect(d->ops->view(), SIGNAL(doubleClicked(QModelIndex)), this, SLOT(_k_slotViewDoubleClicked(QModelIndex)));
01721     }
01722     d->ops->clearHistory();
01723 
01724     QWidget::showEvent(event);
01725 }
01726 
01727 bool KFileWidget::eventFilter(QObject* watched, QEvent* event)
01728 {
01729     const bool res = QWidget::eventFilter(watched, event);
01730 
01731     QKeyEvent *keyEvent = dynamic_cast<QKeyEvent*>(event);
01732     if (watched == d->iconSizeSlider && keyEvent) {
01733         if (keyEvent->key() == Qt::Key_Left || keyEvent->key() == Qt::Key_Up ||
01734             keyEvent->key() == Qt::Key_Right || keyEvent->key() == Qt::Key_Down) {
01735             d->_k_slotIconSizeSliderMoved(d->iconSizeSlider->value());
01736         }
01737     } else if (watched == d->locationEdit && event->type() == QEvent::KeyPress) {
01738         if (keyEvent->modifiers() & Qt::AltModifier) {
01739             switch (keyEvent->key()) {
01740                 case Qt::Key_Up:
01741                     d->ops->actionCollection()->action("up")->trigger();
01742                     break;
01743                 case Qt::Key_Left:
01744                     d->ops->actionCollection()->action("back")->trigger();
01745                     break;
01746                 case Qt::Key_Right:
01747                     d->ops->actionCollection()->action("forward")->trigger();
01748                     break;
01749                 default:
01750                     break;
01751             }
01752         }
01753     }
01754 
01755     return res;
01756 }
01757 
01758 void KFileWidget::setMode( KFile::Modes m )
01759 {
01760 //     kDebug(kfile_area);
01761 
01762     d->ops->setMode(m);
01763     if ( d->ops->dirOnlyMode() ) {
01764         d->filterWidget->setDefaultFilter( i18n("*|All Folders") );
01765     }
01766     else {
01767         d->filterWidget->setDefaultFilter( i18n("*|All Files") );
01768     }
01769 
01770     d->updateAutoSelectExtension();
01771 }
01772 
01773 KFile::Modes KFileWidget::mode() const
01774 {
01775     return d->ops->mode();
01776 }
01777 
01778 
01779 void KFileWidgetPrivate::readConfig(KConfigGroup &configGroup)
01780 {
01781 //     kDebug(kfile_area);
01782 
01783     readRecentFiles(configGroup);
01784 
01785     ops->setViewConfig(configGroup);
01786     ops->readConfig(configGroup);
01787 
01788     KUrlComboBox *combo = urlNavigator->editor();
01789     combo->setUrls( configGroup.readPathEntry( RecentURLs, QStringList() ), KUrlComboBox::RemoveTop );
01790     combo->setMaxItems( configGroup.readEntry( RecentURLsNumber,
01791                                        DefaultRecentURLsNumber ) );
01792     combo->setUrl( ops->url() );
01793     autoDirectoryFollowing = configGroup.readEntry(AutoDirectoryFollowing,
01794                                                    DefaultDirectoryFollowing);
01795 
01796     KGlobalSettings::Completion cm = (KGlobalSettings::Completion)
01797                                       configGroup.readEntry( PathComboCompletionMode,
01798                                       static_cast<int>( KGlobalSettings::completionMode() ) );
01799     if ( cm != KGlobalSettings::completionMode() )
01800         combo->setCompletionMode( cm );
01801 
01802     cm = (KGlobalSettings::Completion)
01803          configGroup.readEntry( LocationComboCompletionMode,
01804                         static_cast<int>( KGlobalSettings::completionMode() ) );
01805     if ( cm != KGlobalSettings::completionMode() )
01806         locationEdit->setCompletionMode( cm );
01807 
01808     // since we delayed this moment, initialize the directory of the completion object to
01809     // our current directory (that was very probably set on the constructor)
01810     KUrlCompletion *completion = dynamic_cast<KUrlCompletion*>(locationEdit->completionObject());
01811     if (completion) {
01812         completion->setDir(ops->url().url());
01813     }
01814 
01815     // show or don't show the speedbar
01816     _k_toggleSpeedbar( configGroup.readEntry( ShowSpeedbar, true ) );
01817 
01818     // show or don't show the bookmarks
01819     _k_toggleBookmarks( configGroup.readEntry(ShowBookmarks, false) );
01820 
01821     // does the user want Automatically Select Extension?
01822     autoSelectExtChecked = configGroup.readEntry (AutoSelectExtChecked, DefaultAutoSelectExtChecked);
01823     updateAutoSelectExtension();
01824 
01825     // should the URL navigator use the breadcrumb navigation?
01826     urlNavigator->setUrlEditable( !configGroup.readEntry(BreadcrumbNavigation, true) );
01827 
01828     // should the URL navigator show the full path?
01829     urlNavigator->setShowFullPath( configGroup.readEntry(ShowFullPath, false) );
01830 
01831     int w1 = q->minimumSize().width();
01832     int w2 = toolbar->sizeHint().width();
01833     if (w1 < w2)
01834         q->setMinimumWidth(w2);
01835 }
01836 
01837 void KFileWidgetPrivate::writeConfig(KConfigGroup &configGroup)
01838 {
01839 //     kDebug(kfile_area);
01840 
01841     // these settings are global settings; ALL instances of the file dialog
01842     // should reflect them
01843     configGroup.config()->setForceGlobal(true);
01844 
01845     KUrlComboBox *pathCombo = urlNavigator->editor();
01846     configGroup.writePathEntry( RecentURLs, pathCombo->urls() );
01847     //saveDialogSize( configGroup, KConfigGroup::Persistent | KConfigGroup::Global );
01848     configGroup.writeEntry( PathComboCompletionMode, static_cast<int>(pathCombo->completionMode()) );
01849     configGroup.writeEntry( LocationComboCompletionMode, static_cast<int>(locationEdit->completionMode()) );
01850 
01851     const bool showSpeedbar = placesDock && !placesDock->isHidden();
01852     configGroup.writeEntry( ShowSpeedbar, showSpeedbar );
01853     if (showSpeedbar) {
01854         const QList<int> sizes = placesViewSplitter->sizes();
01855         Q_ASSERT( sizes.count() > 0 );
01856         configGroup.writeEntry( SpeedbarWidth, sizes[0] );
01857     }
01858 
01859     configGroup.writeEntry( ShowBookmarks, bookmarkHandler != 0 );
01860     configGroup.writeEntry( AutoSelectExtChecked, autoSelectExtChecked );
01861     configGroup.writeEntry( BreadcrumbNavigation, !urlNavigator->isUrlEditable() );
01862     configGroup.writeEntry( ShowFullPath, urlNavigator->showFullPath() );
01863 
01864     ops->writeConfig(configGroup);
01865     configGroup.config()->setForceGlobal(false);
01866 }
01867 
01868 
01869 void KFileWidgetPrivate::readRecentFiles(KConfigGroup &cg)
01870 {
01871 //     kDebug(kfile_area);
01872 
01873     QObject::disconnect(locationEdit, SIGNAL(editTextChanged(QString)),
01874                         q, SLOT(_k_slotLocationChanged(QString)));
01875 
01876     locationEdit->setMaxItems(cg.readEntry(RecentFilesNumber, DefaultRecentURLsNumber));
01877     locationEdit->setUrls(cg.readPathEntry(RecentFiles, QStringList()),
01878                           KUrlComboBox::RemoveBottom);
01879     locationEdit->setCurrentIndex(-1);
01880 
01881     QObject::connect(locationEdit, SIGNAL(editTextChanged(QString)),
01882                      q, SLOT(_k_slotLocationChanged(QString)));
01883 }
01884 
01885 void KFileWidgetPrivate::saveRecentFiles(KConfigGroup &cg)
01886 {
01887 //     kDebug(kfile_area);
01888     cg.writePathEntry(RecentFiles, locationEdit->urls());
01889 }
01890 
01891 KPushButton * KFileWidget::okButton() const
01892 {
01893     return d->okButton;
01894 }
01895 
01896 KPushButton * KFileWidget::cancelButton() const
01897 {
01898     return d->cancelButton;
01899 }
01900 
01901 // Called by KFileDialog
01902 void KFileWidget::slotCancel()
01903 {
01904 //     kDebug(kfile_area);
01905 
01906     d->ops->close();
01907 
01908     KConfigGroup grp(KGlobal::config(), ConfigGroup);
01909     d->writeConfig(grp);
01910 }
01911 
01912 void KFileWidget::setKeepLocation( bool keep )
01913 {
01914     d->keepLocation = keep;
01915 }
01916 
01917 bool KFileWidget::keepsLocation() const
01918 {
01919     return d->keepLocation;
01920 }
01921 
01922 void KFileWidget::setOperationMode( OperationMode mode )
01923 {
01924 //     kDebug(kfile_area);
01925 
01926     d->operationMode = mode;
01927     d->keepLocation = (mode == Saving);
01928     d->filterWidget->setEditable( !d->hasDefaultFilter || mode != Saving );
01929     if ( mode == Opening ) {
01930         // don't use KStandardGuiItem::open() here which has trailing ellipsis!
01931         d->okButton->setGuiItem( KGuiItem( i18n( "&Open" ), "document-open") );
01932         // hide the new folder actions...usability team says they shouldn't be in open file dialog
01933         actionCollection()->removeAction( actionCollection()->action("mkdir" ) );
01934     } else if ( mode == Saving ) {
01935         d->okButton->setGuiItem( KStandardGuiItem::save() );
01936         d->setNonExtSelection();
01937     } else {
01938         d->okButton->setGuiItem( KStandardGuiItem::ok() );
01939     }
01940     d->updateLocationWhatsThis();
01941     d->updateAutoSelectExtension();
01942 
01943     if (d->ops) {
01944         d->ops->setIsSaving(mode == Saving);
01945     }
01946 }
01947 
01948 KFileWidget::OperationMode KFileWidget::operationMode() const
01949 {
01950     return d->operationMode;
01951 }
01952 
01953 void KFileWidgetPrivate::_k_slotAutoSelectExtClicked()
01954 {
01955 //     kDebug (kfile_area) << "slotAutoSelectExtClicked(): "
01956 //                          << autoSelectExtCheckBox->isChecked() << endl;
01957 
01958     // whether the _user_ wants it on/off
01959     autoSelectExtChecked = autoSelectExtCheckBox->isChecked();
01960 
01961     // update the current filename's extension
01962     updateLocationEditExtension (extension /* extension hasn't changed */);
01963 }
01964 
01965 void KFileWidgetPrivate::_k_placesViewSplitterMoved(int pos, int index)
01966 {
01967 //     kDebug(kfile_area);
01968 
01969     // we need to record the size of the splitter when the splitter changes size
01970     // so we can keep the places box the right size!
01971     if (placesDock && index == 1) {
01972         placesViewWidth = pos;
01973 //         kDebug() << "setting lafBox minwidth to" << placesViewWidth;
01974         lafBox->setColumnMinimumWidth(0, placesViewWidth);
01975     }
01976 }
01977 
01978 void KFileWidgetPrivate::_k_activateUrlNavigator()
01979 {
01980 //     kDebug(kfile_area);
01981 
01982     urlNavigator->setUrlEditable(true);
01983     urlNavigator->setFocus();
01984     urlNavigator->editor()->lineEdit()->selectAll();
01985 }
01986 
01987 void KFileWidgetPrivate::_k_zoomOutIconsSize()
01988 {
01989     const int currValue = ops->iconsZoom();
01990     const int futValue = qMax(0, currValue - 10);
01991     iconSizeSlider->setValue(futValue);
01992     _k_slotIconSizeSliderMoved(futValue);
01993 }
01994 
01995 void KFileWidgetPrivate::_k_zoomInIconsSize()
01996 {
01997     const int currValue = ops->iconsZoom();
01998     const int futValue = qMin(100, currValue + 10);
01999     iconSizeSlider->setValue(futValue);
02000     _k_slotIconSizeSliderMoved(futValue);
02001 }
02002 
02003 void KFileWidgetPrivate::_k_slotIconSizeChanged(int _value)
02004 {
02005     int maxSize = KIconLoader::SizeEnormous - KIconLoader::SizeSmall;
02006     int value = (maxSize * _value / 100) + KIconLoader::SizeSmall;
02007     switch (value) {
02008         case KIconLoader::SizeSmall:
02009         case KIconLoader::SizeSmallMedium:
02010         case KIconLoader::SizeMedium:
02011         case KIconLoader::SizeLarge:
02012         case KIconLoader::SizeHuge:
02013         case KIconLoader::SizeEnormous:
02014             iconSizeSlider->setToolTip(i18n("Icon size: %1 pixels (standard size)", value));
02015             break;
02016         default:
02017             iconSizeSlider->setToolTip(i18n("Icon size: %1 pixels", value));
02018             break;
02019     }
02020 }
02021 
02022 void KFileWidgetPrivate::_k_slotIconSizeSliderMoved(int _value)
02023 {
02024     // Force this to be called in case this slot is called first on the
02025     // slider move.
02026     _k_slotIconSizeChanged(_value);
02027 
02028     QPoint global(iconSizeSlider->rect().topLeft());
02029     global.ry() += iconSizeSlider->height() / 2;
02030     QHelpEvent toolTipEvent(QEvent::ToolTip, QPoint(0, 0), iconSizeSlider->mapToGlobal(global));
02031     QApplication::sendEvent(iconSizeSlider, &toolTipEvent);
02032 }
02033 
02034 void KFileWidgetPrivate::_k_slotViewDoubleClicked(const QModelIndex &index)
02035 {
02036     if (!index.isValid()) {
02037         return;
02038     }
02039     q->slotOk();
02040 }
02041 
02042 static QString getExtensionFromPatternList(const QStringList &patternList)
02043 {
02044 //     kDebug(kfile_area);
02045 
02046     QString ret;
02047 //     kDebug (kfile_area) << "\tgetExtension " << patternList;
02048 
02049     QStringList::ConstIterator patternListEnd = patternList.end();
02050     for (QStringList::ConstIterator it = patternList.begin();
02051          it != patternListEnd;
02052          ++it)
02053     {
02054 //         kDebug (kfile_area) << "\t\ttry: \'" << (*it) << "\'";
02055 
02056         // is this pattern like "*.BMP" rather than useless things like:
02057         //
02058         // README
02059         // *.
02060         // *.*
02061         // *.JP*G
02062         // *.JP?
02063         if ((*it).startsWith ("*.") &&
02064             (*it).length() > 2 &&
02065             (*it).indexOf('*', 2) < 0 && (*it).indexOf ('?', 2) < 0)
02066         {
02067             ret = (*it).mid (1);
02068             break;
02069         }
02070     }
02071 
02072     return ret;
02073 }
02074 
02075 static QString stripUndisplayable (const QString &string)
02076 {
02077     QString ret = string;
02078 
02079     ret.remove (':');
02080     ret = KGlobal::locale()->removeAcceleratorMarker (ret);
02081 
02082     return ret;
02083 }
02084 
02085 
02086 //QString KFileWidget::currentFilterExtension()
02087 //{
02088 //    return d->extension;
02089 //}
02090 
02091 void KFileWidgetPrivate::updateAutoSelectExtension()
02092 {
02093     if (!autoSelectExtCheckBox) return;
02094 
02095     //
02096     // Figure out an extension for the Automatically Select Extension thing
02097     // (some Windows users apparently don't know what to do when confronted
02098     // with a text file called "COPYING" but do know what to do with
02099     // COPYING.txt ...)
02100     //
02101 
02102 //     kDebug (kfile_area) << "Figure out an extension: ";
02103     QString lastExtension = extension;
02104     extension.clear();
02105 
02106     // Automatically Select Extension is only valid if the user is _saving_ a _file_
02107     if ((operationMode == KFileWidget::Saving) && (ops->mode() & KFile::File))
02108     {
02109         //
02110         // Get an extension from the filter
02111         //
02112 
02113         QString filter = filterWidget->currentFilter();
02114         if (!filter.isEmpty())
02115         {
02116             // e.g. "*.cpp"
02117             if (filter.indexOf ('/') < 0)
02118             {
02119                 extension = getExtensionFromPatternList (filter.split(' ', QString::SkipEmptyParts)/*QStringList::split (" ", filter)*/).toLower();
02120 //                 kDebug (kfile_area) << "\tsetFilter-style: pattern ext=\'"
02121 //                                     << extension << "\'" << endl;
02122             }
02123             // e.g. "text/html"
02124             else
02125             {
02126                 KMimeType::Ptr mime = KMimeType::mimeType (filter);
02127                 if (mime)
02128                 {
02129                         extension = mime->mainExtension().toLower();
02130 //                         kDebug (kfile_area) << "\tsetMimeFilter-style: pattern ext=\'"
02131 //                                             << extension << "\'" << endl;
02132                 }
02133             }
02134         }
02135 
02136 
02137         //
02138         // GUI: checkbox
02139         //
02140 
02141         QString whatsThisExtension;
02142         if (!extension.isEmpty())
02143         {
02144             // remember: sync any changes to the string with below
02145             autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension (%1)",  extension));
02146             whatsThisExtension = i18n ("the extension <b>%1</b>",  extension);
02147 
02148             autoSelectExtCheckBox->setEnabled (true);
02149             autoSelectExtCheckBox->setChecked (autoSelectExtChecked);
02150         }
02151         else
02152         {
02153             // remember: sync any changes to the string with above
02154             autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension"));
02155             whatsThisExtension = i18n ("a suitable extension");
02156 
02157             autoSelectExtCheckBox->setChecked (false);
02158             autoSelectExtCheckBox->setEnabled (false);
02159         }
02160 
02161         const QString locationLabelText = stripUndisplayable (locationLabel->text());
02162         const QString filterLabelText = stripUndisplayable (filterLabel->text());
02163         autoSelectExtCheckBox->setWhatsThis(            "<qt>" +
02164                 i18n (
02165                   "This option enables some convenient features for "
02166                   "saving files with extensions:<br />"
02167                   "<ol>"
02168                     "<li>Any extension specified in the <b>%1</b> text "
02169                     "area will be updated if you change the file type "
02170                     "to save in.<br />"
02171                     "<br /></li>"
02172                     "<li>If no extension is specified in the <b>%2</b> "
02173                     "text area when you click "
02174                     "<b>Save</b>, %3 will be added to the end of the "
02175                     "filename (if the filename does not already exist). "
02176                     "This extension is based on the file type that you "
02177                     "have chosen to save in.<br />"
02178                     "<br />"
02179                     "If you do not want KDE to supply an extension for the "
02180                     "filename, you can either turn this option off or you "
02181                     "can suppress it by adding a period (.) to the end of "
02182                     "the filename (the period will be automatically "
02183                     "removed)."
02184                     "</li>"
02185                   "</ol>"
02186                   "If unsure, keep this option enabled as it makes your "
02187                   "files more manageable."
02188                     ,
02189                   locationLabelText,
02190                   locationLabelText,
02191                   whatsThisExtension)
02192             + "</qt>"
02193             );
02194 
02195         autoSelectExtCheckBox->show();
02196 
02197 
02198         // update the current filename's extension
02199         updateLocationEditExtension (lastExtension);
02200     }
02201     // Automatically Select Extension not valid
02202     else
02203     {
02204         autoSelectExtCheckBox->setChecked (false);
02205         autoSelectExtCheckBox->hide();
02206     }
02207 }
02208 
02209 // Updates the extension of the filename specified in d->locationEdit if the
02210 // Automatically Select Extension feature is enabled.
02211 // (this prevents you from accidently saving "file.kwd" as RTF, for example)
02212 void KFileWidgetPrivate::updateLocationEditExtension (const QString &lastExtension)
02213 {
02214     if (!autoSelectExtCheckBox->isChecked() || extension.isEmpty())
02215         return;
02216 
02217     QString urlStr = locationEditCurrentText();
02218     if (urlStr.isEmpty())
02219         return;
02220 
02221     KUrl url = getCompleteUrl(urlStr);
02222 //     kDebug (kfile_area) << "updateLocationEditExtension (" << url << ")";
02223 
02224     const int fileNameOffset = urlStr.lastIndexOf ('/') + 1;
02225     QString fileName = urlStr.mid (fileNameOffset);
02226 
02227     const int dot = fileName.lastIndexOf ('.');
02228     const int len = fileName.length();
02229     if (dot > 0 && // has an extension already and it's not a hidden file
02230                    // like ".hidden" (but we do accept ".hidden.ext")
02231         dot != len - 1 // and not deliberately suppressing extension
02232         )
02233     {
02234         // exists?
02235         KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo);
02236         bool result = KIO::NetAccess::synchronousRun(statJob, 0);
02237         if (result)
02238         {
02239 //             kDebug (kfile_area) << "\tfile exists";
02240 
02241             if (statJob->statResult().isDir())
02242             {
02243 //                 kDebug (kfile_area) << "\tisDir - won't alter extension";
02244                 return;
02245             }
02246 
02247             // --- fall through ---
02248         }
02249 
02250 
02251         //
02252         // try to get rid of the current extension
02253         //
02254 
02255         // catch "double extensions" like ".tar.gz"
02256         if (lastExtension.length() && fileName.endsWith (lastExtension))
02257             fileName.truncate (len - lastExtension.length());
02258         else if (extension.length() && fileName.endsWith (extension))
02259             fileName.truncate (len - extension.length());
02260         // can only handle "single extensions"
02261         else
02262             fileName.truncate (dot);
02263 
02264         // add extension
02265         const QString newText = urlStr.left (fileNameOffset) + fileName + extension;
02266         if ( newText != locationEditCurrentText() )
02267         {
02268             locationEdit->setItemText(locationEdit->currentIndex(),urlStr.left (fileNameOffset) + fileName + extension);
02269             locationEdit->lineEdit()->setModified (true);
02270         }
02271     }
02272 }
02273 
02274 // Updates the filter if the extension of the filename specified in d->locationEdit is changed
02275 // (this prevents you from accidently saving "file.kwd" as RTF, for example)
02276 void KFileWidgetPrivate::updateFilter()
02277 {
02278 //     kDebug(kfile_area);
02279 
02280     if ((operationMode == KFileWidget::Saving) && (ops->mode() & KFile::File) ) {
02281         const QString urlStr = locationEditCurrentText();
02282         if (urlStr.isEmpty())
02283             return;
02284 
02285         KMimeType::Ptr mime = KMimeType::findByPath(urlStr, 0, true);
02286         if (mime && mime->name() != KMimeType::defaultMimeType()) {
02287             if (filterWidget->currentFilter() != mime->name() &&
02288                 filterWidget->filters().indexOf(mime->name()) != -1)
02289                 filterWidget->setCurrentFilter(mime->name());
02290         }
02291     }
02292 }
02293 
02294 // applies only to a file that doesn't already exist
02295 void KFileWidgetPrivate::appendExtension (KUrl &url)
02296 {
02297 //     kDebug(kfile_area);
02298 
02299     if (!autoSelectExtCheckBox->isChecked() || extension.isEmpty())
02300         return;
02301 
02302     QString fileName = url.fileName();
02303     if (fileName.isEmpty())
02304         return;
02305 
02306 //     kDebug (kfile_area) << "appendExtension(" << url << ")";
02307 
02308     const int len = fileName.length();
02309     const int dot = fileName.lastIndexOf ('.');
02310 
02311     const bool suppressExtension = (dot == len - 1);
02312     const bool unspecifiedExtension = (dot <= 0);
02313 
02314     // don't KIO::Stat if unnecessary
02315     if (!(suppressExtension || unspecifiedExtension))
02316         return;
02317 
02318     // exists?
02319     KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo);
02320     bool res = KIO::NetAccess::synchronousRun(statJob, 0);
02321     if (res)
02322     {
02323 //         kDebug (kfile_area) << "\tfile exists - won't append extension";
02324         return;
02325     }
02326 
02327     // suppress automatically append extension?
02328     if (suppressExtension)
02329     {
02330         //
02331         // Strip trailing dot
02332         // This allows lazy people to have autoSelectExtCheckBox->isChecked
02333         // but don't want a file extension to be appended
02334         // e.g. "README." will make a file called "README"
02335         //
02336         // If you really want a name like "README.", then type "README.."
02337         // and the trailing dot will be removed (or just stop being lazy and
02338         // turn off this feature so that you can type "README.")
02339         //
02340 //         kDebug (kfile_area) << "\tstrip trailing dot";
02341         url.setFileName (fileName.left (len - 1));
02342     }
02343     // evilmatically append extension :) if the user hasn't specified one
02344     else if (unspecifiedExtension)
02345     {
02346 //         kDebug (kfile_area) << "\tappending extension \'" << extension << "\'...";
02347         url.setFileName (fileName + extension);
02348 //         kDebug (kfile_area) << "\tsaving as \'" << url << "\'";
02349     }
02350 }
02351 
02352 
02353 // adds the selected files/urls to 'recent documents'
02354 void KFileWidgetPrivate::addToRecentDocuments()
02355 {
02356     int m = ops->mode();
02357     int atmost = KRecentDocument::maximumItems();
02358     //don't add more than we need. KRecentDocument::add() is pretty slow
02359 
02360     if (m & KFile::LocalOnly) {
02361         const QStringList files = q->selectedFiles();
02362         QStringList::ConstIterator it = files.begin();
02363         for ( ; it != files.end() && atmost > 0; ++it ) {
02364             KRecentDocument::add( *it );
02365             atmost--;
02366         }
02367     }
02368 
02369     else { // urls
02370         const KUrl::List urls = q->selectedUrls();
02371         KUrl::List::ConstIterator it = urls.begin();
02372         for ( ; it != urls.end() && atmost > 0; ++it ) {
02373             if ( (*it).isValid() ) {
02374                 KRecentDocument::add( *it );
02375                 atmost--;
02376             }
02377         }
02378     }
02379 }
02380 
02381 KUrlComboBox* KFileWidget::locationEdit() const
02382 {
02383     return d->locationEdit;
02384 }
02385 
02386 KFileFilterCombo* KFileWidget::filterWidget() const
02387 {
02388     return d->filterWidget;
02389 }
02390 
02391 KActionCollection * KFileWidget::actionCollection() const
02392 {
02393     return d->ops->actionCollection();
02394 }
02395 
02396 void KFileWidgetPrivate::_k_toggleSpeedbar(bool show)
02397 {
02398     if (show) {
02399         initSpeedbar();
02400         placesDock->show();
02401         lafBox->setColumnMinimumWidth(0, placesViewWidth);
02402 
02403         // check to see if they have a home item defined, if not show the home button
02404         KUrl homeURL;
02405         homeURL.setPath( QDir::homePath() );
02406         KFilePlacesModel *model = static_cast<KFilePlacesModel*>(placesView->model());
02407         for (int rowIndex = 0 ; rowIndex < model->rowCount() ; rowIndex++) {
02408             QModelIndex index = model->index(rowIndex, 0);
02409             KUrl url = model->url(index);
02410 
02411             if ( homeURL.equals( url, KUrl::CompareWithoutTrailingSlash ) ) {
02412                 toolbar->removeAction( ops->actionCollection()->action( "home" ) );
02413                 break;
02414             }
02415         }
02416     } else {
02417         if (q->sender() == placesDock && placesDock && placesDock->isVisibleTo(q)) {
02418             // we didn't *really* go away! the dialog was simply hidden or
02419             // we changed virtual desktops or ...
02420             return;
02421         }
02422 
02423         if (placesDock) {
02424             placesDock->hide();
02425         }
02426 
02427         QAction* homeAction = ops->actionCollection()->action("home");
02428         QAction* reloadAction = ops->actionCollection()->action("reload");
02429         if (!toolbar->actions().contains(homeAction)) {
02430             toolbar->insertAction(reloadAction, homeAction);
02431         }
02432 
02433         // reset the lafbox to not follow the width of the splitter
02434         lafBox->setColumnMinimumWidth(0, 0);
02435     }
02436 
02437     static_cast<KToggleAction *>(q->actionCollection()->action("toggleSpeedbar"))->setChecked(show);
02438 }
02439 
02440 void KFileWidgetPrivate::_k_toggleBookmarks(bool show)
02441 {
02442     if (show)
02443     {
02444         if (bookmarkHandler)
02445         {
02446             return;
02447         }
02448 
02449         bookmarkHandler = new KFileBookmarkHandler( q );
02450         q->connect( bookmarkHandler, SIGNAL( openUrl( const QString& )),
02451                     SLOT( _k_enterUrl( const QString& )));
02452 
02453         bookmarkButton = new KActionMenu(KIcon("bookmarks"),i18n("Bookmarks"), q);
02454         bookmarkButton->setDelayed(false);
02455         q->actionCollection()->addAction("bookmark", bookmarkButton);
02456         bookmarkButton->setMenu(bookmarkHandler->menu());
02457         bookmarkButton->setWhatsThis(i18n("<qt>This button allows you to bookmark specific locations. "
02458                                 "Click on this button to open the bookmark menu where you may add, "
02459                                 "edit or select a bookmark.<br /><br />"
02460                                 "These bookmarks are specific to the file dialog, but otherwise operate "
02461                                 "like bookmarks elsewhere in KDE.</qt>"));
02462         toolbar->addAction(bookmarkButton);
02463     }
02464     else if (bookmarkHandler)
02465     {
02466         delete bookmarkHandler;
02467         bookmarkHandler = 0;
02468         delete bookmarkButton;
02469         bookmarkButton = 0;
02470     }
02471 
02472     static_cast<KToggleAction *>(q->actionCollection()->action("toggleBookmarks"))->setChecked( show );
02473 }
02474 
02475 
02476 // static, overloaded
02477 KUrl KFileWidget::getStartUrl( const KUrl& startDir,
02478                                QString& recentDirClass )
02479 {
02480     QString fileName;                   // result discarded
02481     return getStartUrl( startDir, recentDirClass, fileName );
02482 }
02483 
02484 
02485 // static, overloaded
02486 KUrl KFileWidget::getStartUrl( const KUrl& startDir,
02487                                QString& recentDirClass,
02488                                QString& fileName )
02489 {
02490     recentDirClass.clear();
02491     fileName.clear();
02492     KUrl ret;
02493 
02494     bool useDefaultStartDir = startDir.isEmpty();
02495     if ( !useDefaultStartDir )
02496     {
02497         if ( startDir.protocol() == "kfiledialog" )
02498         {
02499 
02500 //  The startDir URL with this protocol may be in the format:
02501 //                                                    directory()   fileName()
02502 //  1.  kfiledialog:///keyword                           "/"         keyword
02503 //  2.  kfiledialog:///keyword?global                    "/"         keyword
02504 //  3.  kfiledialog:///keyword/                          "/"         keyword
02505 //  4.  kfiledialog:///keyword/?global                   "/"         keyword
02506 //  5.  kfiledialog:///keyword/filename                /keyword      filename
02507 //  6.  kfiledialog:///keyword/filename?global         /keyword      filename
02508 
02509             QString keyword;
02510             QString urlDir = startDir.directory();
02511             QString urlFile = startDir.fileName();
02512             if ( urlDir == "/" )            // '1'..'4' above
02513             {
02514                 keyword = urlFile;
02515                 fileName = QString();
02516             }
02517             else                    // '5' or '6' above
02518             {
02519                 keyword = urlDir.mid( 1 );
02520                 fileName = urlFile;
02521             }
02522 
02523             if ( startDir.query() == "?global" )
02524               recentDirClass = QString( "::%1" ).arg( keyword );
02525             else
02526               recentDirClass = QString( ":%1" ).arg( keyword );
02527 
02528             ret = KUrl( KRecentDirs::dir(recentDirClass) );
02529         }
02530         else
02531         {
02532             ret = startDir;
02533             // If we won't be able to list it (e.g. http), then use default
02534             if ( !KProtocolManager::supportsListing( ret ) )
02535                 useDefaultStartDir = true;
02536         }
02537     }
02538 
02539     if ( useDefaultStartDir )
02540     {
02541         if (lastDirectory->isEmpty()) {
02542             lastDirectory->setPath(KGlobalSettings::documentPath());
02543             KUrl home;
02544             home.setPath( QDir::homePath() );
02545             // if there is no docpath set (== home dir), we prefer the current
02546             // directory over it. We also prefer the homedir when our CWD is
02547             // different from our homedirectory or when the document dir
02548             // does not exist
02549             if ( lastDirectory->path(KUrl::AddTrailingSlash) == home.path(KUrl::AddTrailingSlash) ||
02550                  QDir::currentPath() != QDir::homePath() ||
02551                  !QDir(lastDirectory->path(KUrl::AddTrailingSlash)).exists() )
02552                 lastDirectory->setPath(QDir::currentPath());
02553         }
02554         ret = *lastDirectory;
02555     }
02556 
02557     kDebug(kfile_area) << "for" << startDir << "ret" << ret << "recentDirClass" << recentDirClass << "fileName" << fileName;
02558     return ret;
02559 }
02560 
02561 void KFileWidget::setStartDir( const KUrl& directory )
02562 {
02563     if ( directory.isValid() )
02564         *lastDirectory = directory;
02565 }
02566 
02567 void KFileWidgetPrivate::setNonExtSelection()
02568 {
02569     // Enhanced rename: Don't highlight the file extension.
02570     QString filename = locationEditCurrentText();
02571     QString extension = KMimeType::extractKnownExtension( filename );
02572 
02573     if ( !extension.isEmpty() )
02574        locationEdit->lineEdit()->setSelection( 0, filename.length() - extension.length() - 1 );
02575     else
02576     {
02577        int lastDot = filename.lastIndexOf( '.' );
02578        if ( lastDot > 0 )
02579           locationEdit->lineEdit()->setSelection( 0, lastDot );
02580     }
02581 }
02582 
02583 KToolBar * KFileWidget::toolBar() const
02584 {
02585     return d->toolbar;
02586 }
02587 
02588 void KFileWidget::setCustomWidget(QWidget* widget)
02589 {
02590     delete d->bottomCustomWidget;
02591     d->bottomCustomWidget = widget;
02592 
02593     // add it to the dialog, below the filter list box.
02594 
02595     // Change the parent so that this widget is a child of the main widget
02596     d->bottomCustomWidget->setParent( this );
02597 
02598     d->vbox->addWidget( d->bottomCustomWidget );
02599     //d->vbox->addSpacing(3); // can't do this every time...
02600 
02601     // FIXME: This should adjust the tab orders so that the custom widget
02602     // comes after the Cancel button. The code appears to do this, but the result
02603     // somehow screws up the tab order of the file path combo box. Not a major
02604     // problem, but ideally the tab order with a custom widget should be
02605     // the same as the order without one.
02606     setTabOrder(d->cancelButton, d->bottomCustomWidget);
02607     setTabOrder(d->bottomCustomWidget, d->urlNavigator);
02608 }
02609 
02610 void KFileWidget::setCustomWidget(const QString& text, QWidget* widget)
02611 {
02612     delete d->labeledCustomWidget;
02613     d->labeledCustomWidget = widget;
02614 
02615     QLabel* label = new QLabel(text, this);
02616     label->setAlignment(Qt::AlignRight);
02617     d->lafBox->addWidget(label, 2, 0, Qt::AlignVCenter);
02618     d->lafBox->addWidget(widget, 2, 1, Qt::AlignVCenter);
02619 }
02620 
02621 void KFileWidget::virtual_hook( int id, void* data )
02622 {
02623     // this is a workaround to avoid binary compatibility breakage
02624     // since setConfirmOverwrite in kabstractfilewidget.h is a new function
02625     // introduced for 4.2. As stated in kabstractfilewidget.h this workaround
02626     // is going to become a virtual function for KDE5
02627 
02628     switch (id) {
02629         case 0: { // setConfirmOverwrite(bool)
02630                 bool *enable = static_cast<bool*>(data);
02631                 d->confirmOverwrite = *enable;
02632             }
02633             break;
02634         case 1: { // setInlinePreviewShown(bool)
02635                 bool *show = static_cast<bool*>(data);
02636                 d->setInlinePreviewShown(*show);
02637             }
02638             break;
02639         default:
02640             break;
02641     }
02642 }
02643 
02644 KDirOperator* KFileWidget::dirOperator()
02645 {
02646     return d->ops;
02647 }
02648 
02649 QString KFileWidgetPrivate::locationEditCurrentText() const
02650 {
02651     return QDir::fromNativeSeparators(locationEdit->currentText().trimmed());
02652 }
02653 
02654 KUrl KFileWidgetPrivate::mostLocalUrl(const KUrl &url)
02655 {
02656     if (url.isLocalFile()) {
02657         return url;
02658     }
02659 
02660     KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo);
02661     bool res = KIO::NetAccess::synchronousRun(statJob, 0);
02662 
02663     if (!res) {
02664         return url;
02665     }
02666 
02667     const QString path = statJob->statResult().stringValue(KIO::UDSEntry::UDS_LOCAL_PATH);
02668     if (!path.isEmpty()) {
02669         KUrl newUrl;
02670         newUrl.setPath(path);
02671         return newUrl;
02672     }
02673 
02674     return url;
02675 }
02676 
02677 void KFileWidgetPrivate::setInlinePreviewShown(bool show)
02678 {
02679     ops->setInlinePreviewShown(show);
02680 }
02681 
02682 #include "kfilewidget.moc"

KFile

Skip menu "KFile"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal