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

KFile

kfilewidget.cpp

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

KFile

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

kdelibs

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