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