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

KFile

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

kdelibs

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