tdefiledialog.cpp
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 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00022 Boston, MA 02110-1301, USA. 00023 */ 00024 00025 #include "tdefiledialog.h" 00026 00027 #include <unistd.h> 00028 #include <stdlib.h> 00029 #include <stdio.h> 00030 00031 #include <tqptrcollection.h> 00032 #include <tqcheckbox.h> 00033 #include <tqcombobox.h> 00034 #include <tqlabel.h> 00035 #include <tqlayout.h> 00036 #include <tqlineedit.h> 00037 #include <tqptrlist.h> 00038 #include <tqpixmap.h> 00039 #include <tqtextcodec.h> 00040 #include <tqtooltip.h> 00041 #include <tqtimer.h> 00042 #include <tqwhatsthis.h> 00043 #include <tqfiledialog.h> 00044 00045 #include <tdeaccel.h> 00046 #include <tdeaction.h> 00047 #include <tdeapplication.h> 00048 #include <kcharsets.h> 00049 #include <tdecmdlineargs.h> 00050 #include <tdecompletionbox.h> 00051 #include <tdeconfig.h> 00052 #include <kdebug.h> 00053 #include <tdeglobal.h> 00054 #include <tdeglobalsettings.h> 00055 #include <kiconloader.h> 00056 #include <kimageio.h> 00057 #include <tdeio/job.h> 00058 #include <tdeio/netaccess.h> 00059 #include <tdeio/scheduler.h> 00060 #include <tdeio/kservicetypefactory.h> 00061 #include <tdelocale.h> 00062 #include <tdemessagebox.h> 00063 #include <kmimetype.h> 00064 #include <tdepopupmenu.h> 00065 #include <kprotocolinfo.h> 00066 #include <kpushbutton.h> 00067 #include <tderecentdirs.h> 00068 #include <kshell.h> 00069 #include <kstandarddirs.h> 00070 #include <kstdguiitem.h> 00071 #include <kstaticdeleter.h> 00072 #include <tdetoolbar.h> 00073 #include <tdetoolbarbutton.h> 00074 #include <kurl.h> 00075 #include <kurlcombobox.h> 00076 #include <kurlcompletion.h> 00077 #include <kuser.h> 00078 00079 #include "config-tdefile.h" 00080 #include "kpreviewwidgetbase.h" 00081 00082 #include <kdirselectdialog.h> 00083 #include <tdefileview.h> 00084 #include <tderecentdocument.h> 00085 #include <tdefilefiltercombo.h> 00086 #include <tdediroperator.h> 00087 #include <kimagefilepreview.h> 00088 00089 #include <tdefilespeedbar.h> 00090 #include <tdefilebookmarkhandler.h> 00091 00092 #ifdef Q_WS_X11 00093 #include <X11/Xlib.h> 00094 #include <fixx11h.h> 00095 #endif 00096 00097 enum Buttons { HOTLIST_BUTTON, 00098 PATH_COMBO, CONFIGURE_BUTTON }; 00099 00100 template class TQPtrList<TDEIO::StatJob>; 00101 00102 namespace { 00103 static void silenceQToolBar(TQtMsgType, const char *) 00104 { 00105 } 00106 } 00107 00108 struct KFileDialogPrivate 00109 { 00110 // the last selected url 00111 KURL url; 00112 00113 // the selected filenames in multiselection mode -- FIXME 00114 TQString filenames; 00115 00116 // the name of the filename set by setSelection 00117 TQString selection; 00118 00119 // now following all kind of widgets, that I need to rebuild 00120 // the geometry management 00121 TQBoxLayout *boxLayout; 00122 TQWidget *mainWidget; 00123 00124 TQLabel *locationLabel; 00125 00126 // @deprecated remove in KDE4 00127 TQLabel *filterLabel; 00128 KURLComboBox *pathCombo; 00129 KPushButton *okButton, *cancelButton; 00130 KFileSpeedBar *urlBar; 00131 TQHBoxLayout *urlBarLayout; 00132 TQWidget *customWidget; 00133 00134 // Automatically Select Extension stuff 00135 TQCheckBox *autoSelectExtCheckBox; 00136 bool autoSelectExtChecked; // whether or not the _user_ has checked the above box 00137 TQString extension; // current extension for this filter 00138 00139 TQPtrList<TDEIO::StatJob> statJobs; 00140 00141 KURL::List urlList; //the list of selected urls 00142 00143 TQStringList mimetypes; //the list of possible mimetypes to save as 00144 00145 // indicates if the location edit should be kept or cleared when changing 00146 // directories 00147 bool keepLocation :1; 00148 00149 // the KDirOperators view is set in KFileDialog::show(), so to avoid 00150 // setting it again and again, we have this nice little boolean :) 00151 bool hasView :1; 00152 00153 bool hasDefaultFilter :1; // necessary for the operationMode 00154 KFileDialog::OperationMode operationMode; 00155 00156 // The file class used for TDERecentDirs 00157 TQString fileClass; 00158 00159 KFileBookmarkHandler *bookmarkHandler; 00160 00161 // the ID of the path drop down so subclasses can place their custom widgets properly 00162 int m_pathComboIndex; 00163 }; 00164 00165 KURL *KFileDialog::lastDirectory; // to set the start path 00166 00167 static KStaticDeleter<KURL> ldd; 00168 00169 KFileDialog::KFileDialog(const TQString& startDir, const TQString& filter, 00170 TQWidget *parent, const char* name, bool modal) 00171 : KDialogBase( parent, name, modal, TQString::null, 0 ) 00172 { 00173 init( startDir, filter, 0 ); 00174 } 00175 00176 KFileDialog::KFileDialog(const TQString& startDir, const TQString& filter, 00177 TQWidget *parent, const char* name, bool modal, TQWidget* widget) 00178 : KDialogBase( parent, name, modal, TQString::null, 0 ) 00179 { 00180 init( startDir, filter, widget ); 00181 } 00182 00183 00184 KFileDialog::~KFileDialog() 00185 { 00186 hide(); 00187 00188 TDEConfig *config = TDEGlobal::config(); 00189 00190 if (d->urlBar) 00191 d->urlBar->save( config ); 00192 00193 config->sync(); 00194 00195 delete d->bookmarkHandler; // Should be deleted before ops! 00196 delete ops; 00197 delete d; 00198 } 00199 00200 void KFileDialog::setLocationLabel(const TQString& text) 00201 { 00202 d->locationLabel->setText(text); 00203 } 00204 00205 void KFileDialog::setFilter(const TQString& filter) 00206 { 00207 int pos = filter.find('/'); 00208 00209 // Check for an un-escaped '/', if found 00210 // interpret as a MIME filter. 00211 00212 if (pos > 0 && filter[pos - 1] != '\\') { 00213 TQStringList filters = TQStringList::split( " ", filter ); 00214 setMimeFilter( filters ); 00215 return; 00216 } 00217 00218 // Strip the escape characters from 00219 // escaped '/' characters. 00220 00221 TQString copy (filter); 00222 for (pos = 0; (pos = copy.find("\\/", pos)) != -1; ++pos) 00223 copy.remove(pos, 1); 00224 00225 ops->clearFilter(); 00226 filterWidget->setFilter(copy); 00227 ops->setNameFilter(filterWidget->currentFilter()); 00228 d->hasDefaultFilter = false; 00229 filterWidget->setEditable( true ); 00230 00231 updateAutoSelectExtension (); 00232 } 00233 00234 TQString KFileDialog::currentFilter() const 00235 { 00236 return filterWidget->currentFilter(); 00237 } 00238 00239 // deprecated 00240 void KFileDialog::setFilterMimeType(const TQString &label, 00241 const KMimeType::List &types, 00242 const KMimeType::Ptr &defaultType) 00243 { 00244 d->mimetypes.clear(); 00245 d->filterLabel->setText(label); 00246 00247 KMimeType::List::ConstIterator it; 00248 for( it = types.begin(); it != types.end(); ++it) 00249 d->mimetypes.append( (*it)->name() ); 00250 00251 setMimeFilter( d->mimetypes, defaultType->name() ); 00252 } 00253 00254 void KFileDialog::setMimeFilter( const TQStringList& mimeTypes, 00255 const TQString& defaultType ) 00256 { 00257 d->mimetypes = mimeTypes; 00258 filterWidget->setMimeFilter( mimeTypes, defaultType ); 00259 00260 TQStringList types = TQStringList::split(" ", filterWidget->currentFilter()); 00261 types.append( TQString::fromLatin1( "inode/directory" )); 00262 ops->clearFilter(); 00263 ops->setMimeFilter( types ); 00264 d->hasDefaultFilter = !defaultType.isEmpty(); 00265 filterWidget->setEditable( !d->hasDefaultFilter || 00266 d->operationMode != Saving ); 00267 00268 updateAutoSelectExtension (); 00269 } 00270 00271 void KFileDialog::clearFilter() 00272 { 00273 d->mimetypes.clear(); 00274 filterWidget->setFilter( TQString::null ); 00275 ops->clearFilter(); 00276 d->hasDefaultFilter = false; 00277 filterWidget->setEditable( true ); 00278 00279 updateAutoSelectExtension (); 00280 } 00281 00282 TQString KFileDialog::currentMimeFilter() const 00283 { 00284 int i = filterWidget->currentItem(); 00285 if (filterWidget->showsAllTypes()) 00286 i--; 00287 00288 if ((i >= 0) && (i < (int) d->mimetypes.count())) 00289 return d->mimetypes[i]; 00290 return TQString::null; // The "all types" item has no mimetype 00291 } 00292 00293 KMimeType::Ptr KFileDialog::currentFilterMimeType() 00294 { 00295 return KMimeType::mimeType( currentMimeFilter() ); 00296 } 00297 00298 void KFileDialog::setPreviewWidget(const TQWidget *w) { 00299 ops->setPreviewWidget(w); 00300 ops->clearHistory(); 00301 d->hasView = true; 00302 } 00303 00304 void KFileDialog::setPreviewWidget(const KPreviewWidgetBase *w) { 00305 ops->setPreviewWidget(w); 00306 ops->clearHistory(); 00307 d->hasView = true; 00308 } 00309 00310 KURL KFileDialog::getCompleteURL(const TQString &_url) 00311 { 00312 TQString url = KShell::tildeExpand(_url); 00313 KURL u; 00314 00315 if ( KURL::isRelativeURL(url) ) // only a full URL isn't relative. Even /path is. 00316 { 00317 if (!url.isEmpty() && !TQDir::isRelativePath(url) ) // absolute path 00318 u.setPath( url ); 00319 else 00320 { 00321 u = ops->url(); 00322 u.addPath( url ); // works for filenames and relative paths 00323 u.cleanPath(); // fix "dir/.." 00324 } 00325 } 00326 else // complete URL 00327 u = url; 00328 00329 return u; 00330 } 00331 00332 // FIXME: check for "existing" flag here? 00333 void KFileDialog::slotOk() 00334 { 00335 kdDebug(tdefile_area) << "slotOK\n"; 00336 00337 if (locationEdit->lineEdit()->edited()) 00338 { 00339 enterURL(d->pathCombo->lineEdit()->text()); 00340 } 00341 // a list of all selected files/directories (if any) 00342 // can only be used if the user didn't type any filenames/urls himself 00343 const KFileItemList *items = ops->selectedItems(); 00344 00345 if ( (mode() & KFile::Directory) != KFile::Directory ) { 00346 if ( locationEdit->currentText().stripWhiteSpace().isEmpty() ) { 00347 if ( !items || items->isEmpty() ) 00348 { 00349 TQString msg; 00350 if ( d->operationMode == Saving ) 00351 msg = i18n("Please specify the filename to save to."); 00352 else 00353 msg = i18n("Please select the file to open."); 00354 KMessageBox::information(this, msg); 00355 return; 00356 } 00357 00358 // weird case: the location edit is empty, but there are 00359 // highlighted files 00360 else { 00361 00362 bool multi = (mode() & KFile::Files) != 0; 00363 KFileItemListIterator it( *items ); 00364 TQString endQuote = TQString::fromLatin1("\" "); 00365 TQString name, files; 00366 while ( it.current() ) { 00367 name = (*it)->name(); 00368 if ( multi ) { 00369 name.prepend( '"' ); 00370 name.append( endQuote ); 00371 } 00372 00373 files.append( name ); 00374 ++it; 00375 } 00376 setLocationText( files ); 00377 return; 00378 } 00379 } 00380 } 00381 00382 bool dirOnly = ops->dirOnlyMode(); 00383 00384 // we can use our tdefileitems, no need to parse anything 00385 if ( items && !locationEdit->lineEdit()->edited() && 00386 !(items->isEmpty() && !dirOnly) ) { 00387 00388 d->urlList.clear(); 00389 d->filenames = TQString::null; 00390 00391 if ( dirOnly ) { 00392 d->url = ops->url(); 00393 } 00394 else { 00395 if ( !(mode() & KFile::Files) ) {// single selection 00396 d->url = items->getFirst()->url(); 00397 } 00398 00399 else { // multi (dirs and/or files) 00400 d->url = ops->url(); 00401 KFileItemListIterator it( *items ); 00402 while ( it.current() ) { 00403 d->urlList.append( (*it)->url() ); 00404 ++it; 00405 } 00406 } 00407 } 00408 00409 KURL url = TDEIO::NetAccess::mostLocalURL(d->url,topLevelWidget()); 00410 if ( (mode() & KFile::LocalOnly) == KFile::LocalOnly && 00411 !url.isLocalFile() ) { 00412 // ### after message freeze, add message for directories! 00413 KMessageBox::sorry( d->mainWidget, 00414 i18n("You can only select local files."), 00415 i18n("Remote Files Not Accepted") ); 00416 return; 00417 } 00418 00419 d->url = url; 00420 accept(); 00421 return; 00422 } 00423 00424 00425 KURL selectedURL; 00426 00427 if ( (mode() & KFile::Files) == KFile::Files ) {// multiselection mode 00428 TQString locationText = locationEdit->currentText(); 00429 if ( locationText.contains( '/' )) { 00430 // relative path? -> prepend the current directory 00431 KURL u( ops->url(), KShell::tildeExpand(locationText)); 00432 if ( u.isValid() ) 00433 selectedURL = u; 00434 else 00435 selectedURL = ops->url(); 00436 } 00437 else // simple filename -> just use the current URL 00438 selectedURL = ops->url(); 00439 } 00440 00441 else { 00442 selectedURL = getCompleteURL(locationEdit->currentText()); 00443 00444 // appendExtension() may change selectedURL 00445 appendExtension (selectedURL); 00446 } 00447 00448 if ( !selectedURL.isValid() ) { 00449 KMessageBox::sorry( d->mainWidget, i18n("%1\ndoes not appear to be a valid URL.\n").arg(d->url.url()), i18n("Invalid URL") ); 00450 return; 00451 } 00452 00453 KURL url = TDEIO::NetAccess::mostLocalURL(selectedURL,topLevelWidget()); 00454 if ( (mode() & KFile::LocalOnly) == KFile::LocalOnly && 00455 !url.isLocalFile() ) { 00456 KMessageBox::sorry( d->mainWidget, 00457 i18n("You can only select local files."), 00458 i18n("Remote Files Not Accepted") ); 00459 return; 00460 } 00461 00462 d->url = url; 00463 00464 // d->url is a correct URL now 00465 00466 if ( (mode() & KFile::Directory) == KFile::Directory ) { 00467 kdDebug(tdefile_area) << "Directory" << endl; 00468 bool done = true; 00469 if ( d->url.isLocalFile() ) { 00470 if ( locationEdit->currentText().stripWhiteSpace().isEmpty() ) { 00471 TQFileInfo info( d->url.path() ); 00472 if ( info.isDir() ) { 00473 d->filenames = TQString::null; 00474 d->urlList.clear(); 00475 d->urlList.append( d->url ); 00476 accept(); 00477 } 00478 else if (!info.exists() && (mode() & KFile::File) != KFile::File) { 00479 // directory doesn't exist, create and enter it 00480 if ( ops->mkdir( d->url.url(), true )) 00481 return; 00482 else 00483 accept(); 00484 } 00485 else { // d->url is not a directory, 00486 // maybe we are in File(s) | Directory mode 00487 if ( (mode() & KFile::File) == KFile::File || 00488 (mode() & KFile::Files) == KFile::Files ) 00489 done = false; 00490 } 00491 } 00492 else // Directory mode, with file[s]/dir[s] selected 00493 { 00494 if ( mode() & KFile::ExistingOnly ) 00495 { 00496 if ( ops->dirOnlyMode() ) 00497 { 00498 KURL fullURL(d->url, locationEdit->currentText()); 00499 if ( TQFile::exists( fullURL.path() ) ) 00500 { 00501 d->url = fullURL; 00502 d->filenames = TQString::null; 00503 d->urlList.clear(); 00504 accept(); 00505 return; 00506 } 00507 else // doesn't exist -> reject 00508 return; 00509 } 00510 } 00511 00512 d->filenames = locationEdit->currentText(); 00513 accept(); // what can we do? 00514 } 00515 00516 } 00517 else { // FIXME: remote directory, should we allow that? 00518 // tqDebug( "**** Selected remote directory: %s", d->url.url().latin1()); 00519 d->filenames = TQString::null; 00520 d->urlList.clear(); 00521 d->urlList.append( d->url ); 00522 00523 if ( mode() & KFile::ExistingOnly ) 00524 done = false; 00525 else 00526 accept(); 00527 } 00528 00529 if ( done ) 00530 return; 00531 } 00532 00533 if (!kapp->authorizeURLAction("open", KURL(), d->url)) 00534 { 00535 TQString msg = TDEIO::buildErrorString(TDEIO::ERR_ACCESS_DENIED, d->url.prettyURL()); 00536 KMessageBox::error( d->mainWidget, msg); 00537 return; 00538 } 00539 00540 TDEIO::StatJob *job = 0L; 00541 d->statJobs.clear(); 00542 d->filenames = KShell::tildeExpand(locationEdit->currentText()); 00543 00544 if ( (mode() & KFile::Files) == KFile::Files && 00545 !locationEdit->currentText().contains( '/' )) { 00546 kdDebug(tdefile_area) << "Files\n"; 00547 KURL::List list = parseSelectedURLs(); 00548 for ( KURL::List::ConstIterator it = list.begin(); 00549 it != list.end(); ++it ) 00550 { 00551 if (!kapp->authorizeURLAction("open", KURL(), *it)) 00552 { 00553 TQString msg = TDEIO::buildErrorString(TDEIO::ERR_ACCESS_DENIED, (*it).prettyURL()); 00554 KMessageBox::error( d->mainWidget, msg); 00555 return; 00556 } 00557 } 00558 for ( KURL::List::ConstIterator it = list.begin(); 00559 it != list.end(); ++it ) 00560 { 00561 job = TDEIO::stat( *it, !(*it).isLocalFile() ); 00562 job->setWindow (topLevelWidget()); 00563 TDEIO::Scheduler::scheduleJob( job ); 00564 d->statJobs.append( job ); 00565 connect( job, TQT_SIGNAL( result(TDEIO::Job *) ), 00566 TQT_SLOT( slotStatResult( TDEIO::Job *) )); 00567 } 00568 return; 00569 } 00570 00571 job = TDEIO::stat(d->url,!d->url.isLocalFile()); 00572 job->setWindow (topLevelWidget()); 00573 d->statJobs.append( job ); 00574 connect(job, TQT_SIGNAL(result(TDEIO::Job*)), TQT_SLOT(slotStatResult(TDEIO::Job*))); 00575 } 00576 00577 00578 static bool isDirectory (const TDEIO::UDSEntry &t) 00579 { 00580 bool isDir = false; 00581 00582 for (TDEIO::UDSEntry::ConstIterator it = t.begin(); 00583 it != t.end(); 00584 it++) 00585 { 00586 if ((*it).m_uds == TDEIO::UDS_FILE_TYPE) 00587 { 00588 isDir = S_ISDIR ((mode_t) ((*it).m_long)); 00589 break; 00590 } 00591 } 00592 00593 return isDir; 00594 } 00595 00596 // FIXME : count all errors and show messagebox when d->statJobs.count() == 0 00597 // in case of an error, we cancel the whole operation (clear d->statJobs and 00598 // don't call accept) 00599 void KFileDialog::slotStatResult(TDEIO::Job* job) 00600 { 00601 kdDebug(tdefile_area) << "slotStatResult" << endl; 00602 TDEIO::StatJob *sJob = static_cast<TDEIO::StatJob *>( job ); 00603 00604 if ( !d->statJobs.removeRef( sJob ) ) { 00605 return; 00606 } 00607 00608 int count = d->statJobs.count(); 00609 00610 // errors mean in general, the location is no directory ;/ 00611 // Can we be sure that it is exististant at all? (pfeiffer) 00612 if (sJob->error() && count == 0 && !ops->dirOnlyMode()) 00613 { 00614 accept(); 00615 return; 00616 } 00617 00618 TDEIO::UDSEntry t = sJob->statResult(); 00619 if (isDirectory (t)) 00620 { 00621 if ( ops->dirOnlyMode() ) 00622 { 00623 d->filenames = TQString::null; 00624 d->urlList.clear(); 00625 accept(); 00626 } 00627 else // in File[s] mode, directory means error -> cd into it 00628 { 00629 if ( count == 0 ) { 00630 locationEdit->clearEdit(); 00631 locationEdit->lineEdit()->setEdited( false ); 00632 setURL( sJob->url() ); 00633 } 00634 } 00635 d->statJobs.clear(); 00636 return; 00637 } 00638 else if ( ops->dirOnlyMode() ) 00639 { 00640 return; // ### error message? 00641 } 00642 00643 kdDebug(tdefile_area) << "filename " << sJob->url().url() << endl; 00644 00645 if ( count == 0 ) 00646 accept(); 00647 } 00648 00649 void KFileDialog::accept() 00650 { 00651 setResult( TQDialog::Accepted ); // parseSelectedURLs() checks that 00652 00653 *lastDirectory = ops->url(); 00654 if (!d->fileClass.isEmpty()) 00655 TDERecentDirs::add(d->fileClass, ops->url().url()); 00656 00657 // clear the topmost item, we insert it as full path later on as item 1 00658 locationEdit->changeItem( TQString::null, 0 ); 00659 00660 KURL::List list = selectedURLs(); 00661 TQValueListConstIterator<KURL> it = list.begin(); 00662 for ( ; it != list.end(); ++it ) { 00663 const KURL& url = *it; 00664 // we strip the last slash (-1) because KURLComboBox does that as well 00665 // when operating in file-mode. If we wouldn't , dupe-finding wouldn't 00666 // work. 00667 TQString file = url.isLocalFile() ? url.path(-1) : url.prettyURL(-1); 00668 00669 // remove dupes 00670 for ( int i = 1; i < locationEdit->count(); i++ ) { 00671 if ( locationEdit->text( i ) == file ) { 00672 locationEdit->removeItem( i-- ); 00673 break; 00674 } 00675 } 00676 locationEdit->insertItem( file, 1 ); 00677 } 00678 00679 TDEConfig *config = TDEGlobal::config(); 00680 config->setForceGlobal( true ); 00681 writeConfig( config, ConfigGroup ); 00682 config->setForceGlobal( false ); 00683 00684 saveRecentFiles( config ); 00685 config->sync(); 00686 00687 KDialogBase::accept(); 00688 00689 addToRecentDocuments(); 00690 00691 if ( (mode() & KFile::Files) != KFile::Files ) // single selection 00692 emit fileSelected(d->url.url()); 00693 00694 ops->close(); 00695 emit okClicked(); 00696 } 00697 00698 00699 void KFileDialog::fileHighlighted(const KFileItem *i) 00700 { 00701 if (i && i->isDir()) 00702 return; 00703 00704 00705 if ( (ops->mode() & KFile::Files) != KFile::Files ) { 00706 if ( !i ) 00707 return; 00708 00709 d->url = i->url(); 00710 00711 if ( !locationEdit->hasFocus() ) { // don't disturb while editing 00712 setLocationText( i->name() ); 00713 } 00714 emit fileHighlighted(d->url.url()); 00715 } 00716 00717 else { 00718 multiSelectionChanged(); 00719 emit selectionChanged(); 00720 } 00721 } 00722 00723 void KFileDialog::fileSelected(const KFileItem *i) 00724 { 00725 if (i && i->isDir()) 00726 return; 00727 00728 if ( (ops->mode() & KFile::Files) != KFile::Files ) { 00729 if ( !i ) 00730 return; 00731 00732 d->url = i->url(); 00733 setLocationText( i->name() ); 00734 } 00735 else { 00736 multiSelectionChanged(); 00737 emit selectionChanged(); 00738 } 00739 slotOk(); 00740 } 00741 00742 00743 // I know it's slow to always iterate thru the whole filelist 00744 // (ops->selectedItems()), but what can we do? 00745 void KFileDialog::multiSelectionChanged() 00746 { 00747 if ( locationEdit->hasFocus() ) // don't disturb 00748 return; 00749 00750 locationEdit->lineEdit()->setEdited( false ); 00751 KFileItem *item; 00752 const KFileItemList *list = ops->selectedItems(); 00753 if ( !list ) { 00754 locationEdit->clearEdit(); 00755 return; 00756 } 00757 00758 static const TQString &begin = TDEGlobal::staticQString(" \""); 00759 KFileItemListIterator it ( *list ); 00760 TQString text; 00761 while ( (item = it.current()) ) { 00762 text.append( begin ).append( item->name() ).append( '\"' ); 00763 ++it; 00764 } 00765 00766 setLocationText( text.stripWhiteSpace() ); 00767 } 00768 00769 void KFileDialog::setLocationText( const TQString& text ) 00770 { 00771 // setCurrentItem() will cause textChanged() being emitted, 00772 // so slotLocationChanged() will be called. Make sure we don't clear 00773 // the KDirOperator's view-selection in there 00774 disconnect( locationEdit, TQT_SIGNAL( textChanged( const TQString& ) ), 00775 this, TQT_SLOT( slotLocationChanged( const TQString& ) ) ); 00776 locationEdit->setCurrentItem( 0 ); 00777 connect( locationEdit, TQT_SIGNAL( textChanged( const TQString& ) ), 00778 TQT_SLOT( slotLocationChanged( const TQString& )) ); 00779 locationEdit->setEditText( text ); 00780 00781 // don't change selection when user has clicked on an item 00782 if ( d->operationMode == Saving && !locationEdit->isVisible()) 00783 setNonExtSelection(); 00784 } 00785 00786 static const char autocompletionWhatsThisText[] = I18N_NOOP("<p>While typing in the text area, you may be presented " 00787 "with possible matches. " 00788 "This feature can be controlled by clicking with the right mouse button " 00789 "and selecting a preferred mode from the <b>Text Completion</b> menu.") "</qt>"; 00790 void KFileDialog::updateLocationWhatsThis (void) 00791 { 00792 TQString whatsThisText; 00793 if (d->operationMode == KFileDialog::Saving) 00794 { 00795 whatsThisText = "<qt>" + i18n("This is the name to save the file as.") + 00796 i18n (autocompletionWhatsThisText); 00797 } 00798 else if (ops->mode() & KFile::Files) 00799 { 00800 whatsThisText = "<qt>" + i18n("This is the list of files to open. More than " 00801 "one file can be specified by listing several " 00802 "files, separated by spaces.") + 00803 i18n (autocompletionWhatsThisText); 00804 } 00805 else 00806 { 00807 whatsThisText = "<qt>" + i18n("This is the name of the file to open.") + 00808 i18n (autocompletionWhatsThisText); 00809 } 00810 00811 TQWhatsThis::add(d->locationLabel, whatsThisText); 00812 TQWhatsThis::add(locationEdit, whatsThisText); 00813 } 00814 00815 void KFileDialog::init(const TQString& startDir, const TQString& filter, TQWidget* widget) 00816 { 00817 initStatic(); 00818 d = new KFileDialogPrivate(); 00819 00820 d->boxLayout = 0; 00821 d->keepLocation = false; 00822 d->operationMode = Opening; 00823 d->bookmarkHandler = 0; 00824 d->hasDefaultFilter = false; 00825 d->hasView = false; 00826 d->mainWidget = new TQWidget( this, "KFileDialog::mainWidget"); 00827 setMainWidget( d->mainWidget ); 00828 d->okButton = new KPushButton( KStdGuiItem::ok(), d->mainWidget ); 00829 d->okButton->setDefault( true ); 00830 d->cancelButton = new KPushButton(KStdGuiItem::cancel(), d->mainWidget); 00831 connect( d->okButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotOk() )); 00832 connect( d->cancelButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotCancel() )); 00833 d->customWidget = widget; 00834 d->autoSelectExtCheckBox = 0; // delayed loading 00835 d->autoSelectExtChecked = false; 00836 d->urlBar = 0; // delayed loading 00837 00838 TQtMsgHandler oldHandler = tqInstallMsgHandler( silenceQToolBar ); 00839 toolbar = new TDEToolBar( d->mainWidget, "KFileDialog::toolbar", true); 00840 toolbar->setFlat(true); 00841 tqInstallMsgHandler( oldHandler ); 00842 00843 d->pathCombo = new KURLComboBox( KURLComboBox::Directories, true, 00844 toolbar, "path combo" ); 00845 TQToolTip::add( d->pathCombo, i18n("Current location") ); 00846 TQWhatsThis::add( d->pathCombo, "<qt>" + i18n("This is the currently listed location. " 00847 "The drop-down list also lists commonly used locations. " 00848 "This includes standard locations, such as your home folder, as well as " 00849 "locations that have been visited recently.") + i18n (autocompletionWhatsThisText)); 00850 00851 KURL u; 00852 u.setPath( TQDir::rootDirPath() ); 00853 TQString text = i18n("Root Folder: %1").arg( u.path() ); 00854 d->pathCombo->addDefaultURL( u, 00855 KMimeType::pixmapForURL( u, 0, TDEIcon::Small ), 00856 text ); 00857 00858 u.setPath( TQDir::homeDirPath() ); 00859 text = i18n("Home Folder: %1").arg( u.path( +1 ) ); 00860 d->pathCombo->addDefaultURL( u, KMimeType::pixmapForURL( u, 0, TDEIcon::Small ), 00861 text ); 00862 00863 KURL docPath; 00864 docPath.setPath( TDEGlobalSettings::documentPath() ); 00865 if ( (u.path(+1) != docPath.path(+1)) && 00866 TQDir(docPath.path(+1)).exists() ) 00867 { 00868 text = i18n("Documents: %1").arg( docPath.path( +1 ) ); 00869 d->pathCombo->addDefaultURL( docPath, 00870 KMimeType::pixmapForURL( docPath, 0, TDEIcon::Small ), 00871 text ); 00872 } 00873 00874 u.setPath( TDEGlobalSettings::desktopPath() ); 00875 text = i18n("Desktop: %1").arg( u.path( +1 ) ); 00876 d->pathCombo->addDefaultURL( u, 00877 KMimeType::pixmapForURL( u, 0, TDEIcon::Small ), 00878 text ); 00879 00880 d->url = getStartURL( startDir, d->fileClass ); 00881 d->selection = d->url.url(); 00882 00883 // If local, check it exists. If not, go up until it exists. 00884 if ( d->url.isLocalFile() ) 00885 { 00886 if ( !TQFile::exists( d->url.path() ) ) 00887 { 00888 d->url = d->url.upURL(); 00889 TQDir dir( d->url.path() ); 00890 while ( !dir.exists() ) 00891 { 00892 d->url = d->url.upURL(); 00893 dir.setPath( d->url.path() ); 00894 } 00895 } 00896 } 00897 00898 ops = new KDirOperator(d->url, d->mainWidget, "KFileDialog::ops"); 00899 ops->setOnlyDoubleClickSelectsFiles( true ); 00900 connect(ops, TQT_SIGNAL(urlEntered(const KURL&)), 00901 TQT_SLOT(urlEntered(const KURL&))); 00902 connect(ops, TQT_SIGNAL(fileHighlighted(const KFileItem *)), 00903 TQT_SLOT(fileHighlighted(const KFileItem *))); 00904 connect(ops, TQT_SIGNAL(fileSelected(const KFileItem *)), 00905 TQT_SLOT(fileSelected(const KFileItem *))); 00906 connect(ops, TQT_SIGNAL(finishedLoading()), 00907 TQT_SLOT(slotLoadingFinished())); 00908 00909 ops->setupMenu(KDirOperator::SortActions | 00910 KDirOperator::FileActions | 00911 KDirOperator::ViewActions); 00912 TDEActionCollection *coll = ops->actionCollection(); 00913 00914 // plug nav items into the toolbar 00915 coll->action( "up" )->plug( toolbar ); 00916 coll->action( "up" )->setWhatsThis(i18n("<qt>Click this button to enter the parent folder.<p>" 00917 "For instance, if the current location is file:/home/%1 clicking this " 00918 "button will take you to file:/home.</qt>").arg( KUser().loginName() )); 00919 coll->action( "back" )->plug( toolbar ); 00920 coll->action( "back" )->setWhatsThis(i18n("Click this button to move backwards one step in the browsing history.")); 00921 coll->action( "forward" )->plug( toolbar ); 00922 coll->action( "forward" )->setWhatsThis(i18n("Click this button to move forward one step in the browsing history.")); 00923 coll->action( "reload" )->plug( toolbar ); 00924 coll->action( "reload" )->setWhatsThis(i18n("Click this button to reload the contents of the current location.")); 00925 coll->action( "mkdir" )->setShortcut(Key_F10); 00926 coll->action( "mkdir" )->plug( toolbar ); 00927 coll->action( "mkdir" )->setWhatsThis(i18n("Click this button to create a new folder.")); 00928 00929 TDEToggleAction *showSidebarAction = 00930 new TDEToggleAction(i18n("Show Quick Access Navigation Panel"), Key_F9, coll,"toggleSpeedbar"); 00931 showSidebarAction->setCheckedState(i18n("Hide Quick Access Navigation Panel")); 00932 connect( showSidebarAction, TQT_SIGNAL( toggled( bool ) ), 00933 TQT_SLOT( toggleSpeedbar( bool )) ); 00934 00935 TDEToggleAction *showBookmarksAction = 00936 new TDEToggleAction(i18n("Show Bookmarks"), 0, coll, "toggleBookmarks"); 00937 showBookmarksAction->setCheckedState(i18n("Hide Bookmarks")); 00938 connect( showBookmarksAction, TQT_SIGNAL( toggled( bool ) ), 00939 TQT_SLOT( toggleBookmarks( bool )) ); 00940 00941 TDEActionMenu *menu = new TDEActionMenu( i18n("Configure"), "configure", TQT_TQOBJECT(this), "extra menu" ); 00942 menu->setWhatsThis(i18n("<qt>This is the configuration menu for the file dialog. " 00943 "Various options can be accessed from this menu including: <ul>" 00944 "<li>how files are sorted in the list</li>" 00945 "<li>types of view, including icon and list</li>" 00946 "<li>showing of hidden files</li>" 00947 "<li>the Quick Access navigation panel</li>" 00948 "<li>file previews</li>" 00949 "<li>separating folders from files</li></ul></qt>")); 00950 menu->insert( coll->action( "sorting menu" )); 00951 menu->insert( coll->action( "separator" )); 00952 coll->action( "short view" )->setShortcut(Key_F6); 00953 menu->insert( coll->action( "short view" )); 00954 coll->action( "detailed view" )->setShortcut(Key_F7); 00955 menu->insert( coll->action( "detailed view" )); 00956 menu->insert( coll->action( "separator" )); 00957 coll->action( "show hidden" )->setShortcut(Key_F8); 00958 menu->insert( coll->action( "show hidden" )); 00959 menu->insert( showSidebarAction ); 00960 menu->insert( showBookmarksAction ); 00961 coll->action( "preview" )->setShortcut(Key_F11); 00962 menu->insert( coll->action( "preview" )); 00963 coll->action( "separate dirs" )->setShortcut(Key_F12); 00964 menu->insert( coll->action( "separate dirs" )); 00965 00966 menu->setDelayed( false ); 00967 connect( menu->popupMenu(), TQT_SIGNAL( aboutToShow() ), 00968 ops, TQT_SLOT( updateSelectionDependentActions() )); 00969 menu->plug( toolbar ); 00970 00971 //Insert a separator. 00972 TDEToolBarSeparator* spacerWidget = new TDEToolBarSeparator(Qt::Horizontal, false /*no line*/, 00973 toolbar); 00974 d->m_pathComboIndex = toolbar->insertWidget(-1, -1, spacerWidget); 00975 toolbar->insertWidget(PATH_COMBO, 0, d->pathCombo); 00976 00977 00978 toolbar->setItemAutoSized (PATH_COMBO); 00979 toolbar->setIconText(TDEToolBar::IconOnly); 00980 toolbar->setBarPos(TDEToolBar::Top); 00981 toolbar->setMovingEnabled(false); 00982 toolbar->adjustSize(); 00983 00984 KURLCompletion *pathCompletionObj = new KURLCompletion( KURLCompletion::DirCompletion ); 00985 d->pathCombo->setCompletionObject( pathCompletionObj ); 00986 d->pathCombo->setAutoDeleteCompletionObject( true ); 00987 00988 connect( d->pathCombo, TQT_SIGNAL( urlActivated( const KURL& )), 00989 this, TQT_SLOT( enterURL( const KURL& ) )); 00990 connect( d->pathCombo, TQT_SIGNAL( returnPressed( const TQString& )), 00991 this, TQT_SLOT( enterURL( const TQString& ) )); 00992 connect( d->pathCombo, TQT_SIGNAL( activated( const TQString& )), 00993 this, TQT_SLOT( enterURL( const TQString& ) )); 00994 00995 TQString whatsThisText; 00996 00997 // the Location label/edit 00998 d->locationLabel = new TQLabel(i18n("&Location:"), d->mainWidget); 00999 locationEdit = new KURLComboBox(KURLComboBox::Files, true, 01000 d->mainWidget, "LocationEdit"); 01001 locationEdit->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Fixed)); 01002 connect( locationEdit, TQT_SIGNAL( textChanged( const TQString& ) ), 01003 TQT_SLOT( slotLocationChanged( const TQString& )) ); 01004 01005 updateLocationWhatsThis (); 01006 d->locationLabel->setBuddy(locationEdit); 01007 01008 locationEdit->setFocus(); 01009 KURLCompletion *fileCompletionObj = new KURLCompletion( KURLCompletion::FileCompletion ); 01010 TQString dir = d->url.url(+1); 01011 pathCompletionObj->setDir( dir ); 01012 fileCompletionObj->setDir( dir ); 01013 locationEdit->setCompletionObject( fileCompletionObj ); 01014 locationEdit->setAutoDeleteCompletionObject( true ); 01015 connect( fileCompletionObj, TQT_SIGNAL( match( const TQString& ) ), 01016 TQT_SLOT( fileCompletion( const TQString& )) ); 01017 01018 connect( locationEdit, TQT_SIGNAL( returnPressed() ), 01019 this, TQT_SLOT( slotOk())); 01020 connect(locationEdit, TQT_SIGNAL( activated( const TQString& )), 01021 this, TQT_SLOT( locationActivated( const TQString& ) )); 01022 01023 // the Filter label/edit 01024 whatsThisText = i18n("<qt>This is the filter to apply to the file list. " 01025 "File names that do not match the filter will not be shown.<p>" 01026 "You may select from one of the preset filters in the " 01027 "drop down menu, or you may enter a custom filter " 01028 "directly into the text area.<p>" 01029 "Wildcards such as * and ? are allowed.</qt>"); 01030 d->filterLabel = new TQLabel(i18n("&Filter:"), d->mainWidget); 01031 TQWhatsThis::add(d->filterLabel, whatsThisText); 01032 filterWidget = new KFileFilterCombo(d->mainWidget, 01033 "KFileDialog::filterwidget"); 01034 filterWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Fixed)); 01035 TQWhatsThis::add(filterWidget, whatsThisText); 01036 setFilter(filter); 01037 d->filterLabel->setBuddy(filterWidget); 01038 connect(filterWidget, TQT_SIGNAL(filterChanged()), TQT_SLOT(slotFilterChanged())); 01039 01040 // the Automatically Select Extension checkbox 01041 // (the text, visibility etc. is set in updateAutoSelectExtension(), which is called by readConfig()) 01042 d->autoSelectExtCheckBox = new TQCheckBox (d->mainWidget); 01043 connect(d->autoSelectExtCheckBox, TQT_SIGNAL(clicked()), TQT_SLOT(slotAutoSelectExtClicked())); 01044 01045 initGUI(); // activate GM 01046 01047 TDEConfig* config = TDEGlobal::config(); 01048 readRecentFiles( config ); 01049 01050 adjustSize(); 01051 01052 ops->setViewConfig( config, ConfigGroup ); 01053 readConfig( config, ConfigGroup ); 01054 setSelection(d->selection); 01055 } 01056 01057 void KFileDialog::initSpeedbar() 01058 { 01059 d->urlBar = new KFileSpeedBar( d->mainWidget, "url bar" ); 01060 connect( d->urlBar, TQT_SIGNAL( activated( const KURL& )), 01061 TQT_SLOT( enterURL( const KURL& )) ); 01062 01063 // need to set the current url of the urlbar manually (not via urlEntered() 01064 // here, because the initial url of KDirOperator might be the same as the 01065 // one that will be set later (and then urlEntered() won't be emitted). 01066 // ### REMOVE THIS when KDirOperator's initial URL (in the c'tor) is gone. 01067 d->urlBar->setCurrentItem( d->url ); 01068 01069 d->urlBarLayout->insertWidget( 0, d->urlBar ); 01070 } 01071 01072 void KFileDialog::initGUI() 01073 { 01074 delete d->boxLayout; // deletes all sub layouts 01075 01076 d->boxLayout = new TQVBoxLayout( d->mainWidget, 0, KDialog::spacingHint()); 01077 d->boxLayout->addWidget(toolbar, AlignTop); 01078 01079 d->urlBarLayout = new TQHBoxLayout( d->boxLayout ); // needed for the urlBar that may appear 01080 TQVBoxLayout *vbox = new TQVBoxLayout( d->urlBarLayout ); 01081 01082 vbox->addWidget(ops, 4); 01083 vbox->addSpacing(3); 01084 01085 TQGridLayout* lafBox= new TQGridLayout(2, 3, KDialog::spacingHint()); 01086 01087 lafBox->addWidget(d->locationLabel, 0, 0, Qt::AlignVCenter); 01088 lafBox->addWidget(locationEdit, 0, 1, Qt::AlignVCenter); 01089 lafBox->addWidget(d->okButton, 0, 2, Qt::AlignVCenter); 01090 01091 lafBox->addWidget(d->filterLabel, 1, 0, Qt::AlignVCenter); 01092 lafBox->addWidget(filterWidget, 1, 1, Qt::AlignVCenter); 01093 lafBox->addWidget(d->cancelButton, 1, 2, Qt::AlignVCenter); 01094 01095 lafBox->setColStretch(1, 4); 01096 01097 vbox->addLayout(TQT_TQLAYOUT(lafBox), 0); 01098 vbox->addSpacing(3); 01099 01100 // add the Automatically Select Extension checkbox 01101 vbox->addWidget (d->autoSelectExtCheckBox); 01102 vbox->addSpacing (3); 01103 01104 setTabOrder(ops, d->autoSelectExtCheckBox); 01105 setTabOrder (d->autoSelectExtCheckBox, locationEdit); 01106 setTabOrder(locationEdit, filterWidget); 01107 setTabOrder(filterWidget, d->okButton); 01108 setTabOrder(d->okButton, d->cancelButton); 01109 setTabOrder(d->cancelButton, d->pathCombo); 01110 setTabOrder(d->pathCombo, ops); 01111 01112 // If a custom widget was specified... 01113 if ( d->customWidget != 0 ) 01114 { 01115 // ...add it to the dialog, below the filter list box. 01116 01117 // Change the parent so that this widget is a child of the main widget 01118 d->customWidget->reparent( d->mainWidget, TQPoint() ); 01119 01120 vbox->addWidget( d->customWidget ); 01121 vbox->addSpacing(3); 01122 01123 // FIXME: This should adjust the tab orders so that the custom widget 01124 // comes after the Cancel button. The code appears to do this, but the result 01125 // somehow screws up the tab order of the file path combo box. Not a major 01126 // problem, but ideally the tab order with a custom widget should be 01127 // the same as the order without one. 01128 setTabOrder(d->cancelButton, d->customWidget); 01129 setTabOrder(d->customWidget, d->pathCombo); 01130 } 01131 else 01132 { 01133 setTabOrder(d->cancelButton, d->pathCombo); 01134 } 01135 01136 setTabOrder(d->pathCombo, ops); 01137 } 01138 01139 void KFileDialog::slotFilterChanged() 01140 { 01141 TQString filter = filterWidget->currentFilter(); 01142 ops->clearFilter(); 01143 01144 if ( filter.find( '/' ) > -1 ) { 01145 TQStringList types = TQStringList::split( " ", filter ); 01146 types.prepend( "inode/directory" ); 01147 ops->setMimeFilter( types ); 01148 } 01149 else 01150 ops->setNameFilter( filter ); 01151 01152 ops->updateDir(); 01153 01154 updateAutoSelectExtension (); 01155 01156 emit filterChanged( filter ); 01157 } 01158 01159 01160 void KFileDialog::setURL(const KURL& url, bool clearforward) 01161 { 01162 d->selection = TQString::null; 01163 ops->setURL( url, clearforward); 01164 } 01165 01166 // Protected 01167 void KFileDialog::urlEntered(const KURL& url) 01168 { 01169 TQString filename = locationEdit->currentText(); 01170 d->selection = TQString::null; 01171 01172 if ( d->pathCombo->count() != 0 ) { // little hack 01173 d->pathCombo->setURL( url ); 01174 } 01175 01176 if (url.protocol()=="beagle" && url.path()=="/") { 01177 d->pathCombo->setEditText("beagle:/<"+i18n("search term")+">"); 01178 d->pathCombo->lineEdit()->setSelection(8,255); 01179 d->pathCombo->setFocus(); 01180 } 01181 01182 locationEdit->blockSignals( true ); 01183 locationEdit->setCurrentItem( 0 ); 01184 if ( d->keepLocation ) 01185 locationEdit->setEditText( filename ); 01186 01187 locationEdit->blockSignals( false ); 01188 01189 TQString dir = url.url(+1); 01190 static_cast<KURLCompletion*>( d->pathCombo->completionObject() )->setDir( dir ); 01191 static_cast<KURLCompletion*>( locationEdit->completionObject() )->setDir( dir ); 01192 01193 if ( d->urlBar ) 01194 d->urlBar->setCurrentItem( url ); 01195 } 01196 01197 void KFileDialog::locationActivated( const TQString& url ) 01198 { 01199 // This guard prevents any URL _typed_ by the user from being interpreted 01200 // twice (by returnPressed/slotOk and here, activated/locationActivated) 01201 // after the user presses Enter. Without this, _both_ setSelection and 01202 // slotOk would "u.addPath( url )" ...so instead we leave it up to just 01203 // slotOk.... 01204 if (!locationEdit->lineEdit()->edited()) 01205 setSelection( url ); 01206 } 01207 01208 void KFileDialog::enterURL( const KURL& url) 01209 { 01210 setURL( url ); 01211 } 01212 01213 void KFileDialog::enterURL( const TQString& url ) 01214 { 01215 setURL( KURL::fromPathOrURL( KURLCompletion::replacedPath( url, true, true )) ); 01216 } 01217 01218 void KFileDialog::toolbarCallback(int) // SLOT 01219 { 01220 /* 01221 * yes, nothing uses this anymore. 01222 * it used to be used to show the configure dialog 01223 */ 01224 } 01225 01226 01227 void KFileDialog::setSelection(const TQString& url) 01228 { 01229 kdDebug(tdefile_area) << "setSelection " << url << endl; 01230 01231 if (url.isEmpty()) { 01232 d->selection = TQString::null; 01233 return; 01234 } 01235 01236 KURL u = getCompleteURL(url); 01237 if (!u.isValid()) { // if it still is 01238 kdWarning() << url << " is not a correct argument for setSelection!" << endl; 01239 return; 01240 } 01241 01242 if (!KProtocolInfo::supportsListing(u)) { 01243 locationEdit->lineEdit()->setEdited( true ); 01244 return; 01245 } 01246 01247 /* we strip the first / from the path to avoid file://usr which means 01248 * / on host usr 01249 */ 01250 KFileItem i(KFileItem::Unknown, KFileItem::Unknown, u, true ); 01251 // KFileItem i(u.path()); 01252 if ( i.isDir() && u.isLocalFile() && TQFile::exists( u.path() ) ) { 01253 // trust isDir() only if the file is 01254 // local (we cannot stat non-local urls) and if it exists! 01255 // (as KFileItem does not check if the file exists or not 01256 // -> the statbuffer is undefined -> isDir() is unreliable) (Simon) 01257 setURL(u, true); 01258 } 01259 else { 01260 TQString filename = u.url(); 01261 int sep = filename.findRev('/'); 01262 if (sep >= 0) { // there is a / in it 01263 if ( KProtocolInfo::supportsListing( u )) { 01264 KURL dir(u); 01265 dir.setQuery( TQString::null ); 01266 dir.setFileName( TQString::null ); 01267 setURL(dir, true ); 01268 } 01269 01270 // filename must be decoded, or "name with space" would become 01271 // "name%20with%20space", so we use KURL::fileName() 01272 filename = u.fileName(); 01273 kdDebug(tdefile_area) << "filename " << filename << endl; 01274 d->selection = filename; 01275 setLocationText( filename ); 01276 01277 // tell the line edit that it has been edited 01278 // otherwise we won't know this was set by the user 01279 // and it will be ignored if there has been an 01280 // auto completion. this caused bugs where automcompletion 01281 // would start, the user would pick something from the 01282 // history and then hit Ok only to get the autocompleted 01283 // selection. OOOPS. 01284 locationEdit->lineEdit()->setEdited( true ); 01285 } 01286 01287 d->url = ops->url(); 01288 d->url.addPath(filename); 01289 } 01290 } 01291 01292 void KFileDialog::slotLoadingFinished() 01293 { 01294 if ( !d->selection.isNull() ) 01295 ops->setCurrentItem( d->selection ); 01296 } 01297 01298 // ### remove in KDE4 01299 void KFileDialog::pathComboChanged( const TQString& ) 01300 { 01301 } 01302 void KFileDialog::dirCompletion( const TQString& ) // SLOT 01303 { 01304 } 01305 void KFileDialog::fileCompletion( const TQString& match ) 01306 { 01307 if ( match.isEmpty() && ops->view() ) 01308 ops->view()->clearSelection(); 01309 else 01310 ops->setCurrentItem( match ); 01311 } 01312 01313 void KFileDialog::slotLocationChanged( const TQString& text ) 01314 { 01315 if ( text.isEmpty() && ops->view() ) 01316 ops->view()->clearSelection(); 01317 01318 updateFilter(); 01319 } 01320 01321 void KFileDialog::updateStatusLine(int /* dirs */, int /* files */) 01322 { 01323 kdWarning() << "KFileDialog::updateStatusLine is deprecated! The status line no longer exists. Do not try and use it!" << endl; 01324 } 01325 01326 TQString KFileDialog::getOpenFileName(const TQString& startDir, 01327 const TQString& filter, 01328 TQWidget *parent, const TQString& caption) 01329 { 01330 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01331 dlg.setOperationMode( Opening ); 01332 01333 dlg.setMode( KFile::File | KFile::LocalOnly ); 01334 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01335 01336 dlg.ops->clearHistory(); 01337 dlg.exec(); 01338 01339 return dlg.selectedFile(); 01340 } 01341 01342 TQString KFileDialog::getOpenFileNameWId(const TQString& startDir, 01343 const TQString& filter, 01344 WId parent_id, const TQString& caption) 01345 { 01346 TQWidget* parent = TQT_TQWIDGET(TQWidget::find( parent_id )); 01347 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01348 #ifdef Q_WS_X11 01349 if( parent == NULL && parent_id != 0 ) 01350 XSetTransientForHint( tqt_xdisplay(), dlg.winId(), parent_id ); 01351 #else 01352 // TODO 01353 #endif 01354 01355 dlg.setOperationMode( KFileDialog::Opening ); 01356 01357 dlg.setMode( KFile::File | KFile::LocalOnly ); 01358 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01359 01360 dlg.ops->clearHistory(); 01361 dlg.exec(); 01362 01363 return dlg.selectedFile(); 01364 } 01365 01366 TQStringList KFileDialog::getOpenFileNames(const TQString& startDir, 01367 const TQString& filter, 01368 TQWidget *parent, 01369 const TQString& caption) 01370 { 01371 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01372 dlg.setOperationMode( Opening ); 01373 01374 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01375 dlg.setMode(KFile::Files | KFile::LocalOnly); 01376 dlg.ops->clearHistory(); 01377 dlg.exec(); 01378 01379 return dlg.selectedFiles(); 01380 } 01381 01382 KURL KFileDialog::getOpenURL(const TQString& startDir, const TQString& filter, 01383 TQWidget *parent, const TQString& caption) 01384 { 01385 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01386 dlg.setOperationMode( Opening ); 01387 01388 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01389 dlg.setMode( KFile::File ); 01390 dlg.ops->clearHistory(); 01391 dlg.exec(); 01392 01393 return dlg.selectedURL(); 01394 } 01395 01396 KURL::List KFileDialog::getOpenURLs(const TQString& startDir, 01397 const TQString& filter, 01398 TQWidget *parent, 01399 const TQString& caption) 01400 { 01401 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01402 dlg.setOperationMode( Opening ); 01403 01404 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01405 dlg.setMode(KFile::Files); 01406 dlg.ops->clearHistory(); 01407 dlg.exec(); 01408 01409 return dlg.selectedURLs(); 01410 } 01411 01412 KURL KFileDialog::getExistingURL(const TQString& startDir, 01413 TQWidget *parent, 01414 const TQString& caption) 01415 { 01416 return KDirSelectDialog::selectDirectory(startDir, false, parent, caption); 01417 } 01418 01419 TQString KFileDialog::getExistingDirectory(const TQString& startDir, 01420 TQWidget *parent, 01421 const TQString& caption) 01422 { 01423 #ifdef Q_WS_WIN 01424 return TQFileDialog::getExistingDirectory(startDir, parent, "getExistingDirectory", 01425 caption, true, true); 01426 #else 01427 KURL url = KDirSelectDialog::selectDirectory(startDir, true, parent, 01428 caption); 01429 if ( url.isValid() ) 01430 return url.path(); 01431 01432 return TQString::null; 01433 #endif 01434 } 01435 01436 KURL KFileDialog::getImageOpenURL( const TQString& startDir, TQWidget *parent, 01437 const TQString& caption) 01438 { 01439 TQStringList mimetypes = KImageIO::mimeTypes( KImageIO::Reading ); 01440 KFileDialog dlg(startDir, 01441 mimetypes.join(" "), 01442 parent, "filedialog", true); 01443 dlg.setOperationMode( Opening ); 01444 dlg.setCaption( caption.isNull() ? i18n("Open") : caption ); 01445 dlg.setMode( KFile::File ); 01446 01447 KImageFilePreview *ip = new KImageFilePreview( &dlg ); 01448 dlg.setPreviewWidget( ip ); 01449 dlg.exec(); 01450 01451 return dlg.selectedURL(); 01452 } 01453 01454 KURL KFileDialog::selectedURL() const 01455 { 01456 if ( result() == TQDialog::Accepted ) 01457 return d->url; 01458 else 01459 return KURL(); 01460 } 01461 01462 KURL::List KFileDialog::selectedURLs() const 01463 { 01464 KURL::List list; 01465 if ( result() == TQDialog::Accepted ) { 01466 if ( (ops->mode() & KFile::Files) == KFile::Files ) 01467 list = parseSelectedURLs(); 01468 else 01469 list.append( d->url ); 01470 } 01471 return list; 01472 } 01473 01474 01475 KURL::List& KFileDialog::parseSelectedURLs() const 01476 { 01477 if ( d->filenames.isEmpty() ) { 01478 return d->urlList; 01479 } 01480 01481 d->urlList.clear(); 01482 if ( d->filenames.contains( '/' )) { // assume _one_ absolute filename 01483 static const TQString &prot = TDEGlobal::staticQString(":/"); 01484 KURL u; 01485 if ( d->filenames.find( prot ) != -1 ) 01486 u = d->filenames; 01487 else 01488 u.setPath( d->filenames ); 01489 01490 if ( u.isValid() ) 01491 d->urlList.append( u ); 01492 else 01493 KMessageBox::error( d->mainWidget, 01494 i18n("The chosen filenames do not\n" 01495 "appear to be valid."), 01496 i18n("Invalid Filenames") ); 01497 } 01498 01499 else 01500 d->urlList = tokenize( d->filenames ); 01501 01502 d->filenames = TQString::null; // indicate that we parsed that one 01503 01504 return d->urlList; 01505 } 01506 01507 01508 // FIXME: current implementation drawback: a filename can't contain quotes 01509 KURL::List KFileDialog::tokenize( const TQString& line ) const 01510 { 01511 KURL::List urls; 01512 KURL u( ops->url() ); 01513 TQString name; 01514 01515 int count = line.contains( '"' ); 01516 if ( count == 0 ) { // no " " -> assume one single file 01517 u.setFileName( line ); 01518 if ( u.isValid() ) 01519 urls.append( u ); 01520 01521 return urls; 01522 } 01523 01524 if ( (count % 2) == 1 ) { // odd number of " -> error 01525 TQWidget *that = const_cast<KFileDialog *>(this); 01526 KMessageBox::sorry(that, i18n("The requested filenames\n" 01527 "%1\n" 01528 "do not appear to be valid;\n" 01529 "make sure every filename is enclosed in double quotes.").arg(line), 01530 i18n("Filename Error")); 01531 return urls; 01532 } 01533 01534 int start = 0; 01535 int index1 = -1, index2 = -1; 01536 while ( true ) { 01537 index1 = line.find( '"', start ); 01538 index2 = line.find( '"', index1 + 1 ); 01539 01540 if ( index1 < 0 ) 01541 break; 01542 01543 // get everything between the " " 01544 name = line.mid( index1 + 1, index2 - index1 - 1 ); 01545 u.setFileName( name ); 01546 if ( u.isValid() ) 01547 urls.append( u ); 01548 01549 start = index2 + 1; 01550 } 01551 return urls; 01552 } 01553 01554 01555 TQString KFileDialog::selectedFile() const 01556 { 01557 if ( result() == TQDialog::Accepted ) 01558 { 01559 KURL url = TDEIO::NetAccess::mostLocalURL(d->url,topLevelWidget()); 01560 if (url.isLocalFile()) 01561 return url.path(); 01562 else { 01563 KMessageBox::sorry( d->mainWidget, 01564 i18n("You can only select local files."), 01565 i18n("Remote Files Not Accepted") ); 01566 } 01567 } 01568 return TQString::null; 01569 } 01570 01571 TQStringList KFileDialog::selectedFiles() const 01572 { 01573 TQStringList list; 01574 KURL url; 01575 01576 if ( result() == TQDialog::Accepted ) { 01577 if ( (ops->mode() & KFile::Files) == KFile::Files ) { 01578 KURL::List urls = parseSelectedURLs(); 01579 TQValueListConstIterator<KURL> it = urls.begin(); 01580 while ( it != urls.end() ) { 01581 url = TDEIO::NetAccess::mostLocalURL(*it,topLevelWidget()); 01582 if ( url.isLocalFile() ) 01583 list.append( url.path() ); 01584 ++it; 01585 } 01586 } 01587 01588 else { // single-selection mode 01589 if ( d->url.isLocalFile() ) 01590 list.append( d->url.path() ); 01591 } 01592 } 01593 01594 return list; 01595 } 01596 01597 KURL KFileDialog::baseURL() const 01598 { 01599 return ops->url(); 01600 } 01601 01602 TQString KFileDialog::getSaveFileName(const TQString& dir, const TQString& filter, 01603 TQWidget *parent, 01604 const TQString& caption) 01605 { 01606 bool specialDir = dir.at(0) == ':'; 01607 KFileDialog dlg( specialDir ? dir : TQString::null, filter, parent, "filedialog", true); 01608 if ( !specialDir ) 01609 dlg.setSelection( dir ); // may also be a filename 01610 01611 dlg.setOperationMode( Saving ); 01612 dlg.setCaption(caption.isNull() ? i18n("Save As") : caption); 01613 01614 dlg.exec(); 01615 01616 TQString filename = dlg.selectedFile(); 01617 if (!filename.isEmpty()) 01618 TDERecentDocument::add(filename); 01619 01620 return filename; 01621 } 01622 01623 TQString KFileDialog::getSaveFileNameWId(const TQString& dir, const TQString& filter, 01624 WId parent_id, 01625 const TQString& caption) 01626 { 01627 bool specialDir = dir.at(0) == ':'; 01628 TQWidget* parent = TQT_TQWIDGET(TQWidget::find( parent_id )); 01629 KFileDialog dlg( specialDir ? dir : TQString::null, filter, parent, "filedialog", true); 01630 #ifdef Q_WS_X11 01631 if( parent == NULL && parent_id != 0 ) 01632 XSetTransientForHint(tqt_xdisplay(), dlg.winId(), parent_id); 01633 #else 01634 // TODO 01635 #endif 01636 01637 if ( !specialDir ) 01638 dlg.setSelection( dir ); // may also be a filename 01639 01640 dlg.setOperationMode( KFileDialog::Saving); 01641 dlg.setCaption(caption.isNull() ? i18n("Save As") : caption); 01642 01643 dlg.exec(); 01644 01645 TQString filename = dlg.selectedFile(); 01646 if (!filename.isEmpty()) 01647 TDERecentDocument::add(filename); 01648 01649 return filename; 01650 } 01651 01652 KURL KFileDialog::getSaveURL(const TQString& dir, const TQString& filter, 01653 TQWidget *parent, const TQString& caption) 01654 { 01655 bool specialDir = dir.at(0) == ':'; 01656 KFileDialog dlg(specialDir ? dir : TQString::null, filter, parent, "filedialog", true); 01657 if ( !specialDir ) 01658 dlg.setSelection( dir ); // may also be a filename 01659 01660 dlg.setCaption(caption.isNull() ? i18n("Save As") : caption); 01661 dlg.setOperationMode( Saving ); 01662 01663 dlg.exec(); 01664 01665 KURL url = dlg.selectedURL(); 01666 if (url.isValid()) 01667 TDERecentDocument::add( url ); 01668 01669 return url; 01670 } 01671 01672 void KFileDialog::show() 01673 { 01674 if ( !d->hasView ) { // delayed view-creation 01675 ops->setView(KFile::Default); 01676 ops->clearHistory(); 01677 d->hasView = true; 01678 } 01679 01680 KDialogBase::show(); 01681 } 01682 01683 void KFileDialog::setMode( KFile::Mode m ) 01684 { 01685 ops->setMode(m); 01686 if ( ops->dirOnlyMode() ) { 01687 filterWidget->setDefaultFilter( i18n("*|All Folders") ); 01688 } 01689 else { 01690 filterWidget->setDefaultFilter( i18n("*|All Files") ); 01691 } 01692 01693 updateAutoSelectExtension (); 01694 } 01695 01696 void KFileDialog::setMode( unsigned int m ) 01697 { 01698 setMode(static_cast<KFile::Mode>( m )); 01699 } 01700 01701 KFile::Mode KFileDialog::mode() const 01702 { 01703 return ops->mode(); 01704 } 01705 01706 01707 void KFileDialog::readConfig( TDEConfig *kc, const TQString& group ) 01708 { 01709 if ( !kc ) 01710 return; 01711 01712 TQString oldGroup = kc->group(); 01713 if ( !group.isEmpty() ) 01714 kc->setGroup( group ); 01715 01716 ops->readConfig( kc, group ); 01717 01718 KURLComboBox *combo = d->pathCombo; 01719 combo->setURLs( kc->readPathListEntry( RecentURLs ), KURLComboBox::RemoveTop ); 01720 combo->setMaxItems( kc->readNumEntry( RecentURLsNumber, 01721 DefaultRecentURLsNumber ) ); 01722 combo->setURL( ops->url() ); 01723 autoDirectoryFollowing = kc->readBoolEntry( AutoDirectoryFollowing, 01724 DefaultDirectoryFollowing ); 01725 01726 TDEGlobalSettings::Completion cm = (TDEGlobalSettings::Completion) 01727 kc->readNumEntry( PathComboCompletionMode, 01728 TDEGlobalSettings::completionMode() ); 01729 if ( cm != TDEGlobalSettings::completionMode() ) 01730 combo->setCompletionMode( cm ); 01731 01732 cm = (TDEGlobalSettings::Completion) 01733 kc->readNumEntry( LocationComboCompletionMode, 01734 TDEGlobalSettings::completionMode() ); 01735 if ( cm != TDEGlobalSettings::completionMode() ) 01736 locationEdit->setCompletionMode( cm ); 01737 01738 // show or don't show the speedbar 01739 toggleSpeedbar( kc->readBoolEntry(ShowSpeedbar, true) ); 01740 01741 // show or don't show the bookmarks 01742 toggleBookmarks( kc->readBoolEntry(ShowBookmarks, false) ); 01743 01744 // does the user want Automatically Select Extension? 01745 d->autoSelectExtChecked = kc->readBoolEntry (AutoSelectExtChecked, DefaultAutoSelectExtChecked); 01746 updateAutoSelectExtension (); 01747 01748 int w1 = minimumSize().width(); 01749 int w2 = toolbar->sizeHint().width() + 10; 01750 if (w1 < w2) 01751 setMinimumWidth(w2); 01752 01753 TQSize size = configDialogSize( group ); 01754 resize( size ); 01755 kc->setGroup( oldGroup ); 01756 } 01757 01758 void KFileDialog::writeConfig( TDEConfig *kc, const TQString& group ) 01759 { 01760 if ( !kc ) 01761 return; 01762 01763 TQString oldGroup = kc->group(); 01764 if ( !group.isEmpty() ) 01765 kc->setGroup( group ); 01766 01767 kc->writePathEntry( RecentURLs, d->pathCombo->urls() ); 01768 saveDialogSize( group, true ); 01769 kc->writeEntry( PathComboCompletionMode, static_cast<int>(d->pathCombo->completionMode()) ); 01770 kc->writeEntry( LocationComboCompletionMode, static_cast<int>(locationEdit->completionMode()) ); 01771 kc->writeEntry( ShowSpeedbar, d->urlBar && !d->urlBar->isHidden() ); 01772 kc->writeEntry( ShowBookmarks, d->bookmarkHandler != 0 ); 01773 kc->writeEntry( AutoSelectExtChecked, d->autoSelectExtChecked ); 01774 01775 ops->writeConfig( kc, group ); 01776 kc->setGroup( oldGroup ); 01777 } 01778 01779 01780 void KFileDialog::readRecentFiles( TDEConfig *kc ) 01781 { 01782 TQString oldGroup = kc->group(); 01783 kc->setGroup( ConfigGroup ); 01784 01785 locationEdit->setMaxItems( kc->readNumEntry( RecentFilesNumber, 01786 DefaultRecentURLsNumber ) ); 01787 locationEdit->setURLs( kc->readPathListEntry( RecentFiles ), 01788 KURLComboBox::RemoveBottom ); 01789 locationEdit->insertItem( TQString::null, 0 ); // dummy item without pixmap 01790 locationEdit->setCurrentItem( 0 ); 01791 01792 kc->setGroup( oldGroup ); 01793 } 01794 01795 void KFileDialog::saveRecentFiles( TDEConfig *kc ) 01796 { 01797 TQString oldGroup = kc->group(); 01798 kc->setGroup( ConfigGroup ); 01799 01800 kc->writePathEntry( RecentFiles, locationEdit->urls() ); 01801 01802 kc->setGroup( oldGroup ); 01803 } 01804 01805 KPushButton * KFileDialog::okButton() const 01806 { 01807 return d->okButton; 01808 } 01809 01810 KPushButton * KFileDialog::cancelButton() const 01811 { 01812 return d->cancelButton; 01813 } 01814 01815 KURLBar * KFileDialog::speedBar() 01816 { 01817 return d->urlBar; 01818 } 01819 01820 void KFileDialog::slotCancel() 01821 { 01822 ops->close(); 01823 KDialogBase::slotCancel(); 01824 01825 TDEConfig *config = TDEGlobal::config(); 01826 config->setForceGlobal( true ); 01827 writeConfig( config, ConfigGroup ); 01828 config->setForceGlobal( false ); 01829 } 01830 01831 void KFileDialog::setKeepLocation( bool keep ) 01832 { 01833 d->keepLocation = keep; 01834 } 01835 01836 bool KFileDialog::keepsLocation() const 01837 { 01838 return d->keepLocation; 01839 } 01840 01841 void KFileDialog::setOperationMode( OperationMode mode ) 01842 { 01843 d->operationMode = mode; 01844 d->keepLocation = (mode == Saving); 01845 filterWidget->setEditable( !d->hasDefaultFilter || mode != Saving ); 01846 if ( mode == Opening ) 01847 d->okButton->setGuiItem( KGuiItem( i18n("&Open"), "document-open") ); 01848 else if ( mode == Saving ) { 01849 d->okButton->setGuiItem( KStdGuiItem::save() ); 01850 setNonExtSelection(); 01851 } 01852 else 01853 d->okButton->setGuiItem( KStdGuiItem::ok() ); 01854 updateLocationWhatsThis (); 01855 updateAutoSelectExtension (); 01856 } 01857 01858 KFileDialog::OperationMode KFileDialog::operationMode() const 01859 { 01860 return d->operationMode; 01861 } 01862 01863 void KFileDialog::slotAutoSelectExtClicked() 01864 { 01865 kdDebug (tdefile_area) << "slotAutoSelectExtClicked(): " 01866 << d->autoSelectExtCheckBox->isChecked () << endl; 01867 01868 // whether the _user_ wants it on/off 01869 d->autoSelectExtChecked = d->autoSelectExtCheckBox->isChecked (); 01870 01871 // update the current filename's extension 01872 updateLocationEditExtension (d->extension /* extension hasn't changed */); 01873 } 01874 01875 static TQString getExtensionFromPatternList (const TQStringList &patternList) 01876 { 01877 TQString ret; 01878 kdDebug (tdefile_area) << "\tgetExtension " << patternList << endl; 01879 01880 TQStringList::ConstIterator patternListEnd = patternList.end (); 01881 for (TQStringList::ConstIterator it = patternList.begin (); 01882 it != patternListEnd; 01883 it++) 01884 { 01885 kdDebug (tdefile_area) << "\t\ttry: \'" << (*it) << "\'" << endl; 01886 01887 // is this pattern like "*.BMP" rather than useless things like: 01888 // 01889 // README 01890 // *. 01891 // *.* 01892 // *.JP*G 01893 // *.JP? 01894 if ((*it).startsWith ("*.") && 01895 (*it).length () > 2 && 01896 (*it).find ('*', 2) < 0 && (*it).find ('?', 2) < 0) 01897 { 01898 ret = (*it).mid (1); 01899 break; 01900 } 01901 } 01902 01903 return ret; 01904 } 01905 01906 static TQString stripUndisplayable (const TQString &string) 01907 { 01908 TQString ret = string; 01909 01910 ret.remove (':'); 01911 ret.remove ('&'); 01912 01913 return ret; 01914 } 01915 01916 01917 TQString KFileDialog::currentFilterExtension (void) 01918 { 01919 return d->extension; 01920 } 01921 01922 void KFileDialog::updateAutoSelectExtension (void) 01923 { 01924 if (!d->autoSelectExtCheckBox) return; 01925 01926 // 01927 // Figure out an extension for the Automatically Select Extension thing 01928 // (some Windows users apparently don't know what to do when confronted 01929 // with a text file called "COPYING" but do know what to do with 01930 // COPYING.txt ...) 01931 // 01932 01933 kdDebug (tdefile_area) << "Figure out an extension: " << endl; 01934 TQString lastExtension = d->extension; 01935 d->extension = TQString::null; 01936 01937 // Automatically Select Extension is only valid if the user is _saving_ a _file_ 01938 if ((operationMode () == Saving) && (mode () & KFile::File)) 01939 { 01940 // 01941 // Get an extension from the filter 01942 // 01943 01944 TQString filter = currentFilter (); 01945 if (!filter.isEmpty ()) 01946 { 01947 // e.g. "*.cpp" 01948 if (filter.find ('/') < 0) 01949 { 01950 d->extension = getExtensionFromPatternList (TQStringList::split (" ", filter)).lower (); 01951 kdDebug (tdefile_area) << "\tsetFilter-style: pattern ext=\'" 01952 << d->extension << "\'" << endl; 01953 } 01954 // e.g. "text/html" 01955 else 01956 { 01957 KMimeType::Ptr mime = KMimeType::mimeType (filter); 01958 01959 // first try X-TDE-NativeExtension 01960 TQString nativeExtension = mime->property ("X-TDE-NativeExtension").toString (); 01961 if (nativeExtension.at (0) == '.') 01962 { 01963 d->extension = nativeExtension.lower (); 01964 kdDebug (tdefile_area) << "\tsetMimeFilter-style: native ext=\'" 01965 << d->extension << "\'" << endl; 01966 } 01967 01968 // no X-TDE-NativeExtension 01969 if (d->extension.isEmpty ()) 01970 { 01971 d->extension = getExtensionFromPatternList (mime->patterns ()).lower (); 01972 kdDebug (tdefile_area) << "\tsetMimeFilter-style: pattern ext=\'" 01973 << d->extension << "\'" << endl; 01974 } 01975 } 01976 } 01977 01978 01979 // 01980 // GUI: checkbox 01981 // 01982 01983 TQString whatsThisExtension; 01984 if (!d->extension.isEmpty ()) 01985 { 01986 // remember: sync any changes to the string with below 01987 d->autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension (%1)").arg (d->extension)); 01988 whatsThisExtension = i18n ("the extension <b>%1</b>").arg (d->extension); 01989 01990 d->autoSelectExtCheckBox->setEnabled (true); 01991 d->autoSelectExtCheckBox->setChecked (d->autoSelectExtChecked); 01992 } 01993 else 01994 { 01995 // remember: sync any changes to the string with above 01996 d->autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension")); 01997 whatsThisExtension = i18n ("a suitable extension"); 01998 01999 d->autoSelectExtCheckBox->setChecked (false); 02000 d->autoSelectExtCheckBox->setEnabled (false); 02001 } 02002 02003 const TQString locationLabelText = stripUndisplayable (d->locationLabel->text ()); 02004 const TQString filterLabelText = stripUndisplayable (d->filterLabel->text ()); 02005 TQWhatsThis::add (d->autoSelectExtCheckBox, 02006 "<qt>" + 02007 i18n ( 02008 "This option enables some convenient features for " 02009 "saving files with extensions:<br>" 02010 "<ol>" 02011 "<li>Any extension specified in the <b>%1</b> text " 02012 "area will be updated if you change the file type " 02013 "to save in.<br>" 02014 "<br></li>" 02015 "<li>If no extension is specified in the <b>%2</b> " 02016 "text area when you click " 02017 "<b>Save</b>, %3 will be added to the end of the " 02018 "filename (if the filename does not already exist). " 02019 "This extension is based on the file type that you " 02020 "have chosen to save in.<br>" 02021 "<br>" 02022 "If you do not want TDE to supply an extension for the " 02023 "filename, you can either turn this option off or you " 02024 "can suppress it by adding a period (.) to the end of " 02025 "the filename (the period will be automatically " 02026 "removed)." 02027 "</li>" 02028 "</ol>" 02029 "If unsure, keep this option enabled as it makes your " 02030 "files more manageable." 02031 ) 02032 .arg (locationLabelText) 02033 .arg (locationLabelText) 02034 .arg (whatsThisExtension) 02035 + "</qt>" 02036 ); 02037 02038 d->autoSelectExtCheckBox->show (); 02039 02040 02041 // update the current filename's extension 02042 updateLocationEditExtension (lastExtension); 02043 } 02044 // Automatically Select Extension not valid 02045 else 02046 { 02047 d->autoSelectExtCheckBox->setChecked (false); 02048 d->autoSelectExtCheckBox->hide (); 02049 } 02050 } 02051 02052 // Updates the extension of the filename specified in locationEdit if the 02053 // Automatically Select Extension feature is enabled. 02054 // (this prevents you from accidently saving "file.kwd" as RTF, for example) 02055 void KFileDialog::updateLocationEditExtension (const TQString &lastExtension) 02056 { 02057 if (!d->autoSelectExtCheckBox->isChecked () || d->extension.isEmpty ()) 02058 return; 02059 02060 TQString urlStr = locationEdit->currentText (); 02061 if (urlStr.isEmpty ()) 02062 return; 02063 02064 KURL url = getCompleteURL (urlStr); 02065 kdDebug (tdefile_area) << "updateLocationEditExtension (" << url << ")" << endl; 02066 02067 const int fileNameOffset = urlStr.findRev ('/') + 1; 02068 TQString fileName = urlStr.mid (fileNameOffset); 02069 02070 const int dot = fileName.findRev ('.'); 02071 const int len = fileName.length (); 02072 if (dot > 0 && // has an extension already and it's not a hidden file 02073 // like ".hidden" (but we do accept ".hidden.ext") 02074 dot != len - 1 // and not deliberately suppressing extension 02075 ) 02076 { 02077 // exists? 02078 TDEIO::UDSEntry t; 02079 if (TDEIO::NetAccess::stat (url, t, topLevelWidget())) 02080 { 02081 kdDebug (tdefile_area) << "\tfile exists" << endl; 02082 02083 if (isDirectory (t)) 02084 { 02085 kdDebug (tdefile_area) << "\tisDir - won't alter extension" << endl; 02086 return; 02087 } 02088 02089 // --- fall through --- 02090 } 02091 02092 02093 // 02094 // try to get rid of the current extension 02095 // 02096 02097 // catch "double extensions" like ".tar.gz" 02098 if (lastExtension.length () && fileName.endsWith (lastExtension)) 02099 fileName.truncate (len - lastExtension.length ()); 02100 // can only handle "single extensions" 02101 else 02102 fileName.truncate (dot); 02103 02104 // add extension 02105 const TQString newText = urlStr.left (fileNameOffset) + fileName + d->extension; 02106 if ( newText != locationEdit->currentText() ) 02107 { 02108 locationEdit->setCurrentText (urlStr.left (fileNameOffset) + fileName + d->extension); 02109 locationEdit->lineEdit()->setEdited (true); 02110 } 02111 } 02112 } 02113 02114 // Updates the filter if the extension of the filename specified in locationEdit is changed 02115 // (this prevents you from accidently saving "file.kwd" as RTF, for example) 02116 void KFileDialog::updateFilter () 02117 { 02118 if ((operationMode() == Saving) && (mode() & KFile::File) ) { 02119 const TQString urlStr = locationEdit->currentText (); 02120 if (urlStr.isEmpty ()) 02121 return; 02122 02123 KMimeType::Ptr mime = KMimeType::findByPath(urlStr, 0, true); 02124 if (mime && mime->name() != KMimeType::defaultMimeType()) { 02125 if (filterWidget->currentFilter() != mime->name() && 02126 filterWidget->filters.findIndex(mime->name()) != -1) { 02127 filterWidget->setCurrentFilter(mime->name()); 02128 } 02129 } 02130 } 02131 } 02132 02133 // applies only to a file that doesn't already exist 02134 void KFileDialog::appendExtension (KURL &url) 02135 { 02136 if (!d->autoSelectExtCheckBox->isChecked () || d->extension.isEmpty ()) 02137 return; 02138 02139 TQString fileName = url.fileName (); 02140 if (fileName.isEmpty ()) 02141 return; 02142 02143 kdDebug (tdefile_area) << "appendExtension(" << url << ")" << endl; 02144 02145 const int len = fileName.length (); 02146 const int dot = fileName.findRev ('.'); 02147 02148 const bool suppressExtension = (dot == len - 1); 02149 const bool unspecifiedExtension = (dot <= 0); 02150 02151 // don't TDEIO::NetAccess::Stat if unnecessary 02152 if (!(suppressExtension || unspecifiedExtension)) 02153 return; 02154 02155 // exists? 02156 TDEIO::UDSEntry t; 02157 if (TDEIO::NetAccess::stat (url, t, topLevelWidget())) 02158 { 02159 kdDebug (tdefile_area) << "\tfile exists - won't append extension" << endl; 02160 return; 02161 } 02162 02163 // suppress automatically append extension? 02164 if (suppressExtension) 02165 { 02166 // 02167 // Strip trailing dot 02168 // This allows lazy people to have autoSelectExtCheckBox->isChecked 02169 // but don't want a file extension to be appended 02170 // e.g. "README." will make a file called "README" 02171 // 02172 // If you really want a name like "README.", then type "README.." 02173 // and the trailing dot will be removed (or just stop being lazy and 02174 // turn off this feature so that you can type "README.") 02175 // 02176 kdDebug (tdefile_area) << "\tstrip trailing dot" << endl; 02177 url.setFileName (fileName.left (len - 1)); 02178 } 02179 // evilmatically append extension :) if the user hasn't specified one 02180 else if (unspecifiedExtension) 02181 { 02182 kdDebug (tdefile_area) << "\tappending extension \'" << d->extension << "\'..." << endl; 02183 url.setFileName (fileName + d->extension); 02184 kdDebug (tdefile_area) << "\tsaving as \'" << url << "\'" << endl; 02185 } 02186 } 02187 02188 02189 // adds the selected files/urls to 'recent documents' 02190 void KFileDialog::addToRecentDocuments() 02191 { 02192 int m = ops->mode(); 02193 02194 if ( m & KFile::LocalOnly ) { 02195 TQStringList files = selectedFiles(); 02196 TQStringList::ConstIterator it = files.begin(); 02197 for ( ; it != files.end(); ++it ) 02198 TDERecentDocument::add( *it ); 02199 } 02200 02201 else { // urls 02202 KURL::List urls = selectedURLs(); 02203 KURL::List::ConstIterator it = urls.begin(); 02204 for ( ; it != urls.end(); ++it ) { 02205 if ( (*it).isValid() ) 02206 TDERecentDocument::add( *it ); 02207 } 02208 } 02209 } 02210 02211 TDEActionCollection * KFileDialog::actionCollection() const 02212 { 02213 return ops->actionCollection(); 02214 } 02215 02216 void KFileDialog::keyPressEvent( TQKeyEvent *e ) 02217 { 02218 if ( e->key() == Key_Escape ) 02219 { 02220 e->accept(); 02221 d->cancelButton->animateClick(); 02222 } 02223 else 02224 KDialogBase::keyPressEvent( e ); 02225 } 02226 02227 void KFileDialog::toggleSpeedbar( bool show ) 02228 { 02229 if ( show ) 02230 { 02231 if ( !d->urlBar ) 02232 initSpeedbar(); 02233 02234 d->urlBar->show(); 02235 02236 // check to see if they have a home item defined, if not show the home button 02237 KURLBarItem *urlItem = static_cast<KURLBarItem*>( d->urlBar->listBox()->firstItem() ); 02238 KURL homeURL; 02239 homeURL.setPath( TQDir::homeDirPath() ); 02240 while ( urlItem ) 02241 { 02242 if ( homeURL.equals( urlItem->url(), true ) ) 02243 { 02244 ops->actionCollection()->action( "home" )->unplug( toolbar ); 02245 break; 02246 } 02247 02248 urlItem = static_cast<KURLBarItem*>( urlItem->next() ); 02249 } 02250 } 02251 else 02252 { 02253 if (d->urlBar) 02254 d->urlBar->hide(); 02255 02256 if ( !ops->actionCollection()->action( "home" )->isPlugged( toolbar ) ) 02257 ops->actionCollection()->action( "home" )->plug( toolbar, 3 ); 02258 } 02259 02260 static_cast<TDEToggleAction *>(actionCollection()->action("toggleSpeedbar"))->setChecked( show ); 02261 } 02262 02263 void KFileDialog::toggleBookmarks(bool show) 02264 { 02265 if (show) 02266 { 02267 if (d->bookmarkHandler) 02268 { 02269 return; 02270 } 02271 02272 d->bookmarkHandler = new KFileBookmarkHandler( this ); 02273 connect( d->bookmarkHandler, TQT_SIGNAL( openURL( const TQString& )), 02274 TQT_SLOT( enterURL( const TQString& ))); 02275 02276 toolbar->insertButton(TQString::fromLatin1("bookmark"), 02277 (int)HOTLIST_BUTTON, true, 02278 i18n("Bookmarks"), 5); 02279 toolbar->getButton(HOTLIST_BUTTON)->setPopup(d->bookmarkHandler->menu(), 02280 true); 02281 TQWhatsThis::add(toolbar->getButton(HOTLIST_BUTTON), 02282 i18n("<qt>This button allows you to bookmark specific locations. " 02283 "Click on this button to open the bookmark menu where you may add, " 02284 "edit or select a bookmark.<p>" 02285 "These bookmarks are specific to the file dialog, but otherwise operate " 02286 "like bookmarks elsewhere in TDE.</qt>")); 02287 } 02288 else if (d->bookmarkHandler) 02289 { 02290 delete d->bookmarkHandler; 02291 d->bookmarkHandler = 0; 02292 toolbar->removeItem(HOTLIST_BUTTON); 02293 } 02294 02295 static_cast<TDEToggleAction *>(actionCollection()->action("toggleBookmarks"))->setChecked( show ); 02296 } 02297 02298 int KFileDialog::pathComboIndex() 02299 { 02300 return d->m_pathComboIndex; 02301 } 02302 02303 // static 02304 void KFileDialog::initStatic() 02305 { 02306 if ( lastDirectory ) 02307 return; 02308 02309 lastDirectory = ldd.setObject(lastDirectory, new KURL()); 02310 } 02311 02312 // static 02313 KURL KFileDialog::getStartURL( const TQString& startDir, 02314 TQString& recentDirClass ) 02315 { 02316 initStatic(); 02317 02318 recentDirClass = TQString::null; 02319 KURL ret; 02320 02321 bool useDefaultStartDir = startDir.isEmpty(); 02322 if ( !useDefaultStartDir ) 02323 { 02324 if (startDir[0] == ':') 02325 { 02326 recentDirClass = startDir; 02327 ret = KURL::fromPathOrURL( TDERecentDirs::dir(recentDirClass) ); 02328 } 02329 else 02330 { 02331 ret = TDECmdLineArgs::makeURL( TQFile::encodeName(startDir) ); 02332 // If we won't be able to list it (e.g. http), then use default 02333 if ( !KProtocolInfo::supportsListing( ret ) ) 02334 useDefaultStartDir = true; 02335 } 02336 } 02337 02338 if ( useDefaultStartDir ) 02339 { 02340 if (lastDirectory->isEmpty()) { 02341 lastDirectory->setPath(TDEGlobalSettings::documentPath()); 02342 KURL home; 02343 home.setPath( TQDir::homeDirPath() ); 02344 // if there is no docpath set (== home dir), we prefer the current 02345 // directory over it. We also prefer the homedir when our CWD is 02346 // different from our homedirectory or when the document dir 02347 // does not exist 02348 if ( lastDirectory->path(+1) == home.path(+1) || 02349 TQDir::currentDirPath() != TQDir::homeDirPath() || 02350 !TQDir(lastDirectory->path(+1)).exists() ) 02351 lastDirectory->setPath(TQDir::currentDirPath()); 02352 } 02353 ret = *lastDirectory; 02354 } 02355 02356 return ret; 02357 } 02358 02359 void KFileDialog::setStartDir( const KURL& directory ) 02360 { 02361 initStatic(); 02362 if ( directory.isValid() ) 02363 *lastDirectory = directory; 02364 } 02365 02366 void KFileDialog::setNonExtSelection() 02367 { 02368 // Enhanced rename: Don't highlight the file extension. 02369 TQString pattern, filename = locationEdit->currentText().stripWhiteSpace(); 02370 KServiceTypeFactory::self()->findFromPattern( filename, &pattern ); 02371 02372 if ( !pattern.isEmpty() && pattern.at( 0 ) == '*' && pattern.find( '*' , 1 ) == -1 ) 02373 locationEdit->lineEdit()->setSelection( 0, filename.length() - pattern.stripWhiteSpace().length()+1 ); 02374 else 02375 { 02376 int lastDot = filename.findRev( '.' ); 02377 if ( lastDot > 0 ) 02378 locationEdit->lineEdit()->setSelection( 0, lastDot ); 02379 } 02380 } 02381 02382 void KFileDialog::virtual_hook( int id, void* data ) 02383 { KDialogBase::virtual_hook( id, data ); } 02384 02385 02386 #include "tdefiledialog.moc"
Trinity API Reference