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 locationEdit->blockSignals( true ); 01177 locationEdit->setCurrentItem( 0 ); 01178 if ( d->keepLocation ) 01179 locationEdit->setEditText( filename ); 01180 01181 locationEdit->blockSignals( false ); 01182 01183 TQString dir = url.url(+1); 01184 static_cast<KURLCompletion*>( d->pathCombo->completionObject() )->setDir( dir ); 01185 static_cast<KURLCompletion*>( locationEdit->completionObject() )->setDir( dir ); 01186 01187 if ( d->urlBar ) 01188 d->urlBar->setCurrentItem( url ); 01189 } 01190 01191 void KFileDialog::locationActivated( const TQString& url ) 01192 { 01193 // This guard prevents any URL _typed_ by the user from being interpreted 01194 // twice (by returnPressed/slotOk and here, activated/locationActivated) 01195 // after the user presses Enter. Without this, _both_ setSelection and 01196 // slotOk would "u.addPath( url )" ...so instead we leave it up to just 01197 // slotOk.... 01198 if (!locationEdit->lineEdit()->edited()) 01199 setSelection( url ); 01200 } 01201 01202 void KFileDialog::enterURL( const KURL& url) 01203 { 01204 setURL( url ); 01205 } 01206 01207 void KFileDialog::enterURL( const TQString& url ) 01208 { 01209 setURL( KURL::fromPathOrURL( KURLCompletion::replacedPath( url, true, true )) ); 01210 } 01211 01212 void KFileDialog::toolbarCallback(int) // SLOT 01213 { 01214 /* 01215 * yes, nothing uses this anymore. 01216 * it used to be used to show the configure dialog 01217 */ 01218 } 01219 01220 01221 void KFileDialog::setSelection(const TQString& url) 01222 { 01223 kdDebug(tdefile_area) << "setSelection " << url << endl; 01224 01225 if (url.isEmpty()) { 01226 d->selection = TQString::null; 01227 return; 01228 } 01229 01230 KURL u = getCompleteURL(url); 01231 if (!u.isValid()) { // if it still is 01232 kdWarning() << url << " is not a correct argument for setSelection!" << endl; 01233 return; 01234 } 01235 01236 if (!KProtocolInfo::supportsListing(u)) { 01237 locationEdit->lineEdit()->setEdited( true ); 01238 return; 01239 } 01240 01241 /* we strip the first / from the path to avoid file://usr which means 01242 * / on host usr 01243 */ 01244 KFileItem i(KFileItem::Unknown, KFileItem::Unknown, u, true ); 01245 // KFileItem i(u.path()); 01246 if ( i.isDir() && u.isLocalFile() && TQFile::exists( u.path() ) ) { 01247 // trust isDir() only if the file is 01248 // local (we cannot stat non-local urls) and if it exists! 01249 // (as KFileItem does not check if the file exists or not 01250 // -> the statbuffer is undefined -> isDir() is unreliable) (Simon) 01251 setURL(u, true); 01252 } 01253 else { 01254 TQString filename = u.url(); 01255 int sep = filename.findRev('/'); 01256 if (sep >= 0) { // there is a / in it 01257 if ( KProtocolInfo::supportsListing( u )) { 01258 KURL dir(u); 01259 dir.setQuery( TQString::null ); 01260 dir.setFileName( TQString::null ); 01261 setURL(dir, true ); 01262 } 01263 01264 // filename must be decoded, or "name with space" would become 01265 // "name%20with%20space", so we use KURL::fileName() 01266 filename = u.fileName(); 01267 kdDebug(tdefile_area) << "filename " << filename << endl; 01268 d->selection = filename; 01269 setLocationText( filename ); 01270 01271 // tell the line edit that it has been edited 01272 // otherwise we won't know this was set by the user 01273 // and it will be ignored if there has been an 01274 // auto completion. this caused bugs where automcompletion 01275 // would start, the user would pick something from the 01276 // history and then hit Ok only to get the autocompleted 01277 // selection. OOOPS. 01278 locationEdit->lineEdit()->setEdited( true ); 01279 } 01280 01281 d->url = ops->url(); 01282 d->url.addPath(filename); 01283 } 01284 } 01285 01286 void KFileDialog::slotLoadingFinished() 01287 { 01288 if ( !d->selection.isNull() ) 01289 ops->setCurrentItem( d->selection ); 01290 } 01291 01292 // ### remove in KDE4 01293 void KFileDialog::pathComboChanged( const TQString& ) 01294 { 01295 } 01296 void KFileDialog::dirCompletion( const TQString& ) // SLOT 01297 { 01298 } 01299 void KFileDialog::fileCompletion( const TQString& match ) 01300 { 01301 if ( match.isEmpty() && ops->view() ) 01302 ops->view()->clearSelection(); 01303 else 01304 ops->setCurrentItem( match ); 01305 } 01306 01307 void KFileDialog::slotLocationChanged( const TQString& text ) 01308 { 01309 if ( text.isEmpty() && ops->view() ) 01310 ops->view()->clearSelection(); 01311 01312 updateFilter(); 01313 } 01314 01315 void KFileDialog::updateStatusLine(int /* dirs */, int /* files */) 01316 { 01317 kdWarning() << "KFileDialog::updateStatusLine is deprecated! The status line no longer exists. Do not try and use it!" << endl; 01318 } 01319 01320 TQString KFileDialog::getOpenFileName(const TQString& startDir, 01321 const TQString& filter, 01322 TQWidget *parent, const TQString& caption) 01323 { 01324 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01325 dlg.setOperationMode( Opening ); 01326 01327 dlg.setMode( KFile::File | KFile::LocalOnly ); 01328 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01329 01330 dlg.ops->clearHistory(); 01331 dlg.exec(); 01332 01333 return dlg.selectedFile(); 01334 } 01335 01336 TQString KFileDialog::getOpenFileNameWId(const TQString& startDir, 01337 const TQString& filter, 01338 WId parent_id, const TQString& caption) 01339 { 01340 TQWidget* parent = TQT_TQWIDGET(TQWidget::find( parent_id )); 01341 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01342 #ifdef Q_WS_X11 01343 if( parent == NULL && parent_id != 0 ) 01344 XSetTransientForHint( tqt_xdisplay(), dlg.winId(), parent_id ); 01345 #else 01346 // TODO 01347 #endif 01348 01349 dlg.setOperationMode( KFileDialog::Opening ); 01350 01351 dlg.setMode( KFile::File | KFile::LocalOnly ); 01352 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01353 01354 dlg.ops->clearHistory(); 01355 dlg.exec(); 01356 01357 return dlg.selectedFile(); 01358 } 01359 01360 TQStringList KFileDialog::getOpenFileNames(const TQString& startDir, 01361 const TQString& filter, 01362 TQWidget *parent, 01363 const TQString& caption) 01364 { 01365 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01366 dlg.setOperationMode( Opening ); 01367 01368 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01369 dlg.setMode(KFile::Files | KFile::LocalOnly); 01370 dlg.ops->clearHistory(); 01371 dlg.exec(); 01372 01373 return dlg.selectedFiles(); 01374 } 01375 01376 KURL KFileDialog::getOpenURL(const TQString& startDir, const TQString& filter, 01377 TQWidget *parent, const TQString& caption) 01378 { 01379 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01380 dlg.setOperationMode( Opening ); 01381 01382 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01383 dlg.setMode( KFile::File ); 01384 dlg.ops->clearHistory(); 01385 dlg.exec(); 01386 01387 return dlg.selectedURL(); 01388 } 01389 01390 KURL::List KFileDialog::getOpenURLs(const TQString& startDir, 01391 const TQString& filter, 01392 TQWidget *parent, 01393 const TQString& caption) 01394 { 01395 KFileDialog dlg(startDir, filter, parent, "filedialog", true); 01396 dlg.setOperationMode( Opening ); 01397 01398 dlg.setCaption(caption.isNull() ? i18n("Open") : caption); 01399 dlg.setMode(KFile::Files); 01400 dlg.ops->clearHistory(); 01401 dlg.exec(); 01402 01403 return dlg.selectedURLs(); 01404 } 01405 01406 KURL KFileDialog::getExistingURL(const TQString& startDir, 01407 TQWidget *parent, 01408 const TQString& caption) 01409 { 01410 return KDirSelectDialog::selectDirectory(startDir, false, parent, caption); 01411 } 01412 01413 TQString KFileDialog::getExistingDirectory(const TQString& startDir, 01414 TQWidget *parent, 01415 const TQString& caption) 01416 { 01417 #ifdef Q_WS_WIN 01418 return TQFileDialog::getExistingDirectory(startDir, parent, "getExistingDirectory", 01419 caption, true, true); 01420 #else 01421 KURL url = KDirSelectDialog::selectDirectory(startDir, true, parent, 01422 caption); 01423 if ( url.isValid() ) 01424 return url.path(); 01425 01426 return TQString::null; 01427 #endif 01428 } 01429 01430 KURL KFileDialog::getImageOpenURL( const TQString& startDir, TQWidget *parent, 01431 const TQString& caption) 01432 { 01433 TQStringList mimetypes = KImageIO::mimeTypes( KImageIO::Reading ); 01434 KFileDialog dlg(startDir, 01435 mimetypes.join(" "), 01436 parent, "filedialog", true); 01437 dlg.setOperationMode( Opening ); 01438 dlg.setCaption( caption.isNull() ? i18n("Open") : caption ); 01439 dlg.setMode( KFile::File ); 01440 01441 KImageFilePreview *ip = new KImageFilePreview( &dlg ); 01442 dlg.setPreviewWidget( ip ); 01443 dlg.exec(); 01444 01445 return dlg.selectedURL(); 01446 } 01447 01448 KURL KFileDialog::selectedURL() const 01449 { 01450 if ( result() == TQDialog::Accepted ) 01451 return d->url; 01452 else 01453 return KURL(); 01454 } 01455 01456 KURL::List KFileDialog::selectedURLs() const 01457 { 01458 KURL::List list; 01459 if ( result() == TQDialog::Accepted ) { 01460 if ( (ops->mode() & KFile::Files) == KFile::Files ) 01461 list = parseSelectedURLs(); 01462 else 01463 list.append( d->url ); 01464 } 01465 return list; 01466 } 01467 01468 01469 KURL::List& KFileDialog::parseSelectedURLs() const 01470 { 01471 if ( d->filenames.isEmpty() ) { 01472 return d->urlList; 01473 } 01474 01475 d->urlList.clear(); 01476 if ( d->filenames.contains( '/' )) { // assume _one_ absolute filename 01477 static const TQString &prot = TDEGlobal::staticQString(":/"); 01478 KURL u; 01479 if ( d->filenames.find( prot ) != -1 ) 01480 u = d->filenames; 01481 else 01482 u.setPath( d->filenames ); 01483 01484 if ( u.isValid() ) 01485 d->urlList.append( u ); 01486 else 01487 KMessageBox::error( d->mainWidget, 01488 i18n("The chosen filenames do not\n" 01489 "appear to be valid."), 01490 i18n("Invalid Filenames") ); 01491 } 01492 01493 else 01494 d->urlList = tokenize( d->filenames ); 01495 01496 d->filenames = TQString::null; // indicate that we parsed that one 01497 01498 return d->urlList; 01499 } 01500 01501 01502 // FIXME: current implementation drawback: a filename can't contain quotes 01503 KURL::List KFileDialog::tokenize( const TQString& line ) const 01504 { 01505 KURL::List urls; 01506 KURL u( ops->url() ); 01507 TQString name; 01508 01509 int count = line.contains( '"' ); 01510 if ( count == 0 ) { // no " " -> assume one single file 01511 u.setFileName( line ); 01512 if ( u.isValid() ) 01513 urls.append( u ); 01514 01515 return urls; 01516 } 01517 01518 if ( (count % 2) == 1 ) { // odd number of " -> error 01519 TQWidget *that = const_cast<KFileDialog *>(this); 01520 KMessageBox::sorry(that, i18n("The requested filenames\n" 01521 "%1\n" 01522 "do not appear to be valid;\n" 01523 "make sure every filename is enclosed in double quotes.").arg(line), 01524 i18n("Filename Error")); 01525 return urls; 01526 } 01527 01528 int start = 0; 01529 int index1 = -1, index2 = -1; 01530 while ( true ) { 01531 index1 = line.find( '"', start ); 01532 index2 = line.find( '"', index1 + 1 ); 01533 01534 if ( index1 < 0 ) 01535 break; 01536 01537 // get everything between the " " 01538 name = line.mid( index1 + 1, index2 - index1 - 1 ); 01539 u.setFileName( name ); 01540 if ( u.isValid() ) 01541 urls.append( u ); 01542 01543 start = index2 + 1; 01544 } 01545 return urls; 01546 } 01547 01548 01549 TQString KFileDialog::selectedFile() const 01550 { 01551 if ( result() == TQDialog::Accepted ) 01552 { 01553 KURL url = TDEIO::NetAccess::mostLocalURL(d->url,topLevelWidget()); 01554 if (url.isLocalFile()) 01555 return url.path(); 01556 else { 01557 KMessageBox::sorry( d->mainWidget, 01558 i18n("You can only select local files."), 01559 i18n("Remote Files Not Accepted") ); 01560 } 01561 } 01562 return TQString::null; 01563 } 01564 01565 TQStringList KFileDialog::selectedFiles() const 01566 { 01567 TQStringList list; 01568 KURL url; 01569 01570 if ( result() == TQDialog::Accepted ) { 01571 if ( (ops->mode() & KFile::Files) == KFile::Files ) { 01572 KURL::List urls = parseSelectedURLs(); 01573 TQValueListConstIterator<KURL> it = urls.begin(); 01574 while ( it != urls.end() ) { 01575 url = TDEIO::NetAccess::mostLocalURL(*it,topLevelWidget()); 01576 if ( url.isLocalFile() ) 01577 list.append( url.path() ); 01578 ++it; 01579 } 01580 } 01581 01582 else { // single-selection mode 01583 if ( d->url.isLocalFile() ) 01584 list.append( d->url.path() ); 01585 } 01586 } 01587 01588 return list; 01589 } 01590 01591 KURL KFileDialog::baseURL() const 01592 { 01593 return ops->url(); 01594 } 01595 01596 TQString KFileDialog::getSaveFileName(const TQString& dir, const TQString& filter, 01597 TQWidget *parent, 01598 const TQString& caption) 01599 { 01600 bool specialDir = dir.at(0) == ':'; 01601 KFileDialog dlg( specialDir ? dir : TQString::null, filter, parent, "filedialog", true); 01602 if ( !specialDir ) 01603 dlg.setSelection( dir ); // may also be a filename 01604 01605 dlg.setOperationMode( Saving ); 01606 dlg.setCaption(caption.isNull() ? i18n("Save As") : caption); 01607 01608 dlg.exec(); 01609 01610 TQString filename = dlg.selectedFile(); 01611 if (!filename.isEmpty()) 01612 TDERecentDocument::add(filename); 01613 01614 return filename; 01615 } 01616 01617 TQString KFileDialog::getSaveFileNameWId(const TQString& dir, const TQString& filter, 01618 WId parent_id, 01619 const TQString& caption) 01620 { 01621 bool specialDir = dir.at(0) == ':'; 01622 TQWidget* parent = TQT_TQWIDGET(TQWidget::find( parent_id )); 01623 KFileDialog dlg( specialDir ? dir : TQString::null, filter, parent, "filedialog", true); 01624 #ifdef Q_WS_X11 01625 if( parent == NULL && parent_id != 0 ) 01626 XSetTransientForHint(tqt_xdisplay(), dlg.winId(), parent_id); 01627 #else 01628 // TODO 01629 #endif 01630 01631 if ( !specialDir ) 01632 dlg.setSelection( dir ); // may also be a filename 01633 01634 dlg.setOperationMode( KFileDialog::Saving); 01635 dlg.setCaption(caption.isNull() ? i18n("Save As") : caption); 01636 01637 dlg.exec(); 01638 01639 TQString filename = dlg.selectedFile(); 01640 if (!filename.isEmpty()) 01641 TDERecentDocument::add(filename); 01642 01643 return filename; 01644 } 01645 01646 KURL KFileDialog::getSaveURL(const TQString& dir, const TQString& filter, 01647 TQWidget *parent, const TQString& caption) 01648 { 01649 bool specialDir = dir.at(0) == ':'; 01650 KFileDialog dlg(specialDir ? dir : TQString::null, filter, parent, "filedialog", true); 01651 if ( !specialDir ) 01652 dlg.setSelection( dir ); // may also be a filename 01653 01654 dlg.setCaption(caption.isNull() ? i18n("Save As") : caption); 01655 dlg.setOperationMode( Saving ); 01656 01657 dlg.exec(); 01658 01659 KURL url = dlg.selectedURL(); 01660 if (url.isValid()) 01661 TDERecentDocument::add( url ); 01662 01663 return url; 01664 } 01665 01666 void KFileDialog::show() 01667 { 01668 if ( !d->hasView ) { // delayed view-creation 01669 ops->setView(KFile::Default); 01670 ops->clearHistory(); 01671 d->hasView = true; 01672 } 01673 01674 KDialogBase::show(); 01675 } 01676 01677 void KFileDialog::setMode( KFile::Mode m ) 01678 { 01679 ops->setMode(m); 01680 if ( ops->dirOnlyMode() ) { 01681 filterWidget->setDefaultFilter( i18n("*|All Folders") ); 01682 } 01683 else { 01684 filterWidget->setDefaultFilter( i18n("*|All Files") ); 01685 } 01686 01687 updateAutoSelectExtension (); 01688 } 01689 01690 void KFileDialog::setMode( unsigned int m ) 01691 { 01692 setMode(static_cast<KFile::Mode>( m )); 01693 } 01694 01695 KFile::Mode KFileDialog::mode() const 01696 { 01697 return ops->mode(); 01698 } 01699 01700 01701 void KFileDialog::readConfig( TDEConfig *kc, const TQString& group ) 01702 { 01703 if ( !kc ) 01704 return; 01705 01706 TQString oldGroup = kc->group(); 01707 if ( !group.isEmpty() ) 01708 kc->setGroup( group ); 01709 01710 ops->readConfig( kc, group ); 01711 01712 KURLComboBox *combo = d->pathCombo; 01713 combo->setURLs( kc->readPathListEntry( RecentURLs ), KURLComboBox::RemoveTop ); 01714 combo->setMaxItems( kc->readNumEntry( RecentURLsNumber, 01715 DefaultRecentURLsNumber ) ); 01716 combo->setURL( ops->url() ); 01717 autoDirectoryFollowing = kc->readBoolEntry( AutoDirectoryFollowing, 01718 DefaultDirectoryFollowing ); 01719 01720 TDEGlobalSettings::Completion cm = (TDEGlobalSettings::Completion) 01721 kc->readNumEntry( PathComboCompletionMode, 01722 TDEGlobalSettings::completionMode() ); 01723 if ( cm != TDEGlobalSettings::completionMode() ) 01724 combo->setCompletionMode( cm ); 01725 01726 cm = (TDEGlobalSettings::Completion) 01727 kc->readNumEntry( LocationComboCompletionMode, 01728 TDEGlobalSettings::completionMode() ); 01729 if ( cm != TDEGlobalSettings::completionMode() ) 01730 locationEdit->setCompletionMode( cm ); 01731 01732 // show or don't show the speedbar 01733 toggleSpeedbar( kc->readBoolEntry(ShowSpeedbar, true) ); 01734 01735 // show or don't show the bookmarks 01736 toggleBookmarks( kc->readBoolEntry(ShowBookmarks, false) ); 01737 01738 // does the user want Automatically Select Extension? 01739 d->autoSelectExtChecked = kc->readBoolEntry (AutoSelectExtChecked, DefaultAutoSelectExtChecked); 01740 updateAutoSelectExtension (); 01741 01742 int w1 = minimumSize().width(); 01743 int w2 = toolbar->sizeHint().width() + 10; 01744 if (w1 < w2) 01745 setMinimumWidth(w2); 01746 01747 TQSize size = configDialogSize( group ); 01748 resize( size ); 01749 kc->setGroup( oldGroup ); 01750 } 01751 01752 void KFileDialog::writeConfig( TDEConfig *kc, const TQString& group ) 01753 { 01754 if ( !kc ) 01755 return; 01756 01757 TQString oldGroup = kc->group(); 01758 if ( !group.isEmpty() ) 01759 kc->setGroup( group ); 01760 01761 kc->writePathEntry( RecentURLs, d->pathCombo->urls() ); 01762 saveDialogSize( group, true ); 01763 kc->writeEntry( PathComboCompletionMode, static_cast<int>(d->pathCombo->completionMode()) ); 01764 kc->writeEntry( LocationComboCompletionMode, static_cast<int>(locationEdit->completionMode()) ); 01765 kc->writeEntry( ShowSpeedbar, d->urlBar && !d->urlBar->isHidden() ); 01766 kc->writeEntry( ShowBookmarks, d->bookmarkHandler != 0 ); 01767 kc->writeEntry( AutoSelectExtChecked, d->autoSelectExtChecked ); 01768 01769 ops->writeConfig( kc, group ); 01770 kc->setGroup( oldGroup ); 01771 } 01772 01773 01774 void KFileDialog::readRecentFiles( TDEConfig *kc ) 01775 { 01776 TQString oldGroup = kc->group(); 01777 kc->setGroup( ConfigGroup ); 01778 01779 locationEdit->setMaxItems( kc->readNumEntry( RecentFilesNumber, 01780 DefaultRecentURLsNumber ) ); 01781 locationEdit->setURLs( kc->readPathListEntry( RecentFiles ), 01782 KURLComboBox::RemoveBottom ); 01783 locationEdit->insertItem( TQString::null, 0 ); // dummy item without pixmap 01784 locationEdit->setCurrentItem( 0 ); 01785 01786 kc->setGroup( oldGroup ); 01787 } 01788 01789 void KFileDialog::saveRecentFiles( TDEConfig *kc ) 01790 { 01791 TQString oldGroup = kc->group(); 01792 kc->setGroup( ConfigGroup ); 01793 01794 kc->writePathEntry( RecentFiles, locationEdit->urls() ); 01795 01796 kc->setGroup( oldGroup ); 01797 } 01798 01799 KPushButton * KFileDialog::okButton() const 01800 { 01801 return d->okButton; 01802 } 01803 01804 KPushButton * KFileDialog::cancelButton() const 01805 { 01806 return d->cancelButton; 01807 } 01808 01809 KURLBar * KFileDialog::speedBar() 01810 { 01811 return d->urlBar; 01812 } 01813 01814 void KFileDialog::slotCancel() 01815 { 01816 ops->close(); 01817 KDialogBase::slotCancel(); 01818 01819 TDEConfig *config = TDEGlobal::config(); 01820 config->setForceGlobal( true ); 01821 writeConfig( config, ConfigGroup ); 01822 config->setForceGlobal( false ); 01823 } 01824 01825 void KFileDialog::setKeepLocation( bool keep ) 01826 { 01827 d->keepLocation = keep; 01828 } 01829 01830 bool KFileDialog::keepsLocation() const 01831 { 01832 return d->keepLocation; 01833 } 01834 01835 void KFileDialog::setOperationMode( OperationMode mode ) 01836 { 01837 d->operationMode = mode; 01838 d->keepLocation = (mode == Saving); 01839 filterWidget->setEditable( !d->hasDefaultFilter || mode != Saving ); 01840 if ( mode == Opening ) 01841 d->okButton->setGuiItem( KGuiItem( i18n("&Open"), "document-open") ); 01842 else if ( mode == Saving ) { 01843 d->okButton->setGuiItem( KStdGuiItem::save() ); 01844 setNonExtSelection(); 01845 } 01846 else 01847 d->okButton->setGuiItem( KStdGuiItem::ok() ); 01848 updateLocationWhatsThis (); 01849 updateAutoSelectExtension (); 01850 } 01851 01852 KFileDialog::OperationMode KFileDialog::operationMode() const 01853 { 01854 return d->operationMode; 01855 } 01856 01857 void KFileDialog::slotAutoSelectExtClicked() 01858 { 01859 kdDebug (tdefile_area) << "slotAutoSelectExtClicked(): " 01860 << d->autoSelectExtCheckBox->isChecked () << endl; 01861 01862 // whether the _user_ wants it on/off 01863 d->autoSelectExtChecked = d->autoSelectExtCheckBox->isChecked (); 01864 01865 // update the current filename's extension 01866 updateLocationEditExtension (d->extension /* extension hasn't changed */); 01867 } 01868 01869 static TQString getExtensionFromPatternList (const TQStringList &patternList) 01870 { 01871 TQString ret; 01872 kdDebug (tdefile_area) << "\tgetExtension " << patternList << endl; 01873 01874 TQStringList::ConstIterator patternListEnd = patternList.end (); 01875 for (TQStringList::ConstIterator it = patternList.begin (); 01876 it != patternListEnd; 01877 it++) 01878 { 01879 kdDebug (tdefile_area) << "\t\ttry: \'" << (*it) << "\'" << endl; 01880 01881 // is this pattern like "*.BMP" rather than useless things like: 01882 // 01883 // README 01884 // *. 01885 // *.* 01886 // *.JP*G 01887 // *.JP? 01888 if ((*it).startsWith ("*.") && 01889 (*it).length () > 2 && 01890 (*it).find ('*', 2) < 0 && (*it).find ('?', 2) < 0) 01891 { 01892 ret = (*it).mid (1); 01893 break; 01894 } 01895 } 01896 01897 return ret; 01898 } 01899 01900 static TQString stripUndisplayable (const TQString &string) 01901 { 01902 TQString ret = string; 01903 01904 ret.remove (':'); 01905 ret.remove ('&'); 01906 01907 return ret; 01908 } 01909 01910 01911 TQString KFileDialog::currentFilterExtension (void) 01912 { 01913 return d->extension; 01914 } 01915 01916 void KFileDialog::updateAutoSelectExtension (void) 01917 { 01918 if (!d->autoSelectExtCheckBox) return; 01919 01920 // 01921 // Figure out an extension for the Automatically Select Extension thing 01922 // (some Windows users apparently don't know what to do when confronted 01923 // with a text file called "COPYING" but do know what to do with 01924 // COPYING.txt ...) 01925 // 01926 01927 kdDebug (tdefile_area) << "Figure out an extension: " << endl; 01928 TQString lastExtension = d->extension; 01929 d->extension = TQString::null; 01930 01931 // Automatically Select Extension is only valid if the user is _saving_ a _file_ 01932 if ((operationMode () == Saving) && (mode () & KFile::File)) 01933 { 01934 // 01935 // Get an extension from the filter 01936 // 01937 01938 TQString filter = currentFilter (); 01939 if (!filter.isEmpty ()) 01940 { 01941 // e.g. "*.cpp" 01942 if (filter.find ('/') < 0) 01943 { 01944 d->extension = getExtensionFromPatternList (TQStringList::split (" ", filter)).lower (); 01945 kdDebug (tdefile_area) << "\tsetFilter-style: pattern ext=\'" 01946 << d->extension << "\'" << endl; 01947 } 01948 // e.g. "text/html" 01949 else 01950 { 01951 KMimeType::Ptr mime = KMimeType::mimeType (filter); 01952 01953 // first try X-TDE-NativeExtension 01954 TQString nativeExtension = mime->property ("X-TDE-NativeExtension").toString (); 01955 if (nativeExtension.at (0) == '.') 01956 { 01957 d->extension = nativeExtension.lower (); 01958 kdDebug (tdefile_area) << "\tsetMimeFilter-style: native ext=\'" 01959 << d->extension << "\'" << endl; 01960 } 01961 01962 // no X-TDE-NativeExtension 01963 if (d->extension.isEmpty ()) 01964 { 01965 d->extension = getExtensionFromPatternList (mime->patterns ()).lower (); 01966 kdDebug (tdefile_area) << "\tsetMimeFilter-style: pattern ext=\'" 01967 << d->extension << "\'" << endl; 01968 } 01969 } 01970 } 01971 01972 01973 // 01974 // GUI: checkbox 01975 // 01976 01977 TQString whatsThisExtension; 01978 if (!d->extension.isEmpty ()) 01979 { 01980 // remember: sync any changes to the string with below 01981 d->autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension (%1)").arg (d->extension)); 01982 whatsThisExtension = i18n ("the extension <b>%1</b>").arg (d->extension); 01983 01984 d->autoSelectExtCheckBox->setEnabled (true); 01985 d->autoSelectExtCheckBox->setChecked (d->autoSelectExtChecked); 01986 } 01987 else 01988 { 01989 // remember: sync any changes to the string with above 01990 d->autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension")); 01991 whatsThisExtension = i18n ("a suitable extension"); 01992 01993 d->autoSelectExtCheckBox->setChecked (false); 01994 d->autoSelectExtCheckBox->setEnabled (false); 01995 } 01996 01997 const TQString locationLabelText = stripUndisplayable (d->locationLabel->text ()); 01998 const TQString filterLabelText = stripUndisplayable (d->filterLabel->text ()); 01999 TQWhatsThis::add (d->autoSelectExtCheckBox, 02000 "<qt>" + 02001 i18n ( 02002 "This option enables some convenient features for " 02003 "saving files with extensions:<br>" 02004 "<ol>" 02005 "<li>Any extension specified in the <b>%1</b> text " 02006 "area will be updated if you change the file type " 02007 "to save in.<br>" 02008 "<br></li>" 02009 "<li>If no extension is specified in the <b>%2</b> " 02010 "text area when you click " 02011 "<b>Save</b>, %3 will be added to the end of the " 02012 "filename (if the filename does not already exist). " 02013 "This extension is based on the file type that you " 02014 "have chosen to save in.<br>" 02015 "<br>" 02016 "If you do not want TDE to supply an extension for the " 02017 "filename, you can either turn this option off or you " 02018 "can suppress it by adding a period (.) to the end of " 02019 "the filename (the period will be automatically " 02020 "removed)." 02021 "</li>" 02022 "</ol>" 02023 "If unsure, keep this option enabled as it makes your " 02024 "files more manageable." 02025 ) 02026 .arg (locationLabelText) 02027 .arg (locationLabelText) 02028 .arg (whatsThisExtension) 02029 + "</qt>" 02030 ); 02031 02032 d->autoSelectExtCheckBox->show (); 02033 02034 02035 // update the current filename's extension 02036 updateLocationEditExtension (lastExtension); 02037 } 02038 // Automatically Select Extension not valid 02039 else 02040 { 02041 d->autoSelectExtCheckBox->setChecked (false); 02042 d->autoSelectExtCheckBox->hide (); 02043 } 02044 } 02045 02046 // Updates the extension of the filename specified in locationEdit if the 02047 // Automatically Select Extension feature is enabled. 02048 // (this prevents you from accidently saving "file.kwd" as RTF, for example) 02049 void KFileDialog::updateLocationEditExtension (const TQString &lastExtension) 02050 { 02051 if (!d->autoSelectExtCheckBox->isChecked () || d->extension.isEmpty ()) 02052 return; 02053 02054 TQString urlStr = locationEdit->currentText (); 02055 if (urlStr.isEmpty ()) 02056 return; 02057 02058 KURL url = getCompleteURL (urlStr); 02059 kdDebug (tdefile_area) << "updateLocationEditExtension (" << url << ")" << endl; 02060 02061 const int fileNameOffset = urlStr.findRev ('/') + 1; 02062 TQString fileName = urlStr.mid (fileNameOffset); 02063 02064 const int dot = fileName.findRev ('.'); 02065 const int len = fileName.length (); 02066 if (dot > 0 && // has an extension already and it's not a hidden file 02067 // like ".hidden" (but we do accept ".hidden.ext") 02068 dot != len - 1 // and not deliberately suppressing extension 02069 ) 02070 { 02071 // exists? 02072 TDEIO::UDSEntry t; 02073 if (TDEIO::NetAccess::stat (url, t, topLevelWidget())) 02074 { 02075 kdDebug (tdefile_area) << "\tfile exists" << endl; 02076 02077 if (isDirectory (t)) 02078 { 02079 kdDebug (tdefile_area) << "\tisDir - won't alter extension" << endl; 02080 return; 02081 } 02082 02083 // --- fall through --- 02084 } 02085 02086 02087 // 02088 // try to get rid of the current extension 02089 // 02090 02091 // catch "double extensions" like ".tar.gz" 02092 if (lastExtension.length () && fileName.endsWith (lastExtension)) 02093 fileName.truncate (len - lastExtension.length ()); 02094 // can only handle "single extensions" 02095 else 02096 fileName.truncate (dot); 02097 02098 // add extension 02099 const TQString newText = urlStr.left (fileNameOffset) + fileName + d->extension; 02100 if ( newText != locationEdit->currentText() ) 02101 { 02102 locationEdit->setCurrentText (urlStr.left (fileNameOffset) + fileName + d->extension); 02103 locationEdit->lineEdit()->setEdited (true); 02104 } 02105 } 02106 } 02107 02108 // Updates the filter if the extension of the filename specified in locationEdit is changed 02109 // (this prevents you from accidently saving "file.kwd" as RTF, for example) 02110 void KFileDialog::updateFilter () 02111 { 02112 if ((operationMode() == Saving) && (mode() & KFile::File) ) { 02113 const TQString urlStr = locationEdit->currentText (); 02114 if (urlStr.isEmpty ()) 02115 return; 02116 02117 KMimeType::Ptr mime = KMimeType::findByPath(urlStr, 0, true); 02118 if (mime && mime->name() != KMimeType::defaultMimeType()) { 02119 if (filterWidget->currentFilter() != mime->name() && 02120 filterWidget->filters.findIndex(mime->name()) != -1) { 02121 filterWidget->setCurrentFilter(mime->name()); 02122 } 02123 } 02124 } 02125 } 02126 02127 // applies only to a file that doesn't already exist 02128 void KFileDialog::appendExtension (KURL &url) 02129 { 02130 if (!d->autoSelectExtCheckBox->isChecked () || d->extension.isEmpty ()) 02131 return; 02132 02133 TQString fileName = url.fileName (); 02134 if (fileName.isEmpty ()) 02135 return; 02136 02137 kdDebug (tdefile_area) << "appendExtension(" << url << ")" << endl; 02138 02139 const int len = fileName.length (); 02140 const int dot = fileName.findRev ('.'); 02141 02142 const bool suppressExtension = (dot == len - 1); 02143 const bool unspecifiedExtension = (dot <= 0); 02144 02145 // don't TDEIO::NetAccess::Stat if unnecessary 02146 if (!(suppressExtension || unspecifiedExtension)) 02147 return; 02148 02149 // exists? 02150 TDEIO::UDSEntry t; 02151 if (TDEIO::NetAccess::stat (url, t, topLevelWidget())) 02152 { 02153 kdDebug (tdefile_area) << "\tfile exists - won't append extension" << endl; 02154 return; 02155 } 02156 02157 // suppress automatically append extension? 02158 if (suppressExtension) 02159 { 02160 // 02161 // Strip trailing dot 02162 // This allows lazy people to have autoSelectExtCheckBox->isChecked 02163 // but don't want a file extension to be appended 02164 // e.g. "README." will make a file called "README" 02165 // 02166 // If you really want a name like "README.", then type "README.." 02167 // and the trailing dot will be removed (or just stop being lazy and 02168 // turn off this feature so that you can type "README.") 02169 // 02170 kdDebug (tdefile_area) << "\tstrip trailing dot" << endl; 02171 url.setFileName (fileName.left (len - 1)); 02172 } 02173 // evilmatically append extension :) if the user hasn't specified one 02174 else if (unspecifiedExtension) 02175 { 02176 kdDebug (tdefile_area) << "\tappending extension \'" << d->extension << "\'..." << endl; 02177 url.setFileName (fileName + d->extension); 02178 kdDebug (tdefile_area) << "\tsaving as \'" << url << "\'" << endl; 02179 } 02180 } 02181 02182 02183 // adds the selected files/urls to 'recent documents' 02184 void KFileDialog::addToRecentDocuments() 02185 { 02186 int m = ops->mode(); 02187 02188 if ( m & KFile::LocalOnly ) { 02189 TQStringList files = selectedFiles(); 02190 TQStringList::ConstIterator it = files.begin(); 02191 for ( ; it != files.end(); ++it ) 02192 TDERecentDocument::add( *it ); 02193 } 02194 02195 else { // urls 02196 KURL::List urls = selectedURLs(); 02197 KURL::List::ConstIterator it = urls.begin(); 02198 for ( ; it != urls.end(); ++it ) { 02199 if ( (*it).isValid() ) 02200 TDERecentDocument::add( *it ); 02201 } 02202 } 02203 } 02204 02205 TDEActionCollection * KFileDialog::actionCollection() const 02206 { 02207 return ops->actionCollection(); 02208 } 02209 02210 void KFileDialog::keyPressEvent( TQKeyEvent *e ) 02211 { 02212 if ( e->key() == Key_Escape ) 02213 { 02214 e->accept(); 02215 d->cancelButton->animateClick(); 02216 } 02217 else 02218 KDialogBase::keyPressEvent( e ); 02219 } 02220 02221 void KFileDialog::toggleSpeedbar( bool show ) 02222 { 02223 if ( show ) 02224 { 02225 if ( !d->urlBar ) 02226 initSpeedbar(); 02227 02228 d->urlBar->show(); 02229 02230 // check to see if they have a home item defined, if not show the home button 02231 KURLBarItem *urlItem = static_cast<KURLBarItem*>( d->urlBar->listBox()->firstItem() ); 02232 KURL homeURL; 02233 homeURL.setPath( TQDir::homeDirPath() ); 02234 while ( urlItem ) 02235 { 02236 if ( homeURL.equals( urlItem->url(), true ) ) 02237 { 02238 ops->actionCollection()->action( "home" )->unplug( toolbar ); 02239 break; 02240 } 02241 02242 urlItem = static_cast<KURLBarItem*>( urlItem->next() ); 02243 } 02244 } 02245 else 02246 { 02247 if (d->urlBar) 02248 d->urlBar->hide(); 02249 02250 if ( !ops->actionCollection()->action( "home" )->isPlugged( toolbar ) ) 02251 ops->actionCollection()->action( "home" )->plug( toolbar, 3 ); 02252 } 02253 02254 static_cast<TDEToggleAction *>(actionCollection()->action("toggleSpeedbar"))->setChecked( show ); 02255 } 02256 02257 void KFileDialog::toggleBookmarks(bool show) 02258 { 02259 if (show) 02260 { 02261 if (d->bookmarkHandler) 02262 { 02263 return; 02264 } 02265 02266 d->bookmarkHandler = new KFileBookmarkHandler( this ); 02267 connect( d->bookmarkHandler, TQT_SIGNAL( openURL( const TQString& )), 02268 TQT_SLOT( enterURL( const TQString& ))); 02269 02270 toolbar->insertButton(TQString::fromLatin1("bookmark"), 02271 (int)HOTLIST_BUTTON, true, 02272 i18n("Bookmarks"), 5); 02273 toolbar->getButton(HOTLIST_BUTTON)->setPopup(d->bookmarkHandler->menu(), 02274 true); 02275 TQWhatsThis::add(toolbar->getButton(HOTLIST_BUTTON), 02276 i18n("<qt>This button allows you to bookmark specific locations. " 02277 "Click on this button to open the bookmark menu where you may add, " 02278 "edit or select a bookmark.<p>" 02279 "These bookmarks are specific to the file dialog, but otherwise operate " 02280 "like bookmarks elsewhere in TDE.</qt>")); 02281 } 02282 else if (d->bookmarkHandler) 02283 { 02284 delete d->bookmarkHandler; 02285 d->bookmarkHandler = 0; 02286 toolbar->removeItem(HOTLIST_BUTTON); 02287 } 02288 02289 static_cast<TDEToggleAction *>(actionCollection()->action("toggleBookmarks"))->setChecked( show ); 02290 } 02291 02292 int KFileDialog::pathComboIndex() 02293 { 02294 return d->m_pathComboIndex; 02295 } 02296 02297 // static 02298 void KFileDialog::initStatic() 02299 { 02300 if ( lastDirectory ) 02301 return; 02302 02303 lastDirectory = ldd.setObject(lastDirectory, new KURL()); 02304 } 02305 02306 // static 02307 KURL KFileDialog::getStartURL( const TQString& startDir, 02308 TQString& recentDirClass ) 02309 { 02310 initStatic(); 02311 02312 recentDirClass = TQString::null; 02313 KURL ret; 02314 02315 bool useDefaultStartDir = startDir.isEmpty(); 02316 if ( !useDefaultStartDir ) 02317 { 02318 if (startDir[0] == ':') 02319 { 02320 recentDirClass = startDir; 02321 ret = KURL::fromPathOrURL( TDERecentDirs::dir(recentDirClass) ); 02322 } 02323 else 02324 { 02325 ret = TDECmdLineArgs::makeURL( TQFile::encodeName(startDir) ); 02326 // If we won't be able to list it (e.g. http), then use default 02327 if ( !KProtocolInfo::supportsListing( ret ) ) 02328 useDefaultStartDir = true; 02329 } 02330 } 02331 02332 if ( useDefaultStartDir ) 02333 { 02334 if (lastDirectory->isEmpty()) { 02335 lastDirectory->setPath(TDEGlobalSettings::documentPath()); 02336 KURL home; 02337 home.setPath( TQDir::homeDirPath() ); 02338 // if there is no docpath set (== home dir), we prefer the current 02339 // directory over it. We also prefer the homedir when our CWD is 02340 // different from our homedirectory or when the document dir 02341 // does not exist 02342 if ( lastDirectory->path(+1) == home.path(+1) || 02343 TQDir::currentDirPath() != TQDir::homeDirPath() || 02344 !TQDir(lastDirectory->path(+1)).exists() ) 02345 lastDirectory->setPath(TQDir::currentDirPath()); 02346 } 02347 ret = *lastDirectory; 02348 } 02349 02350 return ret; 02351 } 02352 02353 void KFileDialog::setStartDir( const KURL& directory ) 02354 { 02355 initStatic(); 02356 if ( directory.isValid() ) 02357 *lastDirectory = directory; 02358 } 02359 02360 void KFileDialog::setNonExtSelection() 02361 { 02362 // Enhanced rename: Don't highlight the file extension. 02363 TQString pattern, filename = locationEdit->currentText().stripWhiteSpace(); 02364 KServiceTypeFactory::self()->findFromPattern( filename, &pattern ); 02365 02366 if ( !pattern.isEmpty() && pattern.at( 0 ) == '*' && pattern.find( '*' , 1 ) == -1 ) 02367 locationEdit->lineEdit()->setSelection( 0, filename.length() - pattern.stripWhiteSpace().length()+1 ); 02368 else 02369 { 02370 int lastDot = filename.findRev( '.' ); 02371 if ( lastDot > 0 ) 02372 locationEdit->lineEdit()->setSelection( 0, lastDot ); 02373 } 02374 } 02375 02376 void KFileDialog::virtual_hook( int id, void* data ) 02377 { KDialogBase::virtual_hook( id, data ); } 02378 02379 02380 #include "tdefiledialog.moc"