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