• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KFile

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

KFile

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
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