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

KFile

kfilewidget.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 /* This file is part of the KDE libraries
00003     Copyright (C) 1997, 1998 Richard Moore <rich@kde.org>
00004                   1998 Stephan Kulow <coolo@kde.org>
00005                   1998 Daniel Grana <grana@ie.iwi.unibe.ch>
00006                   1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
00007                   2003 Clarence Dang <dang@kde.org>
00008                   2007 David Faure <faure@kde.org>
00009                   2008 Rafael Fernández López <ereslibre@kde.org>
00010 
00011     This library is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU Library General Public
00013     License as published by the Free Software Foundation; either
00014     version 2 of the License, or (at your option) any later version.
00015 
00016     This library is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019     Library General Public License for more details.
00020 
00021     You should have received a copy of the GNU Library General Public License
00022     along with this library; see the file COPYING.LIB.  If not, write to
00023     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00024     Boston, MA 02110-1301, USA.
00025 */
00026 
00027 #include "kfilewidget.h"
00028 
00029 #include "kfileplacesview.h"
00030 #include "kfileplacesmodel.h"
00031 #include "kfilebookmarkhandler_p.h"
00032 #include "kurlcombobox.h"
00033 #include "kurlnavigator.h"
00034 #include "kfilepreviewgenerator.h"
00035 #include <config-kfile.h>
00036 
00037 #include <kactioncollection.h>
00038 #include <kdiroperator.h>
00039 #include <kdirselectdialog.h>
00040 #include <kfilefiltercombo.h>
00041 #include <kimagefilepreview.h>
00042 #include <kmenu.h>
00043 #include <kmimetype.h>
00044 #include <kpushbutton.h>
00045 #include <krecentdocument.h>
00046 #include <ktoolbar.h>
00047 #include <kurlcompletion.h>
00048 #include <kuser.h>
00049 #include <kprotocolmanager.h>
00050 #include <kio/job.h>
00051 #include <kio/jobuidelegate.h>
00052 #include <kio/netaccess.h>
00053 #include <kio/scheduler.h>
00054 #include <krecentdirs.h>
00055 #include <kdebug.h>
00056 #include <kio/kfileitemdelegate.h>
00057 
00058 #include <QtGui/QCheckBox>
00059 #include <QtGui/QDockWidget>
00060 #include <QtGui/QLayout>
00061 #include <QtGui/QLabel>
00062 #include <QtGui/QLineEdit>
00063 #include <QtGui/QSplitter>
00064 #include <QtGui/QAbstractProxyModel>
00065 #include <QtCore/QFSFileEngine>
00066 #include <kshell.h>
00067 #include <kmessagebox.h>
00068 #include <kauthorized.h>
00069 
00070 class KFileWidgetPrivate
00071 {
00072 public:
00073     KFileWidgetPrivate(KFileWidget *widget)
00074         : q(widget),
00075           boxLayout(0),
00076           placesDock(0),
00077           placesView(0),
00078           placesViewSplitter(0),
00079           placesViewWidth(-1),
00080           labeledCustomWidget(0),
00081           bottomCustomWidget(0),
00082           autoSelectExtCheckBox(0),
00083           operationMode(KFileWidget::Opening),
00084           bookmarkHandler(0),
00085           toolbar(0),
00086           locationEdit(0),
00087           ops(0),
00088           filterWidget(0),
00089           autoSelectExtChecked(false),
00090           keepLocation(false),
00091           hasView(false),
00092           hasDefaultFilter(false),
00093           inAccept(false),
00094           dummyAdded(false),
00095           confirmOverwrite(false),
00096           differentHierarchyLevelItemsEntered(false),
00097           previewGenerator(0),
00098           iconSizeSlider(0)
00099     {
00100     }
00101 
00102     ~KFileWidgetPrivate()
00103     {
00104         delete bookmarkHandler; // Should be deleted before ops!
00105         delete ops;
00106     }
00107 
00108     void updateLocationWhatsThis();
00109     void updateAutoSelectExtension();
00110     void initSpeedbar();
00111     void initGUI();
00112     void readConfig(KConfigGroup &configGroup);
00113     void writeConfig(KConfigGroup &configGroup);
00114     void setNonExtSelection();
00115     void setLocationText(const KUrl&);
00116     void setLocationText(const KUrl::List&);
00117     void appendExtension(KUrl &url);
00118     void updateLocationEditExtension(const QString &);
00119     void updateFilter();
00120     KUrl::List& parseSelectedUrls();
00127     KUrl::List tokenize(const QString& line) const;
00131     void readRecentFiles(KConfigGroup &cg);
00135     void saveRecentFiles(KConfigGroup &cg);
00140     void multiSelectionChanged();
00141 
00145     KUrl getCompleteUrl(const QString&) const;
00146 
00151     void setDummyHistoryEntry(const QString& text, const QPixmap& icon = QPixmap(),
00152                               bool usePreviousPixmapIfNull = true);
00153 
00157     void removeDummyHistoryEntry();
00158 
00165     bool toOverwrite(const KUrl&);
00166 
00167     // private slots
00168     void _k_slotLocationChanged( const QString& );
00169     void _k_urlEntered( const KUrl& );
00170     void _k_enterUrl( const KUrl& );
00171     void _k_enterUrl( const QString& );
00172     void _k_locationAccepted( const QString& );
00173     void _k_slotFilterChanged();
00174     void _k_fileHighlighted( const KFileItem& );
00175     void _k_fileSelected( const KFileItem& );
00176     void _k_slotLoadingFinished();
00177     void _k_fileCompletion( const QString& );
00178     void _k_toggleSpeedbar( bool );
00179     void _k_toggleBookmarks( bool );
00180     void _k_slotAutoSelectExtClicked();
00181     void _k_placesViewSplitterMoved(int, int);
00182     void _k_activateUrlNavigator();
00183     void _k_zoomOutIconsSize();
00184     void _k_zoomInIconsSize();
00185 
00186     void addToRecentDocuments();
00187 
00188     QString locationEditCurrentText() const;
00189 
00195     static KUrl mostLocalUrl(const KUrl &url);
00196 
00197     KFileWidget* q;
00198 
00199     // the last selected url
00200     KUrl url;
00201 
00202     // the selected filenames in multiselection mode -- FIXME
00203     QString filenames;
00204 
00205     // now following all kind of widgets, that I need to rebuild
00206     // the geometry management
00207     QBoxLayout *boxLayout;
00208     QGridLayout *lafBox;
00209     QVBoxLayout *vbox;
00210 
00211     QLabel *locationLabel;
00212     QWidget *opsWidget;
00213     QWidget *pathSpacer;
00214 
00215     QLabel *filterLabel;
00216     KUrlNavigator *urlNavigator;
00217     KPushButton *okButton, *cancelButton;
00218     QDockWidget *placesDock;
00219     KFilePlacesView *placesView;
00220     QSplitter *placesViewSplitter;
00221     // caches the places view width. This value will be updated when the splitter
00222     // is moved. This allows us to properly set a value when the dialog itself
00223     // is resized
00224     int placesViewWidth;
00225 
00226     QWidget *labeledCustomWidget;
00227     QWidget *bottomCustomWidget;
00228 
00229     // Automatically Select Extension stuff
00230     QCheckBox *autoSelectExtCheckBox;
00231     QString extension; // current extension for this filter
00232 
00233     QList<KIO::StatJob*> statJobs;
00234 
00235     KUrl::List urlList; //the list of selected urls
00236 
00237     KFileWidget::OperationMode operationMode;
00238 
00239     // The file class used for KRecentDirs
00240     QString fileClass;
00241 
00242     KFileBookmarkHandler *bookmarkHandler;
00243 
00244     KActionMenu* bookmarkButton;
00245 
00246     KToolBar *toolbar;
00247     KUrlComboBox *locationEdit;
00248     KDirOperator *ops;
00249     KFileFilterCombo *filterWidget;
00250 
00251     KFilePlacesModel *model;
00252 
00253     // whether or not the _user_ has checked the above box
00254     bool autoSelectExtChecked : 1;
00255 
00256     // indicates if the location edit should be kept or cleared when changing
00257     // directories
00258     bool keepLocation : 1;
00259 
00260     // the KDirOperators view is set in KFileWidget::show(), so to avoid
00261     // setting it again and again, we have this nice little boolean :)
00262     bool hasView : 1;
00263 
00264     bool hasDefaultFilter : 1; // necessary for the operationMode
00265     bool autoDirectoryFollowing : 1;
00266     bool inAccept : 1; // true between beginning and end of accept()
00267     bool dummyAdded : 1; // if the dummy item has been added. This prevents the combo from having a
00268                      // blank item added when loaded
00269     bool confirmOverwrite : 1;
00270     bool differentHierarchyLevelItemsEntered;
00271 
00272     KFilePreviewGenerator *previewGenerator;
00273     QSlider *iconSizeSlider;
00274 };
00275 
00276 K_GLOBAL_STATIC(KUrl, lastDirectory) // to set the start path
00277 
00278 static const char autocompletionWhatsThisText[] = I18N_NOOP("<qt>While typing in the text area, you may be presented "
00279                                                   "with possible matches. "
00280                                                   "This feature can be controlled by clicking with the right mouse button "
00281                                                   "and selecting a preferred mode from the <b>Text Completion</b> menu.")  "</qt>";
00282 
00283 // returns true if the string contains "<a>:/" sequence, where <a> is at least 2 alpha chars
00284 static bool containsProtocolSection( const QString& string )
00285 {
00286     int len = string.length();
00287     static const char prot[] = ":/";
00288     for (int i=0; i < len;) {
00289         i = string.indexOf( QLatin1String(prot), i );
00290         if (i == -1)
00291             return false;
00292         int j=i-1;
00293         for (; j >= 0; j--) {
00294             const QChar& ch( string[j] );
00295             if (ch.toAscii() == 0 || !ch.isLetter())
00296                 break;
00297             if (ch.isSpace() && (i-j-1) >= 2)
00298                 return true;
00299         }
00300         if (j < 0 && i >= 2)
00301             return true; // at least two letters before ":/"
00302         i += 3; // skip : and / and one char
00303     }
00304     return false;
00305 }
00306 
00307 KFileWidget::KFileWidget( const KUrl& _startDir, QWidget *parent )
00308     : QWidget(parent), KAbstractFileWidget(), d(new KFileWidgetPrivate(this))
00309 {
00310     KUrl startDir(_startDir);
00311     QString filename;
00312 
00313     d->okButton = new KPushButton(KStandardGuiItem::ok(), this);
00314     d->okButton->setDefault(true);
00315     d->cancelButton = new KPushButton(KStandardGuiItem::cancel(), this);
00316     // The dialog shows them
00317     d->okButton->hide();
00318     d->cancelButton->hide();
00319 
00320     d->opsWidget = new QWidget(this);
00321     QVBoxLayout *opsWidgetLayout = new QVBoxLayout(d->opsWidget);
00322     opsWidgetLayout->setMargin(0);
00323     //d->toolbar = new KToolBar(this, true);
00324     d->toolbar = new KToolBar(d->opsWidget, true);
00325     d->toolbar->setObjectName("KFileWidget::toolbar");
00326     d->toolbar->setMovable(false);
00327     opsWidgetLayout->addWidget(d->toolbar);
00328 
00329     d->model = new KFilePlacesModel(this);
00330     d->urlNavigator = new KUrlNavigator(d->model, startDir, d->opsWidget); //d->toolbar);
00331     d->urlNavigator->setPlacesSelectorVisible(false);
00332     opsWidgetLayout->addWidget(d->urlNavigator);
00333 
00334     KUrl u;
00335     KUrlComboBox *pathCombo = d->urlNavigator->editor();
00336 #ifdef Q_WS_WIN
00337     foreach( const QFileInfo &drive,QFSFileEngine::drives() )
00338     {
00339         u.setPath( drive.filePath() );
00340         pathCombo->addDefaultUrl(u,
00341                                  KIO::pixmapForUrl( u, 0, KIconLoader::Small ),
00342                                  i18n("Drive: %1",  u.toLocalFile()));
00343     }
00344 #else
00345     u.setPath(QDir::rootPath());
00346     pathCombo->addDefaultUrl(u,
00347                              KIO::pixmapForUrl(u, 0, KIconLoader::Small),
00348                              u.toLocalFile());
00349 #endif
00350 
00351     u.setPath(QDir::homePath());
00352     pathCombo->addDefaultUrl(u, KIO::pixmapForUrl(u, 0, KIconLoader::Small),
00353                              u.path(KUrl::AddTrailingSlash));
00354 
00355     KUrl docPath;
00356     docPath.setPath( KGlobalSettings::documentPath() );
00357     if ( (u.path(KUrl::AddTrailingSlash) != docPath.path(KUrl::AddTrailingSlash)) &&
00358           QDir(docPath.path(KUrl::AddTrailingSlash)).exists() )
00359     {
00360         pathCombo->addDefaultUrl( docPath,
00361                                   KIO::pixmapForUrl( docPath, 0, KIconLoader::Small ),
00362                                   docPath.path(KUrl::AddTrailingSlash));
00363     }
00364 
00365     u.setPath( KGlobalSettings::desktopPath() );
00366     pathCombo->addDefaultUrl(u,
00367                              KIO::pixmapForUrl(u, 0, KIconLoader::Small),
00368                              u.path(KUrl::AddTrailingSlash));
00369 
00370     KIO::StatJob *statJob = KIO::stat(startDir, KIO::HideProgressInfo);
00371     bool res = KIO::NetAccess::synchronousRun(statJob, 0);
00372     if (res) {
00373         if (!statJob->statResult().isDir()) {
00374             startDir.adjustPath(KUrl::RemoveTrailingSlash);
00375             filename = startDir.fileName();
00376             startDir.setFileName(QString());
00377         }
00378     }
00379 
00380     d->url = getStartUrl( startDir, d->fileClass );
00381 
00382     d->ops = new KDirOperator(d->url, d->opsWidget);
00383     d->ops->setObjectName( "KFileWidget::ops" );
00384     opsWidgetLayout->addWidget(d->ops);
00385     connect(d->ops, SIGNAL(urlEntered(const KUrl&)),
00386             SLOT(_k_urlEntered(const KUrl&)));
00387     connect(d->ops, SIGNAL(fileHighlighted(const KFileItem &)),
00388             SLOT(_k_fileHighlighted(const KFileItem &)));
00389     connect(d->ops, SIGNAL(fileSelected(const KFileItem &)),
00390             SLOT(_k_fileSelected(const KFileItem &)));
00391     connect(d->ops, SIGNAL(finishedLoading()),
00392             SLOT(_k_slotLoadingFinished()));
00393 
00394     d->ops->setupMenu(KDirOperator::SortActions |
00395                    KDirOperator::FileActions |
00396                    KDirOperator::ViewActions);
00397     KActionCollection *coll = d->ops->actionCollection();
00398 
00399     // add nav items to the toolbar
00400     //
00401     // NOTE:  The order of the button icons here differs from that
00402     // found in the file manager and web browser, but has been discussed
00403     // and agreed upon on the kde-core-devel mailing list:
00404     //
00405     // http://lists.kde.org/?l=kde-core-devel&m=116888382514090&w=2
00406 
00407     coll->action( "up" )->setWhatsThis(i18n("<qt>Click this button to enter the parent folder.<br /><br />"
00408                                             "For instance, if the current location is file:/home/%1 clicking this "
00409                                             "button will take you to file:/home.</qt>",  KUser().loginName() ));
00410 
00411     coll->action( "back" )->setWhatsThis(i18n("Click this button to move backwards one step in the browsing history."));
00412     coll->action( "forward" )->setWhatsThis(i18n("Click this button to move forward one step in the browsing history."));
00413 
00414     coll->action( "reload" )->setWhatsThis(i18n("Click this button to reload the contents of the current location."));
00415     coll->action( "mkdir" )->setShortcut( QKeySequence(Qt::Key_F10) );
00416     coll->action( "mkdir" )->setWhatsThis(i18n("Click this button to create a new folder."));
00417 
00418     KAction *goToNavigatorAction = coll->addAction( "gotonavigator", this, SLOT( _k_activateUrlNavigator() ) );
00419     goToNavigatorAction->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_L) );
00420 
00421     KToggleAction *showSidebarAction =
00422         new KToggleAction(i18n("Show Places Navigation Panel"), this);
00423     coll->addAction("toggleSpeedbar", showSidebarAction);
00424     showSidebarAction->setShortcut( QKeySequence(Qt::Key_F9) );
00425     connect( showSidebarAction, SIGNAL( toggled( bool ) ),
00426              SLOT( _k_toggleSpeedbar( bool )) );
00427 
00428     KToggleAction *showBookmarksAction =
00429         new KToggleAction(i18n("Show Bookmarks"), this);
00430     coll->addAction("toggleBookmarks", showBookmarksAction);
00431     connect( showBookmarksAction, SIGNAL( toggled( bool ) ),
00432              SLOT( _k_toggleBookmarks( bool )) );
00433 
00434     KActionMenu *menu = new KActionMenu( KIcon("configure"), i18n("Options"), this);
00435     coll->addAction("extra menu", menu);
00436     menu->setWhatsThis(i18n("<qt>This is the preferences menu for the file dialog. "
00437                             "Various options can be accessed from this menu including: <ul>"
00438                             "<li>how files are sorted in the list</li>"
00439                             "<li>types of view, including icon and list</li>"
00440                             "<li>showing of hidden files</li>"
00441                             "<li>the Places navigation panel</li>"
00442                             "<li>file previews</li>"
00443                             "<li>separating folders from files</li></ul></qt>"));
00444     menu->addAction(coll->action("sorting menu"));
00445     menu->addAction(coll->action("view menu"));
00446     menu->addSeparator();
00447     menu->addAction(coll->action("decoration menu"));
00448     menu->addSeparator();
00449     coll->action( "show hidden" )->setShortcut( QKeySequence(Qt::Key_F8) );
00450     menu->addAction( coll->action( "show hidden" ));
00451     menu->addAction( showSidebarAction );
00452     menu->addAction( showBookmarksAction );
00453     coll->action( "inline preview" )->setShortcut( QKeySequence(Qt::Key_F11) );
00454     menu->addAction( coll->action( "preview" ));
00455 
00456     menu->setDelayed( false );
00457     connect( menu->menu(), SIGNAL( aboutToShow() ),
00458              d->ops, SLOT( updateSelectionDependentActions() ));
00459 
00460     d->iconSizeSlider = new QSlider(this);
00461     d->iconSizeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
00462     d->iconSizeSlider->setOrientation(Qt::Horizontal);
00463     d->iconSizeSlider->setMinimum(0);
00464     d->iconSizeSlider->setMaximum(100);
00465     connect(d->iconSizeSlider, SIGNAL(valueChanged(int)),
00466             d->ops, SLOT(setIconsZoom(int)));
00467     connect(d->ops, SIGNAL(currentIconSizeChanged(int)),
00468             d->iconSizeSlider, SLOT(setValue(int)));
00469 
00470     KAction *furtherAction = new KAction(KIcon("zoom-out"), i18n("Zoom out"), this);
00471     connect(furtherAction, SIGNAL(triggered()), SLOT(_k_zoomOutIconsSize()));
00472     KAction *closerAction = new KAction(KIcon("zoom-in"), i18n("Zoom in"), this);
00473     connect(closerAction, SIGNAL(triggered()), SLOT(_k_zoomInIconsSize()));
00474 
00475     QWidget *midSpacer = new QWidget(this);
00476     midSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00477 
00478     QAction *separator = new QAction(this);
00479     separator->setSeparator(true);
00480 
00481     QAction *separator2 = new QAction(this);
00482     separator2->setSeparator(true);
00483 
00484     QAction *separator3 = new QAction(this);
00485     separator3->setSeparator(true);
00486 
00487     d->toolbar->addAction(coll->action("back" ));
00488     d->toolbar->addAction(coll->action("forward"));
00489     d->toolbar->addAction(coll->action("up"));
00490     d->toolbar->addAction(coll->action("reload"));
00491     d->toolbar->addAction(separator);
00492     d->toolbar->addAction(coll->action("short view"));
00493     d->toolbar->addAction(coll->action("detailed view"));
00494     d->toolbar->addAction(separator2);
00495     d->toolbar->addAction(coll->action("inline preview"));
00496     d->toolbar->addWidget(midSpacer);
00497     d->toolbar->addAction(furtherAction);
00498     d->toolbar->addWidget(d->iconSizeSlider);
00499     d->toolbar->addAction(closerAction);
00500     d->toolbar->addAction(separator3);
00501     d->toolbar->addAction(coll->action("mkdir"));
00502     d->toolbar->addAction(menu);
00503 
00504     d->toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
00505     d->toolbar->setMovable(false);
00506 
00507     KUrlCompletion *pathCompletionObj = new KUrlCompletion( KUrlCompletion::DirCompletion );
00508     pathCombo->setCompletionObject( pathCompletionObj );
00509     pathCombo->setAutoDeleteCompletionObject( true );
00510 
00511     connect( d->urlNavigator, SIGNAL( urlChanged( const KUrl&  )),
00512              this,  SLOT( _k_enterUrl( const KUrl& ) ));
00513     connect( d->urlNavigator, SIGNAL( returnPressed() ),
00514              d->ops,  SLOT( setFocus() ));
00515 
00516     QString whatsThisText;
00517 
00518     // the Location label/edit
00519     d->locationLabel = new QLabel(i18n("&Name:"), this);
00520     d->locationEdit = new KUrlComboBox(KUrlComboBox::Files, true, this);
00521     // Properly let the dialog be resized (to smaller). Otherwise we could have
00522     // huge dialogs that can't be resized to smaller (it would be as big as the longest
00523     // item in this combo box). (ereslibre)
00524     d->locationEdit->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
00525     connect( d->locationEdit, SIGNAL( editTextChanged( const QString& ) ),
00526              SLOT( _k_slotLocationChanged( const QString& )) );
00527 
00528     d->updateLocationWhatsThis();
00529     d->locationLabel->setBuddy(d->locationEdit);
00530 
00531     KUrlCompletion *fileCompletionObj = new KUrlCompletion( KUrlCompletion::FileCompletion );
00532     d->locationEdit->setCompletionObject( fileCompletionObj );
00533     d->locationEdit->setAutoDeleteCompletionObject( true );
00534     connect( fileCompletionObj, SIGNAL( match( const QString& ) ),
00535              SLOT( _k_fileCompletion( const QString& )) );
00536 
00537     connect(d->locationEdit, SIGNAL( returnPressed( const QString&  )),
00538             this,  SLOT( _k_locationAccepted( const QString& ) ));
00539 
00540     // the Filter label/edit
00541     whatsThisText = i18n("<qt>This is the filter to apply to the file list. "
00542                          "File names that do not match the filter will not be shown.<p>"
00543                          "You may select from one of the preset filters in the "
00544                          "drop down menu, or you may enter a custom filter "
00545                          "directly into the text area.</p><p>"
00546                          "Wildcards such as * and ? are allowed.</p></qt>");
00547     d->filterLabel = new QLabel(i18n("&Filter:"), this);
00548     d->filterLabel->setWhatsThis(whatsThisText);
00549     d->filterWidget = new KFileFilterCombo(this);
00550     // Properly let the dialog be resized (to smaller). Otherwise we could have
00551     // huge dialogs that can't be resized to smaller (it would be as big as the longest
00552     // item in this combo box). (ereslibre)
00553     d->filterWidget->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
00554     d->filterWidget->setWhatsThis(whatsThisText);
00555     d->filterLabel->setBuddy(d->filterWidget);
00556     connect(d->filterWidget, SIGNAL(filterChanged()), SLOT(_k_slotFilterChanged()));
00557 
00558     // the Automatically Select Extension checkbox
00559     // (the text, visibility etc. is set in updateAutoSelectExtension(), which is called by readConfig())
00560     d->autoSelectExtCheckBox = new QCheckBox (this);
00561     d->autoSelectExtCheckBox->setStyleSheet(QString("QCheckBox { padding-top: %1px; }").arg(KDialog::spacingHint()));
00562     connect(d->autoSelectExtCheckBox, SIGNAL(clicked()), SLOT(_k_slotAutoSelectExtClicked()));
00563 
00564     d->initGUI(); // activate GM
00565 
00566     // read our configuration
00567     KSharedConfig::Ptr config = KGlobal::config();
00568     KConfigGroup viewConfigGroup(config, ConfigGroup);
00569     d->readConfig(viewConfigGroup);
00570 
00571     coll->action("inline preview")->setChecked(d->ops->isInlinePreviewShown());
00572     d->iconSizeSlider->setValue(d->ops->iconsZoom());
00573 
00574     KFilePreviewGenerator *pg = d->ops->previewGenerator();
00575     if (pg) {
00576         coll->action("inline preview")->setChecked(pg->isPreviewShown());
00577     }
00578 
00579     // we know it is not a dir, and we could stat it. Set it.
00580     if (!filename.isEmpty()) {
00581         d->locationEdit->lineEdit()->setText(filename);
00582     }
00583 
00584     d->locationEdit->setFocus();
00585 }
00586 
00587 KFileWidget::~KFileWidget()
00588 {
00589     KSharedConfig::Ptr config = KGlobal::config();
00590     config->sync();
00591 
00592     delete d;
00593 }
00594 
00595 void KFileWidget::setLocationLabel(const QString& text)
00596 {
00597     d->locationLabel->setText(text);
00598 }
00599 
00600 void KFileWidget::setFilter(const QString& filter)
00601 {
00602     int pos = filter.indexOf('/');
00603 
00604     // Check for an un-escaped '/', if found
00605     // interpret as a MIME filter.
00606 
00607     if (pos > 0 && filter[pos - 1] != '\\') {
00608         QStringList filters = filter.split(" ", QString::SkipEmptyParts);
00609         setMimeFilter( filters );
00610         return;
00611     }
00612 
00613     // Strip the escape characters from
00614     // escaped '/' characters.
00615 
00616     QString copy (filter);
00617     for (pos = 0; (pos = copy.indexOf("\\/", pos)) != -1; ++pos)
00618         copy.remove(pos, 1);
00619 
00620     d->ops->clearFilter();
00621     d->filterWidget->setFilter(copy);
00622     d->ops->setNameFilter(d->filterWidget->currentFilter());
00623     d->hasDefaultFilter = false;
00624     d->filterWidget->setEditable( true );
00625 
00626     d->updateAutoSelectExtension ();
00627 }
00628 
00629 QString KFileWidget::currentFilter() const
00630 {
00631     return d->filterWidget->currentFilter();
00632 }
00633 
00634 void KFileWidget::setMimeFilter( const QStringList& mimeTypes,
00635                                  const QString& defaultType )
00636 {
00637     d->filterWidget->setMimeFilter( mimeTypes, defaultType );
00638 
00639     QStringList types = d->filterWidget->currentFilter().split(" ",QString::SkipEmptyParts); //QStringList::split(" ", d->filterWidget->currentFilter());
00640     types.append( QLatin1String( "inode/directory" ));
00641     d->ops->clearFilter();
00642     d->ops->setMimeFilter( types );
00643     d->hasDefaultFilter = !defaultType.isEmpty();
00644     d->filterWidget->setEditable( !d->hasDefaultFilter ||
00645                                d->operationMode != Saving );
00646 
00647     d->updateAutoSelectExtension ();
00648 }
00649 
00650 void KFileWidget::clearFilter()
00651 {
00652     d->filterWidget->setFilter( QString() );
00653     d->ops->clearFilter();
00654     d->hasDefaultFilter = false;
00655     d->filterWidget->setEditable( true );
00656 
00657     d->updateAutoSelectExtension ();
00658 }
00659 
00660 QString KFileWidget::currentMimeFilter() const
00661 {
00662     int i = d->filterWidget->currentIndex();
00663     if (d->filterWidget->showsAllTypes() && i == 0)
00664         return QString(); // The "all types" item has no mimetype
00665 
00666     return d->filterWidget->filters()[i];
00667 }
00668 
00669 KMimeType::Ptr KFileWidget::currentFilterMimeType()
00670 {
00671     return KMimeType::mimeType( currentMimeFilter() );
00672 }
00673 
00674 void KFileWidget::setPreviewWidget(KPreviewWidgetBase *w) {
00675     d->ops->setPreviewWidget(w);
00676     d->ops->clearHistory();
00677     d->hasView = true;
00678 }
00679 
00680 KUrl KFileWidgetPrivate::getCompleteUrl(const QString &_url) const
00681 {
00682 //     kDebug(kfile_area) << "got url " << _url;
00683 
00684     QString url = KShell::tildeExpand(_url);
00685     KUrl u;
00686 
00687     if ( KUrl::isRelativeUrl(url) ) // only a full URL isn't relative. Even /path is.
00688     {
00689         if (!url.isEmpty() && !QDir::isRelativePath(url) ) // absolute path
00690             u.setPath( url );
00691         else
00692         {
00693             u = ops->url();
00694 //             kDebug(kfile_area) << "ops url " << u;
00695             u.addPath( url ); // works for filenames and relative paths
00696 //             kDebug(kfile_area) << "after adding path " << u;
00697             u.cleanPath(); // fix "dir/.."
00698 //             kDebug(kfile_area) << "after cleaning path " << u;
00699         }
00700     }
00701     else // complete URL
00702         u = url;
00703 
00704 //     kDebug(kfile_area) << "returning url " << u;
00705 
00706     return u;
00707 }
00708 
00709 // Called by KFileDialog
00710 void KFileWidget::slotOk()
00711 {
00712 //     kDebug(kfile_area) << "slotOk\n";
00713 
00714     const KFileItemList items = d->ops->selectedItems();
00715     const QString locationEditCurrentText(KShell::tildeExpand(d->locationEditCurrentText()));
00716     KUrl::List locationEditCurrentTextList(d->tokenize(locationEditCurrentText));
00717     KFile::Modes mode = d->ops->mode();
00718 
00719     // if there is nothing to do, just return from here
00720     if (!locationEditCurrentTextList.count()) {
00721         return;
00722     }
00723 
00724     // Make sure that one of the modes was provided
00725     Q_ASSERT((mode & KFile::File) || (mode & KFile::Directory) || (mode & KFile::Files));
00726 
00727     // if we are on file mode, and the list of provided files/folder is greater than one, inform
00728     // the user about it
00729     if (locationEditCurrentTextList.count() > 1) {
00730         if (mode & KFile::File) {
00731             KMessageBox::sorry(this,
00732                                i18n("You can only select one file"),
00733                                i18n("More than one file provided"));
00734             return;
00735         }
00736 
00757         if (!d->differentHierarchyLevelItemsEntered) {     // avoid infinite recursion. running this
00758             KUrl::List urlList;                            // one time is always enough.
00759             int start = 0;
00760             KUrl topMostUrl;
00761             KIO::StatJob *statJob;
00762             bool res = false;
00763 
00764             // we need to check for a valid first url, so in theory we only iterate one time over
00765             // this loop. However it can happen that the user did
00766             // "home/foo/nonexistantfile" "boot/grub/menu.lst", so we look for a good first
00767             // candidate.
00768             while (!res && start < locationEditCurrentTextList.count()) {
00769                 topMostUrl = locationEditCurrentTextList.at(start);
00770                 statJob = KIO::stat(topMostUrl, KIO::HideProgressInfo);
00771                 res = KIO::NetAccess::synchronousRun(statJob, 0);
00772                 start++;
00773             }
00774 
00775             // if this is not a dir, strip the filename. after this we have an existant and valid
00776             // dir (if we stated correctly the file, setting a null filename won't make any bad).
00777             if (!statJob->statResult().isDir()) {
00778                 topMostUrl.setFileName(QString());
00779             }
00780 
00781             // now the funny part. for the rest of filenames, go and look for the closest ancestor
00782             // of all them.
00783             for (int i = start; i < locationEditCurrentTextList.count(); ++i) {
00784                 KUrl currUrl = locationEditCurrentTextList.at(i);
00785                 KIO::StatJob *statJob = KIO::stat(currUrl, KIO::HideProgressInfo);
00786                 bool res = KIO::NetAccess::synchronousRun(statJob, 0);
00787                 if (res) {
00788                     // again, we don't care about filenames
00789                     if (!statJob->statResult().isDir()) {
00790                         currUrl.setFileName(QString());
00791                     }
00792 
00793                     // iterate while this item is contained on the top most url
00794                     while (!topMostUrl.isParentOf(currUrl)) {
00795                         topMostUrl = topMostUrl.upUrl();
00796                     }
00797                 }
00798             }
00799 
00800             // now recalculate all paths for them being relative in base of the top most url
00801             for (int i = 0; i < locationEditCurrentTextList.count(); ++i) {
00802                 locationEditCurrentTextList[i] = KUrl::relativeUrl(topMostUrl, locationEditCurrentTextList[i]);
00803             }
00804 
00805             d->ops->setUrl(topMostUrl, true);
00806             const bool signalsBlocked = d->locationEdit->lineEdit()->blockSignals(true);
00807             QStringList stringList;
00808             foreach (const KUrl &url, locationEditCurrentTextList) {
00809                 stringList << url.prettyUrl();
00810             }
00811             d->locationEdit->lineEdit()->setText(QString("\"%1\"").arg(stringList.join("\" \"")));
00812             d->locationEdit->lineEdit()->blockSignals(signalsBlocked);
00813 
00814             d->differentHierarchyLevelItemsEntered = true;
00815             slotOk();
00816             return;
00817         }
00821     } else if (locationEditCurrentTextList.count()) {
00822         // if we are on file or files mode, and we have an absolute url written by
00823         // the user, convert it to relative
00824         if (!(mode & KFile::Directory) && (!KUrl::isRelativeUrl(locationEditCurrentText) ||
00825                                            QDir::isAbsolutePath(locationEditCurrentText))) {
00826             KUrl _url(locationEditCurrentText);
00827             KUrl url(_url.path(KUrl::RemoveTrailingSlash));
00828             url.setFileName(QString());
00829             d->ops->setUrl(url, true);
00830             const bool signalsBlocked = d->locationEdit->lineEdit()->blockSignals(true);
00831             d->locationEdit->lineEdit()->setText(_url.fileName());
00832             d->locationEdit->lineEdit()->blockSignals(signalsBlocked);
00833             slotOk();
00834             return;
00835         }
00836     }
00837 
00838     // restore it
00839     d->differentHierarchyLevelItemsEntered = false;
00840 
00841     // if we are on local mode, make sure we haven't got a remote base url
00842     if ((mode & KFile::LocalOnly) && !d->mostLocalUrl(d->url).isLocalFile()) {
00843         KMessageBox::sorry(this,
00844                            i18n("You can only select local files"),
00845                            i18n("Remote files not accepted"));
00846         return;
00847     }
00848 
00849     // locationEditCurrentTextList contains absolute paths
00850     // this is the general loop for the File and Files mode. Obviously we know
00851     // that the File mode will iterate only one time here
00852     bool directoryMode = (mode & KFile::Directory);
00853     bool onlyDirectoryMode = directoryMode && !(mode & KFile::File) && !(mode & KFile::Files);
00854     foreach (const KUrl &url, locationEditCurrentTextList) {
00855         d->url = url;
00856         KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo);
00857         bool res = KIO::NetAccess::synchronousRun(statJob, 0);
00858 
00859         if (!KAuthorized::authorizeUrlAction("open", KUrl(), url)) {
00860             QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, d->url.prettyUrl());
00861             KMessageBox::error(this, msg);
00862             return;
00863         }
00864 
00865         if ((d->operationMode == Saving) && d->confirmOverwrite && !d->toOverwrite(url)) {
00866             return;
00867         }
00868 
00869         // if we are given a folder when not on directory mode, let's get into it
00870         if (res && !directoryMode && statJob->