kdiroperator.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999,2000 Stephan Kulow <coolo@kde.org> 00003 1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include <unistd.h> 00022 00023 #include <qdir.h> 00024 #include <qapplication.h> 00025 #include <qdialog.h> 00026 #include <qlabel.h> 00027 #include <qlayout.h> 00028 #include <qpushbutton.h> 00029 #include <qpopupmenu.h> 00030 #include <qregexp.h> 00031 #include <qtimer.h> 00032 #include <qvbox.h> 00033 00034 #include <kaction.h> 00035 #include <kapplication.h> 00036 #include <kdebug.h> 00037 #include <kdialog.h> 00038 #include <kdialogbase.h> 00039 #include <kdirlister.h> 00040 #include <kinputdialog.h> 00041 #include <klocale.h> 00042 #include <kmessagebox.h> 00043 #include <kpopupmenu.h> 00044 #include <kprogress.h> 00045 #include <kstdaction.h> 00046 #include <kio/job.h> 00047 #include <kio/jobclasses.h> 00048 #include <kio/netaccess.h> 00049 #include <kio/previewjob.h> 00050 #include <kio/renamedlg.h> 00051 #include <kpropertiesdialog.h> 00052 #include <kservicetypefactory.h> 00053 #include <kstdaccel.h> 00054 #include <kde_file.h> 00055 00056 #include "config-kfile.h" 00057 #include "kcombiview.h" 00058 #include "kdiroperator.h" 00059 #include "kfiledetailview.h" 00060 #include "kfileiconview.h" 00061 #include "kfilepreview.h" 00062 #include "kfileview.h" 00063 #include "kfileitem.h" 00064 #include "kfilemetapreview.h" 00065 00066 00067 template class QPtrStack<KURL>; 00068 template class QDict<KFileItem>; 00069 00070 00071 class KDirOperator::KDirOperatorPrivate 00072 { 00073 public: 00074 KDirOperatorPrivate() { 00075 onlyDoubleClickSelectsFiles = false; 00076 progressDelayTimer = 0L; 00077 dirHighlighting = false; 00078 config = 0L; 00079 dropOptions = 0; 00080 } 00081 00082 ~KDirOperatorPrivate() { 00083 delete progressDelayTimer; 00084 } 00085 00086 bool dirHighlighting; 00087 QString lastURL; // used for highlighting a directory on cdUp 00088 bool onlyDoubleClickSelectsFiles; 00089 QTimer *progressDelayTimer; 00090 KActionSeparator *viewActionSeparator; 00091 int dropOptions; 00092 00093 KConfig *config; 00094 QString configGroup; 00095 }; 00096 00097 KDirOperator::KDirOperator(const KURL& _url, 00098 QWidget *parent, const char* _name) 00099 : QWidget(parent, _name), 00100 dir(0), 00101 m_fileView(0), 00102 progress(0) 00103 { 00104 myPreview = 0L; 00105 myMode = KFile::File; 00106 m_viewKind = KFile::Simple; 00107 mySorting = static_cast<QDir::SortSpec>(QDir::Name | QDir::DirsFirst); 00108 d = new KDirOperatorPrivate; 00109 00110 if (_url.isEmpty()) { // no dir specified -> current dir 00111 QString strPath = QDir::currentDirPath(); 00112 strPath.append('/'); 00113 currUrl = KURL(); 00114 currUrl.setProtocol(QString::fromLatin1("file")); 00115 currUrl.setPath(strPath); 00116 } 00117 else { 00118 currUrl = _url; 00119 if ( currUrl.protocol().isEmpty() ) 00120 currUrl.setProtocol(QString::fromLatin1("file")); 00121 00122 currUrl.addPath("/"); // make sure we have a trailing slash! 00123 } 00124 00125 setDirLister( new KDirLister( true ) ); 00126 00127 connect(&myCompletion, SIGNAL(match(const QString&)), 00128 SLOT(slotCompletionMatch(const QString&))); 00129 00130 progress = new KProgress(this, "progress"); 00131 progress->adjustSize(); 00132 progress->move(2, height() - progress->height() -2); 00133 00134 d->progressDelayTimer = new QTimer( this, "progress delay timer" ); 00135 connect( d->progressDelayTimer, SIGNAL( timeout() ), 00136 SLOT( slotShowProgress() )); 00137 00138 myCompleteListDirty = false; 00139 00140 backStack.setAutoDelete( true ); 00141 forwardStack.setAutoDelete( true ); 00142 00143 // action stuff 00144 setupActions(); 00145 setupMenu(); 00146 00147 setFocusPolicy(QWidget::WheelFocus); 00148 } 00149 00150 KDirOperator::~KDirOperator() 00151 { 00152 resetCursor(); 00153 if ( m_fileView ) 00154 { 00155 if ( d->config ) 00156 m_fileView->writeConfig( d->config, d->configGroup ); 00157 00158 delete m_fileView; 00159 m_fileView = 0L; 00160 } 00161 00162 delete myPreview; 00163 delete dir; 00164 delete d; 00165 } 00166 00167 00168 void KDirOperator::setSorting( QDir::SortSpec spec ) 00169 { 00170 if ( m_fileView ) 00171 m_fileView->setSorting( spec ); 00172 mySorting = spec; 00173 updateSortActions(); 00174 } 00175 00176 void KDirOperator::resetCursor() 00177 { 00178 QApplication::restoreOverrideCursor(); 00179 progress->hide(); 00180 } 00181 00182 void KDirOperator::insertViewDependentActions() 00183 { 00184 // If we have a new view actionCollection(), insert its actions 00185 // into viewActionMenu. 00186 00187 if( !m_fileView ) 00188 return; 00189 00190 if ( (viewActionMenu->popupMenu()->count() == 0) || // Not yet initialized or... 00191 (viewActionCollection != m_fileView->actionCollection()) ) // ...changed since. 00192 { 00193 if (viewActionCollection) 00194 { 00195 disconnect( viewActionCollection, SIGNAL( inserted( KAction * )), 00196 this, SLOT( slotViewActionAdded( KAction * ))); 00197 disconnect( viewActionCollection, SIGNAL( removed( KAction * )), 00198 this, SLOT( slotViewActionRemoved( KAction * ))); 00199 } 00200 00201 viewActionMenu->popupMenu()->clear(); 00202 // viewActionMenu->insert( shortAction ); 00203 // viewActionMenu->insert( detailedAction ); 00204 // viewActionMenu->insert( actionSeparator ); 00205 viewActionMenu->insert( myActionCollection->action( "short view" ) ); 00206 viewActionMenu->insert( myActionCollection->action( "detailed view" ) ); 00207 viewActionMenu->insert( actionSeparator ); 00208 viewActionMenu->insert( showHiddenAction ); 00209 // viewActionMenu->insert( myActionCollection->action( "single" )); 00210 viewActionMenu->insert( separateDirsAction ); 00211 // Warning: adjust slotViewActionAdded() and slotViewActionRemoved() 00212 // when you add/remove actions here! 00213 00214 viewActionCollection = m_fileView->actionCollection(); 00215 if (!viewActionCollection) 00216 return; 00217 00218 if ( !viewActionCollection->isEmpty() ) 00219 { 00220 viewActionMenu->insert( d->viewActionSeparator ); 00221 00222 // first insert the normal actions, then the grouped ones 00223 QStringList groups = viewActionCollection->groups(); 00224 groups.prepend( QString::null ); // actions without group 00225 QStringList::ConstIterator git = groups.begin(); 00226 KActionPtrList list; 00227 KAction *sep = actionCollection()->action("separator"); 00228 for ( ; git != groups.end(); ++git ) 00229 { 00230 if ( git != groups.begin() ) 00231 viewActionMenu->insert( sep ); 00232 00233 list = viewActionCollection->actions( *git ); 00234 KActionPtrList::ConstIterator it = list.begin(); 00235 for ( ; it != list.end(); ++it ) 00236 viewActionMenu->insert( *it ); 00237 } 00238 } 00239 00240 connect( viewActionCollection, SIGNAL( inserted( KAction * )), 00241 SLOT( slotViewActionAdded( KAction * ))); 00242 connect( viewActionCollection, SIGNAL( removed( KAction * )), 00243 SLOT( slotViewActionRemoved( KAction * ))); 00244 } 00245 } 00246 00247 void KDirOperator::activatedMenu( const KFileItem *, const QPoint& pos ) 00248 { 00249 setupMenu(); 00250 updateSelectionDependentActions(); 00251 00252 actionMenu->popup( pos ); 00253 } 00254 00255 void KDirOperator::updateSelectionDependentActions() 00256 { 00257 bool hasSelection = m_fileView && m_fileView->selectedItems() && 00258 !m_fileView->selectedItems()->isEmpty(); 00259 myActionCollection->action( "trash" )->setEnabled( hasSelection ); 00260 myActionCollection->action( "delete" )->setEnabled( hasSelection ); 00261 myActionCollection->action( "properties" )->setEnabled( hasSelection ); 00262 } 00263 00264 void KDirOperator::setPreviewWidget(const QWidget *w) 00265 { 00266 if(w != 0L) 00267 m_viewKind = (m_viewKind | KFile::PreviewContents); 00268 else 00269 m_viewKind = (m_viewKind & ~KFile::PreviewContents); 00270 00271 delete myPreview; 00272 myPreview = w; 00273 00274 KToggleAction *preview = static_cast<KToggleAction*>(myActionCollection->action("preview")); 00275 preview->setEnabled( w != 0L ); 00276 preview->setChecked( w != 0L ); 00277 setView( static_cast<KFile::FileView>(m_viewKind) ); 00278 } 00279 00280 int KDirOperator::numDirs() const 00281 { 00282 return m_fileView ? m_fileView->numDirs() : 0; 00283 } 00284 00285 int KDirOperator::numFiles() const 00286 { 00287 return m_fileView ? m_fileView->numFiles() : 0; 00288 } 00289 00290 void KDirOperator::slotDetailedView() 00291 { 00292 KFile::FileView view = static_cast<KFile::FileView>( (m_viewKind & ~KFile::Simple) | KFile::Detail ); 00293 setView( view ); 00294 } 00295 00296 void KDirOperator::slotSimpleView() 00297 { 00298 KFile::FileView view = static_cast<KFile::FileView>( (m_viewKind & ~KFile::Detail) | KFile::Simple ); 00299 setView( view ); 00300 } 00301 00302 void KDirOperator::slotToggleHidden( bool show ) 00303 { 00304 dir->setShowingDotFiles( show ); 00305 updateDir(); 00306 if ( m_fileView ) 00307 m_fileView->listingCompleted(); 00308 } 00309 00310 void KDirOperator::slotSeparateDirs() 00311 { 00312 if (separateDirsAction->isChecked()) 00313 { 00314 KFile::FileView view = static_cast<KFile::FileView>( m_viewKind | KFile::SeparateDirs ); 00315 setView( view ); 00316 } 00317 else 00318 { 00319 KFile::FileView view = static_cast<KFile::FileView>( m_viewKind & ~KFile::SeparateDirs ); 00320 setView( view ); 00321 } 00322 } 00323 00324 void KDirOperator::slotDefaultPreview() 00325 { 00326 m_viewKind = m_viewKind | KFile::PreviewContents; 00327 if ( !myPreview ) { 00328 myPreview = new KFileMetaPreview( this ); 00329 (static_cast<KToggleAction*>( myActionCollection->action("preview") ))->setChecked(true); 00330 } 00331 00332 setView( static_cast<KFile::FileView>(m_viewKind) ); 00333 } 00334 00335 void KDirOperator::slotSortByName() 00336 { 00337 int sorting = (m_fileView->sorting()) & ~QDir::SortByMask; 00338 m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::Name )); 00339 mySorting = m_fileView->sorting(); 00340 caseInsensitiveAction->setEnabled( true ); 00341 } 00342 00343 void KDirOperator::slotSortBySize() 00344 { 00345 int sorting = (m_fileView->sorting()) & ~QDir::SortByMask; 00346 m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::Size )); 00347 mySorting = m_fileView->sorting(); 00348 caseInsensitiveAction->setEnabled( false ); 00349 } 00350 00351 void KDirOperator::slotSortByDate() 00352 { 00353 int sorting = (m_fileView->sorting()) & ~QDir::SortByMask; 00354 m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::Time )); 00355 mySorting = m_fileView->sorting(); 00356 caseInsensitiveAction->setEnabled( false ); 00357 } 00358 00359 void KDirOperator::slotSortReversed() 00360 { 00361 if ( m_fileView ) 00362 m_fileView->sortReversed(); 00363 } 00364 00365 void KDirOperator::slotToggleDirsFirst() 00366 { 00367 QDir::SortSpec sorting = m_fileView->sorting(); 00368 if ( !KFile::isSortDirsFirst( sorting ) ) 00369 m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::DirsFirst )); 00370 else 00371 m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting & ~QDir::DirsFirst)); 00372 mySorting = m_fileView->sorting(); 00373 } 00374 00375 void KDirOperator::slotToggleIgnoreCase() 00376 { 00377 QDir::SortSpec sorting = m_fileView->sorting(); 00378 if ( !KFile::isSortCaseInsensitive( sorting ) ) 00379 m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting | QDir::IgnoreCase )); 00380 else 00381 m_fileView->setSorting( static_cast<QDir::SortSpec>( sorting & ~QDir::IgnoreCase)); 00382 mySorting = m_fileView->sorting(); 00383 } 00384 00385 void KDirOperator::mkdir() 00386 { 00387 bool ok; 00388 QString where = url().pathOrURL(); 00389 QString name = i18n( "New Folder" ); 00390 if ( url().isLocalFile() && QFileInfo( url().path(+1) + name ).exists() ) 00391 name = KIO::RenameDlg::suggestName( url(), name ); 00392 00393 QString dir = KInputDialog::getText( i18n( "New Folder" ), 00394 i18n( "Create new folder in:\n%1" ).arg( where ), 00395 name, &ok, this); 00396 if (ok) 00397 mkdir( KIO::encodeFileName( dir ), true ); 00398 } 00399 00400 bool KDirOperator::mkdir( const QString& directory, bool enterDirectory ) 00401 { 00402 // Creates "directory", relative to the current directory (currUrl). 00403 // The given path may contain any number directories, existant or not. 00404 // They will all be created, if possible. 00405 00406 bool writeOk = false; 00407 bool exists = false; 00408 KURL url( currUrl ); 00409 00410 QStringList dirs = QStringList::split( QDir::separator(), directory ); 00411 QStringList::ConstIterator it = dirs.begin(); 00412 00413 for ( ; it != dirs.end(); ++it ) 00414 { 00415 url.addPath( *it ); 00416 exists = KIO::NetAccess::exists( url, false, 0 ); 00417 writeOk = !exists && KIO::NetAccess::mkdir( url, topLevelWidget() ); 00418 } 00419 00420 if ( exists ) // url was already existant 00421 { 00422 KMessageBox::sorry(viewWidget(), i18n("A file or folder named %1 already exists.").arg(url.pathOrURL())); 00423 enterDirectory = false; 00424 } 00425 else if ( !writeOk ) { 00426 KMessageBox::sorry(viewWidget(), i18n("You do not have permission to " 00427 "create that folder." )); 00428 } 00429 else if ( enterDirectory ) { 00430 setURL( url, true ); 00431 } 00432 00433 return writeOk; 00434 } 00435 00436 KIO::DeleteJob * KDirOperator::del( const KFileItemList& items, 00437 bool ask, bool showProgress ) 00438 { 00439 return del( items, this, ask, showProgress ); 00440 } 00441 00442 KIO::DeleteJob * KDirOperator::del( const KFileItemList& items, 00443 QWidget *parent, 00444 bool ask, bool showProgress ) 00445 { 00446 if ( items.isEmpty() ) { 00447 KMessageBox::information( parent, 00448 i18n("You did not select a file to delete."), 00449 i18n("Nothing to Delete") ); 00450 return 0L; 00451 } 00452 00453 KURL::List urls; 00454 QStringList files; 00455 KFileItemListIterator it( items ); 00456 00457 for ( ; it.current(); ++it ) { 00458 KURL url = (*it)->url(); 00459 urls.append( url ); 00460 if ( url.isLocalFile() ) 00461 files.append( url.path() ); 00462 else 00463 files.append( url.prettyURL() ); 00464 } 00465 00466 bool doIt = !ask; 00467 if ( ask ) { 00468 int ret; 00469 if ( items.count() == 1 ) { 00470 ret = KMessageBox::warningContinueCancel( parent, 00471 i18n( "<qt>Do you really want to delete\n <b>'%1'</b>?</qt>" ) 00472 .arg( files.first() ), 00473 i18n("Delete File"), 00474 KStdGuiItem::del(), "AskForDelete" ); 00475 } 00476 else 00477 ret = KMessageBox::warningContinueCancelList( parent, 00478 i18n("Do you really want to delete this item?", "Do you really want to delete these %n items?", items.count() ), 00479 files, 00480 i18n("Delete Files"), 00481 KStdGuiItem::del(), "AskForDelete" ); 00482 doIt = (ret == KMessageBox::Continue); 00483 } 00484 00485 if ( doIt ) { 00486 KIO::DeleteJob *job = KIO::del( urls, false, showProgress ); 00487 job->setWindow (topLevelWidget()); 00488 job->setAutoErrorHandlingEnabled( true, parent ); 00489 return job; 00490 } 00491 00492 return 0L; 00493 } 00494 00495 void KDirOperator::deleteSelected() 00496 { 00497 if ( !m_fileView ) 00498 return; 00499 00500 const KFileItemList *list = m_fileView->selectedItems(); 00501 if ( list ) 00502 del( *list ); 00503 } 00504 00505 KIO::CopyJob * KDirOperator::trash( const KFileItemList& items, 00506 QWidget *parent, 00507 bool ask, bool showProgress ) 00508 { 00509 if ( items.isEmpty() ) { 00510 KMessageBox::information( parent, 00511 i18n("You did not select a file to trash."), 00512 i18n("Nothing to Trash") ); 00513 return 0L; 00514 } 00515 00516 KURL::List urls; 00517 QStringList files; 00518 KFileItemListIterator it( items ); 00519 00520 for ( ; it.current(); ++it ) { 00521 KURL url = (*it)->url(); 00522 urls.append( url ); 00523 if ( url.isLocalFile() ) 00524 files.append( url.path() ); 00525 else 00526 files.append( url.prettyURL() ); 00527 } 00528 00529 bool doIt = !ask; 00530 if ( ask ) { 00531 int ret; 00532 if ( items.count() == 1 ) { 00533 ret = KMessageBox::warningContinueCancel( parent, 00534 i18n( "<qt>Do you really want to trash\n <b>'%1'</b>?</qt>" ) 00535 .arg( files.first() ), 00536 i18n("Trash File"), 00537 KGuiItem(i18n("to trash", "&Trash"),"edittrash"), "AskForTrash" ); 00538 } 00539 else 00540 ret = KMessageBox::warningContinueCancelList( parent, 00541 i18n("translators: not called for n == 1", "Do you really want to trash these %n items?", items.count() ), 00542 files, 00543 i18n("Trash Files"), 00544 KGuiItem(i18n("to trash", "&Trash"),"edittrash"), "AskForTrash" ); 00545 doIt = (ret == KMessageBox::Continue); 00546 } 00547 00548 if ( doIt ) { 00549 KIO::CopyJob *job = KIO::trash( urls, showProgress ); 00550 job->setWindow (topLevelWidget()); 00551 job->setAutoErrorHandlingEnabled( true, parent ); 00552 return job; 00553 } 00554 00555 return 0L; 00556 } 00557 00558 void KDirOperator::trashSelected(KAction::ActivationReason reason, Qt::ButtonState state) 00559 { 00560 if ( !m_fileView ) 00561 return; 00562 00563 if ( reason == KAction::PopupMenuActivation && ( state & Qt::ShiftButton ) ) { 00564 deleteSelected(); 00565 return; 00566 } 00567 00568 const KFileItemList *list = m_fileView->selectedItems(); 00569 if ( list ) 00570 trash( *list, this ); 00571 } 00572 00573 void KDirOperator::close() 00574 { 00575 resetCursor(); 00576 pendingMimeTypes.clear(); 00577 myCompletion.clear(); 00578 myDirCompletion.clear(); 00579 myCompleteListDirty = true; 00580 dir->stop(); 00581 } 00582 00583 void KDirOperator::checkPath(const QString &, bool /*takeFiles*/) // SLOT 00584 { 00585 #if 0 00586 // copy the argument in a temporary string 00587 QString text = _txt; 00588 // it's unlikely to happen, that at the beginning are spaces, but 00589 // for the end, it happens quite often, I guess. 00590 text = text.stripWhiteSpace(); 00591 // if the argument is no URL (the check is quite fragil) and it's 00592 // no absolute path, we add the current directory to get a correct url 00593 if (text.find(':') < 0 && text[0] != '/') 00594 text.insert(0, currUrl); 00595 00596 // in case we have a selection defined and someone patched the file- 00597 // name, we check, if the end of the new name is changed. 00598 if (!selection.isNull()) { 00599 int position = text.findRev('/'); 00600 ASSERT(position >= 0); // we already inserted the current dir in case 00601 QString filename = text.mid(position + 1, text.length()); 00602 if (filename != selection) 00603 selection = QString::null; 00604 } 00605 00606 KURL u(text); // I have to take care of entered URLs 00607 bool filenameEntered = false; 00608 00609 if (u.isLocalFile()) { 00610 // the empty path is kind of a hack 00611 KFileItem i("", u.path()); 00612 if (i.isDir()) 00613 setURL(text, true); 00614 else { 00615 if (takeFiles) 00616 if (acceptOnlyExisting && !i.isFile()) 00617 warning("you entered an invalid URL"); 00618 else 00619 filenameEntered = true; 00620 } 00621 } else 00622 setURL(text, true); 00623 00624 if (filenameEntered) { 00625 filename_ = u.url(); 00626 emit fileSelected(filename_); 00627 00628 QApplication::restoreOverrideCursor(); 00629 00630 accept(); 00631 } 00632 #endif 00633 kdDebug(kfile_area) << "TODO KDirOperator::checkPath()" << endl; 00634 } 00635 00636 void KDirOperator::setURL(const KURL& _newurl, bool clearforward) 00637 { 00638 KURL newurl; 00639 00640 if ( !_newurl.isValid() ) 00641 newurl.setPath( QDir::homeDirPath() ); 00642 else 00643 newurl = _newurl; 00644 00645 QString pathstr = newurl.path(+1); 00646 newurl.setPath(pathstr); 00647 00648 // already set 00649 if ( newurl.equals( currUrl, true ) ) 00650 return; 00651 00652 if ( !isReadable( newurl ) ) { 00653 // maybe newurl is a file? check its parent directory 00654 newurl.cd(QString::fromLatin1("..")); 00655 if ( !isReadable( newurl ) ) { 00656 resetCursor(); 00657 KMessageBox::error(viewWidget(), 00658 i18n("The specified folder does not exist " 00659 "or was not readable.")); 00660 return; 00661 } 00662 } 00663 00664 if (clearforward) { 00665 // autodelete should remove this one 00666 backStack.push(new KURL(currUrl)); 00667 forwardStack.clear(); 00668 } 00669 00670 d->lastURL = currUrl.url(-1); 00671 currUrl = newurl; 00672 00673 pathChanged(); 00674 emit urlEntered(newurl); 00675 00676 // enable/disable actions 00677 forwardAction->setEnabled( !forwardStack.isEmpty() ); 00678 backAction->setEnabled( !backStack.isEmpty() ); 00679 upAction->setEnabled( !isRoot() ); 00680 00681 openURL( newurl ); 00682 } 00683 00684 void KDirOperator::updateDir() 00685 { 00686 dir->emitChanges(); 00687 if ( m_fileView ) 00688 m_fileView->listingCompleted(); 00689 } 00690 00691 void KDirOperator::rereadDir() 00692 { 00693 pathChanged(); 00694 openURL( currUrl, false, true ); 00695 } 00696 00697 00698 bool KDirOperator::openURL( const KURL& url, bool keep, bool reload ) 00699 { 00700 bool result = dir->openURL( url, keep, reload ); 00701 if ( !result ) // in that case, neither completed() nor canceled() will be emitted by KDL 00702 slotCanceled(); 00703 00704 return result; 00705 } 00706 00707 // Protected 00708 void KDirOperator::pathChanged() 00709 { 00710 if (!m_fileView) 00711 return; 00712 00713 pendingMimeTypes.clear(); 00714 m_fileView->clear(); 00715 myCompletion.clear(); 00716 myDirCompletion.clear(); 00717 00718 // it may be, that we weren't ready at this time 00719 QApplication::restoreOverrideCursor(); 00720 00721 // when KIO::Job emits finished, the slot will restore the cursor 00722 QApplication::setOverrideCursor( waitCursor ); 00723 00724 if ( !isReadable( currUrl )) { 00725 KMessageBox::error(viewWidget(), 00726 i18n("The specified folder does not exist " 00727 "or was not readable.")); 00728 if (backStack.isEmpty()) 00729 home(); 00730 else 00731 back(); 00732 } 00733 } 00734 00735 void KDirOperator::slotRedirected( const KURL& newURL ) 00736 { 00737 currUrl = newURL; 00738 pendingMimeTypes.clear(); 00739 myCompletion.clear(); 00740 myDirCompletion.clear(); 00741 myCompleteListDirty = true; 00742 emit urlEntered( newURL ); 00743 } 00744 00745 // Code pinched from kfm then hacked 00746 void KDirOperator::back() 00747 { 00748 if ( backStack.isEmpty() ) 00749 return; 00750 00751 forwardStack.push( new KURL(currUrl) ); 00752 00753 KURL *s = backStack.pop(); 00754 00755 setURL(*s, false); 00756 delete s; 00757 } 00758 00759 // Code pinched from kfm then hacked 00760 void KDirOperator::forward() 00761 { 00762 if ( forwardStack.isEmpty() ) 00763 return; 00764 00765 backStack.push(new KURL(currUrl)); 00766 00767 KURL *s = forwardStack.pop(); 00768 setURL(*s, false); 00769 delete s; 00770 } 00771 00772 KURL KDirOperator::url() const 00773 { 00774 return currUrl; 00775 } 00776 00777 void KDirOperator::cdUp() 00778 { 00779 KURL tmp(currUrl); 00780 tmp.cd(QString::fromLatin1("..")); 00781 setURL(tmp, true); 00782 } 00783 00784 void KDirOperator::home() 00785 { 00786 KURL u; 00787 u.setPath( QDir::homeDirPath() ); 00788 setURL(u, true); 00789 } 00790 00791 void KDirOperator::clearFilter() 00792 { 00793 dir->setNameFilter( QString::null ); 00794 dir->clearMimeFilter(); 00795 checkPreviewSupport(); 00796 } 00797 00798 void KDirOperator::setNameFilter(const QString& filter) 00799 { 00800 dir->setNameFilter(filter); 00801 checkPreviewSupport(); 00802 } 00803 00804 void KDirOperator::setMimeFilter( const QStringList& mimetypes ) 00805 { 00806 dir->setMimeFilter( mimetypes ); 00807 checkPreviewSupport(); 00808 } 00809 00810 bool KDirOperator::checkPreviewSupport() 00811 { 00812 KToggleAction *previewAction = static_cast<KToggleAction*>( myActionCollection->action( "preview" )); 00813 00814 bool hasPreviewSupport = false; 00815 KConfig *kc = KGlobal::config(); 00816 KConfigGroupSaver cs( kc, ConfigGroup ); 00817 if ( kc->readBoolEntry( "Show Default Preview", true ) ) 00818 hasPreviewSupport = checkPreviewInternal(); 00819 00820 previewAction->setEnabled( hasPreviewSupport ); 00821 return hasPreviewSupport; 00822 } 00823 00824 bool KDirOperator::checkPreviewInternal() const 00825 { 00826 QStringList supported = KIO::PreviewJob::supportedMimeTypes(); 00827 // no preview support for directories? 00828 if ( dirOnlyMode() && supported.findIndex( "inode/directory" ) == -1 ) 00829 return false; 00830 00831 QStringList mimeTypes = dir->mimeFilters(); 00832 QStringList nameFilter = QStringList::split( " ", dir->nameFilter() ); 00833 00834 if ( mimeTypes.isEmpty() && nameFilter.isEmpty() && !supported.isEmpty() ) 00835 return true; 00836 else { 00837 QRegExp r; 00838 r.setWildcard( true ); // the "mimetype" can be "image/*" 00839 00840 if ( !mimeTypes.isEmpty() ) { 00841 QStringList::Iterator it = supported.begin(); 00842 00843 for ( ; it != supported.end(); ++it ) { 00844 r.setPattern( *it ); 00845 00846 QStringList result = mimeTypes.grep( r ); 00847 if ( !result.isEmpty() ) { // matches! -> we want previews 00848 return true; 00849 } 00850 } 00851 } 00852 00853 if ( !nameFilter.isEmpty() ) { 00854 // find the mimetypes of all the filter-patterns and 00855 KServiceTypeFactory *fac = KServiceTypeFactory::self(); 00856 QStringList::Iterator it1 = nameFilter.begin(); 00857 for ( ; it1 != nameFilter.end(); ++it1 ) { 00858 if ( (*it1) == "*" ) { 00859 return true; 00860 } 00861 00862 KMimeType *mt = fac->findFromPattern( *it1 ); 00863 if ( !mt ) 00864 continue; 00865 QString mime = mt->name(); 00866 delete mt; 00867 00868 // the "mimetypes" we get from the PreviewJob can be "image/*" 00869 // so we need to check in wildcard mode 00870 QStringList::Iterator it2 = supported.begin(); 00871 for ( ; it2 != supported.end(); ++it2 ) { 00872 r.setPattern( *it2 ); 00873 if ( r.search( mime ) != -1 ) { 00874 return true; 00875 } 00876 } 00877 } 00878 } 00879 } 00880 00881 return false; 00882 } 00883 00884 KFileView* KDirOperator::createView( QWidget* parent, KFile::FileView view ) 00885 { 00886 KFileView* new_view = 0L; 00887 bool separateDirs = KFile::isSeparateDirs( view ); 00888 bool preview = ( KFile::isPreviewInfo(view) || KFile::isPreviewContents( view ) ); 00889 00890 if ( separateDirs || preview ) { 00891 KCombiView *combi = 0L; 00892 if (separateDirs) 00893 { 00894 combi = new KCombiView( parent, "combi view" ); 00895 combi->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles); 00896 } 00897 00898 KFileView* v = 0L; 00899 if ( KFile::isSimpleView( view ) ) 00900 v = createView( combi, KFile::Simple ); 00901 else 00902 v = createView( combi, KFile::Detail ); 00903 00904 v->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles); 00905 00906 if (combi) 00907 combi->setRight( v ); 00908 00909 if (preview) 00910 { 00911 KFilePreview* pView = new KFilePreview( combi ? combi : v, parent, "preview" ); 00912 pView->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles); 00913 new_view = pView; 00914 } 00915 else 00916 new_view = combi; 00917 } 00918 else if ( KFile::isDetailView( view ) && !preview ) { 00919 new_view = new KFileDetailView( parent, "detail view"); 00920 new_view->setViewName( i18n("Detailed View") ); 00921 } 00922 else /* if ( KFile::isSimpleView( view ) && !preview ) */ { 00923 KFileIconView *iconView = new KFileIconView( parent, "simple view"); 00924 new_view = iconView; 00925 new_view->setViewName( i18n("Short View") ); 00926 } 00927 00928 new_view->widget()->setAcceptDrops(acceptDrops()); 00929 return new_view; 00930 } 00931 00932 void KDirOperator::setAcceptDrops(bool b) 00933 { 00934 if (m_fileView) 00935 m_fileView->widget()->setAcceptDrops(b); 00936 QWidget::setAcceptDrops(b); 00937 } 00938 00939 void KDirOperator::setDropOptions(int options) 00940 { 00941 d->dropOptions = options; 00942 if (m_fileView) 00943 m_fileView->setDropOptions(options); 00944 } 00945 00946 void KDirOperator::setView( KFile::FileView view ) 00947 { 00948 bool separateDirs = KFile::isSeparateDirs( view ); 00949 bool preview=( KFile::isPreviewInfo(view) || KFile::isPreviewContents( view ) ); 00950 00951 if (view == KFile::Default) { 00952 if ( KFile::isDetailView( (KFile::FileView) defaultView ) ) 00953 view = KFile::Detail; 00954 else 00955 view = KFile::Simple; 00956 00957 separateDirs = KFile::isSeparateDirs( static_cast<KFile::FileView>(defaultView) ); 00958 preview = ( KFile::isPreviewInfo( static_cast<KFile::FileView>(defaultView) ) || 00959 KFile::isPreviewContents( static_cast<KFile::FileView>(defaultView) ) ) 00960 && myActionCollection->action("preview")->isEnabled(); 00961 00962 if ( preview ) { // instantiates KFileMetaPreview and calls setView() 00963 m_viewKind = defaultView; 00964 slotDefaultPreview(); 00965 return; 00966 } 00967 else if ( !separateDirs ) 00968 separateDirsAction->setChecked(true); 00969 } 00970 00971 // if we don't have any files, we can't separate dirs from files :) 00972 if ( (mode() & KFile::File) == 0 && 00973 (mode() & KFile::Files) == 0 ) { 00974 separateDirs = false; 00975 separateDirsAction->setEnabled( false ); 00976 } 00977 00978 m_viewKind = static_cast<int>(view) | (separateDirs ? KFile::SeparateDirs : 0); 00979 view = static_cast<KFile::FileView>(m_viewKind); 00980 00981 KFileView *new_view = createView( this, view ); 00982 if ( preview ) { 00983 // we keep the preview-_widget_ around, but not the KFilePreview. 00984 // KFilePreview::setPreviewWidget handles the reparenting for us 00985 static_cast<KFilePreview*>(new_view)->setPreviewWidget(myPreview, url()); 00986 } 00987 00988 setView( new_view ); 00989 } 00990 00991 00992 void KDirOperator::connectView(KFileView *view) 00993 { 00994 // TODO: do a real timer and restart it after that 00995 pendingMimeTypes.clear(); 00996 bool listDir = true; 00997 00998 if ( dirOnlyMode() ) 00999 view->setViewMode(KFileView::Directories); 01000 else 01001 view->setViewMode(KFileView::All); 01002 01003 if ( myMode & KFile::Files ) 01004 view->setSelectionMode( KFile::Extended ); 01005 else 01006 view->setSelectionMode( KFile::Single ); 01007 01008 if (m_fileView) 01009 { 01010 if ( d->config ) // save and restore the views' configuration 01011 { 01012 m_fileView->writeConfig( d->config, d->configGroup ); 01013 view->readConfig( d->config, d->configGroup ); 01014 } 01015 01016 // transfer the state from old view to new view 01017 view->clear(); 01018 view->addItemList( *m_fileView->items() ); 01019 listDir = false; 01020 01021 if ( m_fileView->widget()->hasFocus() ) 01022 view->widget()->setFocus(); 01023 01024 KFileItem *oldCurrentItem = m_fileView->currentFileItem(); 01025 if ( oldCurrentItem ) { 01026 view->setCurrentItem( oldCurrentItem ); 01027 view->setSelected( oldCurrentItem, false ); 01028 view->ensureItemVisible( oldCurrentItem ); 01029 } 01030 01031 const KFileItemList *oldSelected = m_fileView->selectedItems(); 01032 if ( !oldSelected->isEmpty() ) { 01033 KFileItemListIterator it( *oldSelected ); 01034 for ( ; it.current(); ++it ) 01035 view->setSelected( it.current(), true ); 01036 } 01037 01038 m_fileView->widget()->hide(); 01039 delete m_fileView; 01040 } 01041 01042 else 01043 { 01044 if ( d->config ) 01045 view->readConfig( d->config, d->configGroup ); 01046 } 01047 01048 m_fileView = view; 01049 m_fileView->setDropOptions(d->dropOptions); 01050 viewActionCollection = 0L; 01051 KFileViewSignaler *sig = view->signaler(); 01052 01053 connect(sig, SIGNAL( activatedMenu(const KFileItem *, const QPoint& ) ), 01054 this, SLOT( activatedMenu(const KFileItem *, const QPoint& ))); 01055 connect(sig, SIGNAL( dirActivated(const KFileItem *) ), 01056 this, SLOT( selectDir(const KFileItem*) ) ); 01057 connect(sig, SIGNAL( fileSelected(const KFileItem *) ), 01058 this, SLOT( selectFile(const KFileItem*) ) ); 01059 connect(sig, SIGNAL( fileHighlighted(const KFileItem *) ), 01060 this, SLOT( highlightFile(const KFileItem*) )); 01061 connect(sig, SIGNAL( sortingChanged( QDir::SortSpec ) ), 01062 this, SLOT( slotViewSortingChanged( QDir::SortSpec ))); 01063 connect(sig, SIGNAL( dropped(const KFileItem *, QDropEvent*, const KURL::List&) ), 01064 this, SIGNAL( dropped(const KFileItem *, QDropEvent*, const KURL::List&)) ); 01065 01066 if ( reverseAction->isChecked() != m_fileView->isReversed() ) 01067 slotSortReversed(); 01068 01069 updateViewActions(); 01070 m_fileView->widget()->resize(size()); 01071 m_fileView->widget()->show(); 01072 01073 if ( listDir ) { 01074 QApplication::setOverrideCursor( waitCursor ); 01075 openURL( currUrl ); 01076 } 01077 else 01078 view->listingCompleted(); 01079 } 01080 01081 KFile::Mode KDirOperator::mode() const 01082 { 01083 return myMode; 01084 } 01085 01086 void KDirOperator::setMode(KFile::Mode m) 01087 { 01088 if (myMode == m) 01089 return; 01090 01091 myMode = m; 01092 01093 dir->setDirOnlyMode( dirOnlyMode() ); 01094 01095 // reset the view with the different mode 01096 setView( static_cast<KFile::FileView>(m_viewKind) ); 01097 } 01098 01099 void KDirOperator::setView(KFileView *view) 01100 { 01101 if ( view == m_fileView ) { 01102 return; 01103 } 01104 01105 setFocusProxy(view->widget()); 01106 view->setSorting( mySorting ); 01107 view->setOnlyDoubleClickSelectsFiles( d->onlyDoubleClickSelectsFiles ); 01108 connectView(view); // also deletes the old view 01109 01110 emit viewChanged( view ); 01111 } 01112 01113 void KDirOperator::setDirLister( KDirLister *lister ) 01114 { 01115 if ( lister == dir ) // sanity check 01116 return; 01117 01118 delete dir; 01119 dir = lister; 01120 01121 dir->setAutoUpdate( true ); 01122 01123 QWidget* mainWidget = topLevelWidget(); 01124 dir->setMainWindow (mainWidget); 01125 kdDebug (kfile_area) << "mainWidget=" << mainWidget << endl; 01126 01127 connect( dir, SIGNAL( percent( int )), 01128 SLOT( slotProgress( int ) )); 01129 connect( dir, SIGNAL(started( const KURL& )), SLOT(slotStarted())); 01130 connect( dir, SIGNAL(newItems(const KFileItemList &)), 01131 SLOT(insertNewFiles(const KFileItemList &))); 01132 connect( dir, SIGNAL(completed()), SLOT(slotIOFinished())); 01133 connect( dir, SIGNAL(canceled()), SLOT(slotCanceled())); 01134 connect( dir, SIGNAL(deleteItem(KFileItem *)), 01135 SLOT(itemDeleted(KFileItem *))); 01136 connect( dir, SIGNAL(redirection( const KURL& )), 01137 SLOT( slotRedirected( const KURL& ))); 01138 connect( dir, SIGNAL( clear() ), SLOT( slotClearView() )); 01139 connect( dir, SIGNAL( refreshItems( const KFileItemList& ) ), 01140 SLOT( slotRefreshItems( const KFileItemList& ) ) ); 01141 } 01142 01143 void KDirOperator::insertNewFiles(const KFileItemList &newone) 01144 { 01145 if ( newone.isEmpty() || !m_fileView ) 01146 return; 01147 01148 myCompleteListDirty = true; 01149 m_fileView->addItemList( newone ); 01150 emit updateInformation(m_fileView->numDirs(), m_fileView->numFiles()); 01151 01152 KFileItem *item; 01153 KFileItemListIterator it( newone ); 01154 01155 while ( (item = it.current()) ) { 01156 // highlight the dir we come from, if possible 01157 if ( d->dirHighlighting && item->isDir() && 01158 item->url().url(-1) == d->lastURL ) { 01159 m_fileView->setCurrentItem( item ); 01160 m_fileView->ensureItemVisible( item ); 01161 } 01162 01163 ++it; 01164 } 01165 01166 QTimer::singleShot(200, this, SLOT(resetCursor())); 01167 } 01168 01169 void KDirOperator::selectDir(const KFileItem *item) 01170 { 01171 setURL(item->url(), true); 01172 } 01173 01174 void KDirOperator::itemDeleted(KFileItem *item) 01175 { 01176 pendingMimeTypes.removeRef( item ); 01177 if ( m_fileView ) 01178 { 01179 m_fileView->removeItem( static_cast<KFileItem *>( item )); 01180 emit updateInformation(m_fileView->numDirs(), m_fileView->numFiles()); 01181 } 01182 } 01183 01184 void KDirOperator::selectFile(const KFileItem *item) 01185 { 01186 QApplication::restoreOverrideCursor(); 01187 01188 emit fileSelected( item ); 01189 } 01190 01191 void KDirOperator::setCurrentItem( const QString& filename ) 01192 { 01193 if ( m_fileView ) { 01194 const KFileItem *item = 0L; 01195 01196 if ( !filename.isNull() ) 01197 item = static_cast<KFileItem *>(dir->findByName( filename )); 01198 01199 m_fileView->clearSelection(); 01200 if ( item ) { 01201 m_fileView->setCurrentItem( item ); 01202 m_fileView->setSelected( item, true ); 01203 m_fileView->ensureItemVisible( item ); 01204 } 01205 } 01206 } 01207 01208 QString KDirOperator::makeCompletion(const QString& string) 01209 { 01210 if ( string.isEmpty() ) { 01211 m_fileView->clearSelection(); 01212 return QString::null; 01213 } 01214 01215 prepareCompletionObjects(); 01216 return myCompletion.makeCompletion( string ); 01217 } 01218 01219 QString KDirOperator::makeDirCompletion(const QString& string) 01220 { 01221 if ( string.isEmpty() ) { 01222 m_fileView->clearSelection(); 01223 return QString::null; 01224 } 01225 01226 prepareCompletionObjects(); 01227 return myDirCompletion.makeCompletion( string ); 01228 } 01229 01230 void KDirOperator::prepareCompletionObjects() 01231 { 01232 if ( !m_fileView ) 01233 return; 01234 01235 if ( myCompleteListDirty ) { // create the list of all possible completions 01236 KFileItemListIterator it( *(m_fileView->items()) ); 01237 for( ; it.current(); ++it ) { 01238 KFileItem *item = it.current(); 01239 01240 myCompletion.addItem( item->name() ); 01241 if ( item->isDir() ) 01242 myDirCompletion.addItem( item->name() ); 01243 } 01244 myCompleteListDirty = false; 01245 } 01246 } 01247 01248 void KDirOperator::slotCompletionMatch(const QString& match) 01249 { 01250 setCurrentItem( match ); 01251 emit completion( match ); 01252 } 01253 01254 void KDirOperator::setupActions() 01255 { 01256 myActionCollection = new KActionCollection( topLevelWidget(), this, "KDirOperator::myActionCollection" ); 01257 01258 actionMenu = new KActionMenu( i18n("Menu"), myActionCollection, "popupMenu" ); 01259 upAction = KStdAction::up( this, SLOT( cdUp() ), myActionCollection, "up" ); 01260 upAction->setText( i18n("Parent Folder") ); 01261 backAction = KStdAction::back( this, SLOT( back() ), myActionCollection, "back" ); 01262 forwardAction = KStdAction::forward( this, SLOT(forward()), myActionCollection, "forward" ); 01263 homeAction = KStdAction::home( this, SLOT( home() ), myActionCollection, "home" ); 01264 homeAction->setText(i18n("Home Folder")); 01265 reloadAction = KStdAction::redisplay( this, SLOT(rereadDir()), myActionCollection, "reload" ); 01266 actionSeparator = new KActionSeparator( myActionCollection, "separator" ); 01267 d->viewActionSeparator = new KActionSeparator( myActionCollection, 01268 "viewActionSeparator" ); 01269 mkdirAction = new KAction( i18n("New Folder..."), 0, 01270 this, SLOT( mkdir() ), myActionCollection, "mkdir" ); 01271 KAction* trash = new KAction( i18n( "Move to Trash" ), "edittrash", Key_Delete, myActionCollection, "trash" ); 01272 connect( trash, SIGNAL( activated( KAction::ActivationReason, Qt::ButtonState ) ), 01273 this, SLOT( trashSelected( KAction::ActivationReason, Qt::ButtonState ) ) ); 01274 new KAction( i18n( "Delete" ), "editdelete", SHIFT+Key_Delete, this, 01275 SLOT( deleteSelected() ), myActionCollection, "delete" ); 01276 mkdirAction->setIcon( QString::fromLatin1("folder_new") ); 01277 reloadAction->setText( i18n("Reload") ); 01278 reloadAction->setShortcut( KStdAccel::shortcut( KStdAccel::Reload )); 01279 01280 01281 // the sort menu actions 01282 sortActionMenu = new KActionMenu( i18n("Sorting"), myActionCollection, "sorting menu"); 01283 byNameAction = new KRadioAction( i18n("By Name"), 0, 01284 this, SLOT( slotSortByName() ), 01285 myActionCollection, "by name" ); 01286 byDateAction = new KRadioAction( i18n("By Date"), 0, 01287 this, SLOT( slotSortByDate() ), 01288 myActionCollection, "by date" ); 01289 bySizeAction = new KRadioAction( i18n("By Size"), 0, 01290 this, SLOT( slotSortBySize() ), 01291 myActionCollection, "by size" ); 01292 reverseAction = new KToggleAction( i18n("Reverse"), 0, 01293 this, SLOT( slotSortReversed() ), 01294 myActionCollection, "reversed" ); 01295 01296 QString sortGroup = QString::fromLatin1("sort"); 01297 byNameAction->setExclusiveGroup( sortGroup ); 01298 byDateAction->setExclusiveGroup( sortGroup ); 01299 bySizeAction->setExclusiveGroup( sortGroup ); 01300 01301 01302 dirsFirstAction = new KToggleAction( i18n("Folders First"), 0, 01303 myActionCollection, "dirs first"); 01304 caseInsensitiveAction = new KToggleAction(i18n("Case Insensitive"), 0, 01305 myActionCollection, "case insensitive" ); 01306 01307 connect( dirsFirstAction, SIGNAL( toggled( bool ) ), 01308 SLOT( slotToggleDirsFirst() )); 01309 connect( caseInsensitiveAction, SIGNAL( toggled( bool ) ), 01310 SLOT( slotToggleIgnoreCase() )); 01311 01312 01313 01314 // the view menu actions 01315 viewActionMenu = new KActionMenu( i18n("&View"), myActionCollection, "view menu" ); 01316 connect( viewActionMenu->popupMenu(), SIGNAL( aboutToShow() ), 01317 SLOT( insertViewDependentActions() )); 01318 01319 shortAction = new KRadioAction( i18n("Short View"), "view_multicolumn", 01320 KShortcut(), myActionCollection, "short view" ); 01321 detailedAction = new KRadioAction( i18n("Detailed View"), "view_detailed", 01322 KShortcut(), myActionCollection, "detailed view" ); 01323 01324 showHiddenAction = new KToggleAction( i18n("Show Hidden Files"), KShortcut(), 01325 myActionCollection, "show hidden" ); 01326 // showHiddenAction->setCheckedState( i18n("Hide Hidden Files") ); 01327 separateDirsAction = new KToggleAction( i18n("Separate Folders"), KShortcut(), 01328 this, 01329 SLOT(slotSeparateDirs()), 01330 myActionCollection, "separate dirs" ); 01331 KToggleAction *previewAction = new KToggleAction(i18n("Show Preview"), 01332 "thumbnail", KShortcut(), 01333 myActionCollection, 01334 "preview" ); 01335 previewAction->setCheckedState(i18n("Hide Preview")); 01336 connect( previewAction, SIGNAL( toggled( bool )), 01337 SLOT( togglePreview( bool ))); 01338 01339 01340 QString viewGroup = QString::fromLatin1("view"); 01341 shortAction->setExclusiveGroup( viewGroup ); 01342 detailedAction->setExclusiveGroup( viewGroup ); 01343 01344 connect( shortAction, SIGNAL( activated() ), 01345 SLOT( slotSimpleView() )); 01346 connect( detailedAction, SIGNAL( activated() ), 01347 SLOT( slotDetailedView() )); 01348 connect( showHiddenAction, SIGNAL( toggled( bool ) ), 01349 SLOT( slotToggleHidden( bool ) )); 01350 01351 new KAction( i18n("Properties"), KShortcut(ALT+Key_Return), this, 01352 SLOT(slotProperties()), myActionCollection, "properties" ); 01353 } 01354 01355 void KDirOperator::setupMenu() 01356 { 01357 setupMenu(AllActions); 01358 } 01359 01360 void KDirOperator::setupMenu(int whichActions) 01361 { 01362 // first fill the submenus (sort and view) 01363 sortActionMenu->popupMenu()->clear(); 01364 sortActionMenu->insert( byNameAction ); 01365 sortActionMenu->insert( byDateAction ); 01366 sortActionMenu->insert( bySizeAction ); 01367 sortActionMenu->insert( actionSeparator ); 01368 sortActionMenu->insert( reverseAction ); 01369 sortActionMenu->insert( dirsFirstAction ); 01370 sortActionMenu->insert( caseInsensitiveAction ); 01371 01372 // now plug everything into the popupmenu 01373 actionMenu->popupMenu()->clear(); 01374 if (whichActions & NavActions) 01375 { 01376 actionMenu->insert( upAction ); 01377 actionMenu->insert( backAction ); 01378 actionMenu->insert( forwardAction ); 01379 actionMenu->insert( homeAction ); 01380 actionMenu->insert( actionSeparator ); 01381 } 01382 01383 if (whichActions & FileActions) 01384 { 01385 actionMenu->insert( mkdirAction ); 01386 if (currUrl.isLocalFile() && !(KApplication::keyboardMouseState() & Qt::ShiftButton)) 01387 actionMenu->insert( myActionCollection->action( "trash" ) ); 01388 KConfig *globalconfig = KGlobal::config(); 01389 KConfigGroupSaver cs( globalconfig, QString::fromLatin1("KDE") ); 01390 if (!currUrl.isLocalFile() || (KApplication::keyboardMouseState() & Qt::ShiftButton) || 01391 globalconfig->readBoolEntry("ShowDeleteCommand", false)) 01392 actionMenu->insert( myActionCollection->action( "delete" ) ); 01393 actionMenu->insert( actionSeparator ); 01394 } 01395 01396 if (whichActions & SortActions) 01397 { 01398 actionMenu->insert( sortActionMenu ); 01399 actionMenu->insert( actionSeparator ); 01400 } 01401 01402 if (whichActions & ViewActions) 01403 { 01404 actionMenu->insert( viewActionMenu ); 01405 actionMenu->insert( actionSeparator ); 01406 } 01407 01408 if (whichActions & FileActions) 01409 { 01410 actionMenu->insert( myActionCollection->action( "properties" ) ); 01411 } 01412 } 01413 01414 void KDirOperator::updateSortActions() 01415 { 01416 if ( KFile::isSortByName( mySorting ) ) 01417 byNameAction->setChecked( true ); 01418 else if ( KFile::isSortByDate( mySorting ) ) 01419 byDateAction->setChecked( true ); 01420 else if ( KFile::isSortBySize( mySorting ) ) 01421 bySizeAction->setChecked( true ); 01422 01423 dirsFirstAction->setChecked( KFile::isSortDirsFirst( mySorting ) ); 01424 caseInsensitiveAction->setChecked( KFile::isSortCaseInsensitive(mySorting) ); 01425 caseInsensitiveAction->setEnabled( KFile::isSortByName( mySorting ) ); 01426 01427 if ( m_fileView ) 01428 reverseAction->setChecked( m_fileView->isReversed() ); 01429 } 01430 01431 void KDirOperator::updateViewActions() 01432 { 01433 KFile::FileView fv = static_cast<KFile::FileView>( m_viewKind ); 01434 01435 separateDirsAction->setChecked( KFile::isSeparateDirs( fv ) && 01436 separateDirsAction->isEnabled() ); 01437 01438 shortAction->setChecked( KFile::isSimpleView( fv )); 01439 detailedAction->setChecked( KFile::isDetailView( fv )); 01440 } 01441 01442 void KDirOperator::readConfig( KConfig *kc, const QString& group ) 01443 { 01444 if ( !kc ) 01445 return; 01446 QString oldGroup = kc->group(); 01447 if ( !group.isEmpty() ) 01448 kc->setGroup( group ); 01449 01450 defaultView = 0; 01451 int sorting = 0; 01452 01453 QString viewStyle = kc->readEntry( QString::fromLatin1("View Style"), 01454 QString::fromLatin1("Simple") ); 01455 if ( viewStyle == QString::fromLatin1("Detail") ) 01456 defaultView |= KFile::Detail; 01457 else 01458 defaultView |= KFile::Simple; 01459 if ( kc->readBoolEntry( QString::fromLatin1("Separate Directories"), 01460 DefaultMixDirsAndFiles ) ) 01461 defaultView |= KFile::SeparateDirs; 01462 if ( kc->readBoolEntry(QString::fromLatin1("Show Preview"), false)) 01463 defaultView |= KFile::PreviewContents; 01464 01465 if ( kc->readBoolEntry( QString::fromLatin1("Sort case insensitively"), 01466 DefaultCaseInsensitive ) ) 01467 sorting |= QDir::IgnoreCase; 01468 if ( kc->readBoolEntry( QString::fromLatin1("Sort directories first"), 01469 DefaultDirsFirst ) ) 01470 sorting |= QDir::DirsFirst; 01471 01472 01473 QString name = QString::fromLatin1("Name"); 01474 QString sortBy = kc->readEntry( QString::fromLatin1("Sort by"), name ); 01475 if ( sortBy == name ) 01476 sorting |= QDir::Name; 01477 else if ( sortBy == QString::fromLatin1("Size") ) 01478 sorting |= QDir::Size; 01479 else if ( sortBy == QString::fromLatin1("Date") ) 01480 sorting |= QDir::Time; 01481 01482 mySorting = static_cast<QDir::SortSpec>( sorting ); 01483 setSorting( mySorting ); 01484 01485 01486 if ( kc->readBoolEntry( QString::fromLatin1("Show hidden files"), 01487 DefaultShowHidden ) ) { 01488 showHiddenAction->setChecked( true ); 01489 dir->setShowingDotFiles( true ); 01490 } 01491 if ( kc->readBoolEntry( QString::fromLatin1("Sort reversed"), 01492 DefaultSortReversed ) ) 01493 reverseAction->setChecked( true ); 01494 01495 kc->setGroup( oldGroup ); 01496 } 01497 01498 void KDirOperator::writeConfig( KConfig *kc, const QString& group ) 01499 { 01500 if ( !kc ) 01501 return; 01502 01503 const QString oldGroup = kc->group(); 01504 01505 if ( !group.isEmpty() ) 01506 kc->setGroup( group ); 01507 01508 QString sortBy = QString::fromLatin1("Name"); 01509 if ( KFile::isSortBySize( mySorting ) ) 01510 sortBy = QString::fromLatin1("Size"); 01511 else if ( KFile::isSortByDate( mySorting ) ) 01512 sortBy = QString::fromLatin1("Date"); 01513 kc->writeEntry( QString::fromLatin1("Sort by"), sortBy ); 01514 01515 kc->writeEntry( QString::fromLatin1("Sort reversed"), 01516 reverseAction->isChecked() ); 01517 kc->writeEntry( QString::fromLatin1("Sort case insensitively"), 01518 caseInsensitiveAction->isChecked() ); 01519 kc->writeEntry( QString::fromLatin1("Sort directories first"), 01520 dirsFirstAction->isChecked() ); 01521 01522 // don't save the separate dirs or preview when an application specific 01523 // preview is in use. 01524 bool appSpecificPreview = false; 01525 if ( myPreview ) { 01526 QWidget *preview = const_cast<QWidget*>( myPreview ); // grmbl 01527 KFileMetaPreview *tmp = dynamic_cast<KFileMetaPreview*>( preview ); 01528 appSpecificPreview = (tmp == 0L); 01529 } 01530 01531 if ( !appSpecificPreview ) { 01532 if ( separateDirsAction->isEnabled() ) 01533 kc->writeEntry( QString::fromLatin1("Separate Directories"), 01534 separateDirsAction->isChecked() ); 01535 01536 KToggleAction *previewAction = static_cast<KToggleAction*>(myActionCollection->action("preview")); 01537 if ( previewAction->isEnabled() ) { 01538 bool hasPreview = previewAction->isChecked(); 01539 kc->writeEntry( QString::fromLatin1("Show Preview"), hasPreview ); 01540 } 01541 } 01542 01543 kc->writeEntry( QString::fromLatin1("Show hidden files"), 01544 showHiddenAction->isChecked() ); 01545 01546 KFile::FileView fv = static_cast<KFile::FileView>( m_viewKind ); 01547 QString style; 01548 if ( KFile::isDetailView( fv ) ) 01549 style = QString::fromLatin1("Detail"); 01550 else if ( KFile::isSimpleView( fv ) ) 01551 style = QString::fromLatin1("Simple"); 01552 kc->writeEntry( QString::fromLatin1("View Style"), style ); 01553 01554 kc->setGroup( oldGroup ); 01555 } 01556 01557 01558 void KDirOperator::resizeEvent( QResizeEvent * ) 01559 { 01560 if (m_fileView) 01561 m_fileView->widget()->resize( size() ); 01562 01563 if ( progress->parent() == this ) // might be reparented into a statusbar 01564 progress->move(2, height() - progress->height() -2); 01565 } 01566 01567 void KDirOperator::setOnlyDoubleClickSelectsFiles( bool enable ) 01568 { 01569 d->onlyDoubleClickSelectsFiles = enable; 01570 if ( m_fileView ) 01571 m_fileView->setOnlyDoubleClickSelectsFiles( enable ); 01572 } 01573 01574 bool KDirOperator::onlyDoubleClickSelectsFiles() const 01575 { 01576 return d->onlyDoubleClickSelectsFiles; 01577 } 01578 01579 void KDirOperator::slotStarted() 01580 { 01581 progress->setProgress( 0 ); 01582 // delay showing the progressbar for one second 01583 d->progressDelayTimer->start( 1000, true ); 01584 } 01585 01586 void KDirOperator::slotShowProgress() 01587 { 01588 progress->raise(); 01589 progress->show(); 01590 QApplication::flushX(); 01591 } 01592 01593 void KDirOperator::slotProgress( int percent ) 01594 { 01595 progress->setProgress( percent ); 01596 // we have to redraw this as fast as possible 01597 if ( progress->isVisible() ) 01598 QApplication::flushX(); 01599 } 01600 01601 01602 void KDirOperator::slotIOFinished() 01603 { 01604 d->progressDelayTimer->stop(); 01605 slotProgress( 100 ); 01606 progress->hide(); 01607 emit finishedLoading(); 01608 resetCursor(); 01609 01610 if ( m_fileView ) 01611 m_fileView->listingCompleted(); 01612 } 01613 01614 void KDirOperator::slotCanceled() 01615 { 01616 emit finishedLoading(); 01617 resetCursor(); 01618 01619 if ( m_fileView ) 01620 m_fileView->listingCompleted(); 01621 } 01622 01623 KProgress * KDirOperator::progressBar() const 01624 { 01625 return progress; 01626 } 01627 01628 void KDirOperator::clearHistory() 01629 { 01630 backStack.clear(); 01631 backAction->setEnabled( false ); 01632 forwardStack.clear(); 01633 forwardAction->setEnabled( false ); 01634 } 01635 01636 void KDirOperator::slotViewActionAdded( KAction *action ) 01637 { 01638 if ( viewActionMenu->popupMenu()->count() == 5 ) // need to add a separator 01639 viewActionMenu->insert( d->viewActionSeparator ); 01640 01641 viewActionMenu->insert( action ); 01642 } 01643 01644 void KDirOperator::slotViewActionRemoved( KAction *action ) 01645 { 01646 viewActionMenu->remove( action ); 01647 01648 if ( viewActionMenu->popupMenu()->count() == 6 ) // remove the separator 01649 viewActionMenu->remove( d->viewActionSeparator ); 01650 } 01651 01652 void KDirOperator::slotViewSortingChanged( QDir::SortSpec sort ) 01653 { 01654 mySorting = sort; 01655 updateSortActions(); 01656 } 01657 01658 void KDirOperator::setEnableDirHighlighting( bool enable ) 01659 { 01660 d->dirHighlighting = enable; 01661 } 01662 01663 bool KDirOperator::dirHighlighting() const 01664 { 01665 return d->dirHighlighting; 01666 } 01667 01668 void KDirOperator::slotProperties() 01669 { 01670 if ( m_fileView ) { 01671 const KFileItemList *list = m_fileView->selectedItems(); 01672 if ( !list->isEmpty() ) 01673 (void) new KPropertiesDialog( *list, this, "props dlg", true); 01674 } 01675 } 01676 01677 void KDirOperator::slotClearView() 01678 { 01679 if ( m_fileView ) 01680 m_fileView->clearView(); 01681 } 01682 01683 // ### temporary code 01684 #include <dirent.h> 01685 bool KDirOperator::isReadable( const KURL& url ) 01686 { 01687 if ( !url.isLocalFile() ) 01688 return true; // what else can we say? 01689 01690 KDE_struct_stat buf; 01691 QString ts = url.path(+1); 01692 bool readable = ( KDE_stat( QFile::encodeName( ts ), &buf) == 0 ); 01693 if (readable) { // further checks 01694 DIR *test; 01695 test = opendir( QFile::encodeName( ts )); // we do it just to test here 01696 readable = (test != 0); 01697 if (test) 01698 closedir(test); 01699 } 01700 return readable; 01701 } 01702 01703 void KDirOperator::togglePreview( bool on ) 01704 { 01705 if ( on ) 01706 slotDefaultPreview(); 01707 else 01708 setView( (KFile::FileView) (m_viewKind & ~(KFile::PreviewContents|KFile::PreviewInfo)) ); 01709 } 01710 01711 void KDirOperator::slotRefreshItems( const KFileItemList& items ) 01712 { 01713 if ( !m_fileView ) 01714 return; 01715 01716 KFileItemListIterator it( items ); 01717 for ( ; it.current(); ++it ) 01718 m_fileView->updateView( it.current() ); 01719 } 01720 01721 void KDirOperator::setViewConfig( KConfig *config, const QString& group ) 01722 { 01723 d->config = config; 01724 d->configGroup = group; 01725 } 01726 01727 KConfig * KDirOperator::viewConfig() 01728 { 01729 return d->config; 01730 } 01731 01732 QString KDirOperator::viewConfigGroup() const 01733 { 01734 return d->configGroup; 01735 } 01736 01737 void KDirOperator::virtual_hook( int, void* ) 01738 { /*BASE::virtual_hook( id, data );*/ } 01739 01740 #include "kdiroperator.moc"