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