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

KFile

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

kdelibs

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