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

KDE's Doxygen guidelines are available online.

KFile

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

kdelibs-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal