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

KFile

kfilewidget.cpp

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