KFile
kdirselectdialog.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org> 00003 Copyright (C) 2001 Michael Jarrett <michaelj@corel.com> 00004 Copyright (C) 2009 Shaun Reich <shaun.reich@kdemail.net> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 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 "kdirselectdialog.h" 00022 00023 #include <QtCore/QDir> 00024 #include <QtCore/QStringList> 00025 #include <QtGui/QLayout> 00026 00027 #include <kactioncollection.h> 00028 #include <kapplication.h> 00029 #include <kauthorized.h> 00030 #include <kconfig.h> 00031 #include <kconfiggroup.h> 00032 #include <khistorycombobox.h> 00033 #include <kfiledialog.h> 00034 #include <kfiletreeview.h> 00035 #include <kfileitemdelegate.h> 00036 #include <kglobalsettings.h> 00037 #include <kicon.h> 00038 #include <kinputdialog.h> 00039 #include <kio/job.h> 00040 #include <kio/deletejob.h> 00041 #include <kio/copyjob.h> 00042 #include <kio/netaccess.h> 00043 #include <kio/renamedialog.h> 00044 #include <jobuidelegate.h> 00045 #include <klocale.h> 00046 #include <kmessagebox.h> 00047 #include <krecentdirs.h> 00048 #include <ktoggleaction.h> 00049 #include <kurlcompletion.h> 00050 #include <kurlpixmapprovider.h> 00051 #include <kdebug.h> 00052 #include <kpropertiesdialog.h> 00053 #include <kpushbutton.h> 00054 #include <kmenu.h> 00055 00056 #include "kfileplacesview.h" 00057 #include "kfileplacesmodel.h" 00058 // ### add mutator for treeview! 00059 00060 00061 00062 class KDirSelectDialog::Private 00063 { 00064 public: 00065 Private( bool localOnly, KDirSelectDialog *parent ) 00066 : m_parent( parent ), 00067 m_localOnly( localOnly ), 00068 m_comboLocked( false ), 00069 m_urlCombo(0) 00070 { 00071 } 00072 00073 void readConfig(const KSharedConfigPtr &config, const QString& group); 00074 void saveConfig(KSharedConfigPtr config, const QString& group); 00075 void slotMkdir(); 00076 00077 void slotCurrentChanged(); 00078 void slotExpand(const QModelIndex&); 00079 void slotUrlActivated(const QString&); 00080 void slotComboTextChanged(const QString&); 00081 void slotContextMenuRequested(const QPoint&); 00082 void slotNewFolder(); 00083 void slotMoveToTrash(); 00084 void slotDelete(); 00085 void slotProperties(); 00086 00087 KDirSelectDialog *m_parent; 00088 bool m_localOnly : 1; 00089 bool m_comboLocked : 1; 00090 KUrl m_rootUrl; 00091 KUrl m_startDir; 00092 KFileTreeView *m_treeView; 00093 KMenu *m_contextMenu; 00094 KActionCollection *m_actions; 00095 KFilePlacesView *m_placesView; 00096 KHistoryComboBox *m_urlCombo; 00097 QString m_recentDirClass; 00098 KUrl m_startURL; 00099 KAction* moveToTrash; 00100 KAction* deleteAction; 00101 KAction* showHiddenFoldersAction; 00102 }; 00103 00104 void KDirSelectDialog::Private::readConfig(const KSharedConfig::Ptr &config, const QString& group) 00105 { 00106 m_urlCombo->clear(); 00107 00108 KConfigGroup conf( config, group ); 00109 m_urlCombo->setHistoryItems( conf.readPathEntry( "History Items", QStringList() )); 00110 00111 m_parent->resize( conf.readEntry( "DirSelectDialog Size", QSize( 400, 450 ) ) ); 00112 } 00113 00114 void KDirSelectDialog::Private::saveConfig(KSharedConfig::Ptr config, const QString& group) 00115 { 00116 KConfigGroup conf( config, group ); 00117 KConfigGroup::WriteConfigFlags flags(KConfigGroup::Persistent|KConfigGroup::Global); 00118 conf.writePathEntry( "History Items", m_urlCombo->historyItems(), flags ); 00119 conf.writeEntry( "DirSelectDialog Size", m_parent->size(), flags ); 00120 00121 config->sync(); 00122 } 00123 00124 void KDirSelectDialog::Private::slotMkdir() 00125 { 00126 bool ok; 00127 QString where = m_parent->url().pathOrUrl(); 00128 QString name = i18nc("folder name", "New Folder" ); 00129 if ( m_parent->url().isLocalFile() && QFileInfo( m_parent->url().path(KUrl::AddTrailingSlash) + name ).exists() ) 00130 name = KIO::RenameDialog::suggestName( m_parent->url(), name ); 00131 00132 QString directory = KIO::encodeFileName( KInputDialog::getText( i18nc("@title:window", "New Folder" ), 00133 i18nc("@label:textbox", "Create new folder in:\n%1" , where ), 00134 name, &ok, m_parent)); 00135 if (!ok) 00136 return; 00137 00138 bool selectDirectory = true; 00139 bool writeOk = false; 00140 bool exists = false; 00141 KUrl folderurl( m_parent->url() ); 00142 00143 const QStringList dirs = directory.split( '/', QString::SkipEmptyParts ); 00144 QStringList::ConstIterator it = dirs.begin(); 00145 00146 for ( ; it != dirs.end(); ++it ) 00147 { 00148 folderurl.addPath( *it ); 00149 exists = KIO::NetAccess::exists( folderurl, KIO::NetAccess::DestinationSide, 0 ); 00150 writeOk = !exists && KIO::NetAccess::mkdir( folderurl, m_parent->topLevelWidget() ); 00151 } 00152 00153 if ( exists ) // url was already existent 00154 { 00155 QString which = folderurl.isLocalFile() ? folderurl.path() : folderurl.prettyUrl(); 00156 KMessageBox::sorry(m_parent, i18n("A file or folder named %1 already exists.", which)); 00157 selectDirectory = false; 00158 } 00159 else if ( !writeOk ) { 00160 KMessageBox::sorry(m_parent, i18n("You do not have permission to create that folder." )); 00161 } 00162 else if ( selectDirectory ) { 00163 m_parent->setCurrentUrl( folderurl ); 00164 } 00165 } 00166 00167 void KDirSelectDialog::Private::slotCurrentChanged() 00168 { 00169 if ( m_comboLocked ) 00170 return; 00171 00172 const KUrl u = m_treeView->currentUrl(); 00173 00174 if ( u.isValid() ) 00175 { 00176 if ( u.isLocalFile() ) 00177 m_urlCombo->setEditText( u.toLocalFile() ); 00178 00179 else // remote url 00180 m_urlCombo->setEditText( u.prettyUrl() ); 00181 } 00182 else 00183 m_urlCombo->setEditText( QString() ); 00184 } 00185 00186 void KDirSelectDialog::Private::slotUrlActivated( const QString& text ) 00187 { 00188 if ( text.isEmpty() ) 00189 return; 00190 00191 KUrl url( text ); 00192 m_urlCombo->addToHistory( url.prettyUrl() ); 00193 00194 if ( m_parent->localOnly() && !url.isLocalFile() ) 00195 return; //FIXME: messagebox for the user 00196 00197 KUrl oldUrl = m_treeView->currentUrl(); 00198 if ( oldUrl.isEmpty() ) 00199 oldUrl = m_startDir; 00200 00201 m_parent->setCurrentUrl( oldUrl ); 00202 } 00203 00204 void KDirSelectDialog::Private::slotComboTextChanged( const QString& text ) 00205 { 00206 m_treeView->blockSignals(true); 00207 KUrl url( text ); 00208 #ifdef Q_OS_WIN 00209 if( url.isLocalFile() && !m_treeView->rootUrl().isParentOf( url ) ) 00210 { 00211 KUrl tmp = url.upUrl(); 00212 while(tmp != KUrl("file:///")) { 00213 url = tmp; 00214 tmp = url.upUrl(); 00215 } 00216 m_treeView->setRootUrl( url ); 00217 } 00218 #endif 00219 m_treeView->setCurrentUrl( url ); 00220 m_treeView->blockSignals( false ); 00221 } 00222 00223 void KDirSelectDialog::Private::slotContextMenuRequested( const QPoint& pos ) 00224 { 00225 m_contextMenu->popup( m_treeView->viewport()->mapToGlobal(pos) ); 00226 } 00227 00228 void KDirSelectDialog::Private::slotExpand(const QModelIndex &index) 00229 { 00230 m_treeView->setExpanded(index, !m_treeView->isExpanded(index)); 00231 } 00232 00233 void KDirSelectDialog::Private::slotNewFolder() 00234 { 00235 slotMkdir(); 00236 } 00237 00238 void KDirSelectDialog::Private::slotMoveToTrash() 00239 { 00240 const KUrl url = m_treeView->selectedUrl(); 00241 KIO::JobUiDelegate job; 00242 if (job.askDeleteConfirmation(KUrl::List() << url, KIO::JobUiDelegate::Trash, KIO::JobUiDelegate::DefaultConfirmation)) { 00243 KIO::CopyJob* copyJob = KIO::trash(url); 00244 copyJob->ui()->setWindow(this->m_parent); 00245 copyJob->ui()->setAutoErrorHandlingEnabled(true); 00246 } 00247 } 00248 00249 void KDirSelectDialog::Private::slotDelete() 00250 { 00251 const KUrl url = m_treeView->selectedUrl(); 00252 KIO::JobUiDelegate job; 00253 if (job.askDeleteConfirmation(KUrl::List() << url, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::DefaultConfirmation)) { 00254 KIO::DeleteJob* deleteJob = KIO::del(url); 00255 deleteJob->ui()->setWindow(this->m_parent); 00256 deleteJob->ui()->setAutoErrorHandlingEnabled(true); 00257 } 00258 } 00259 00260 void KDirSelectDialog::Private::slotProperties() 00261 { 00262 KPropertiesDialog* dialog = 0; 00263 dialog = new KPropertiesDialog(m_treeView->selectedUrl(), this->m_parent); 00264 dialog->setAttribute(Qt::WA_DeleteOnClose); 00265 dialog->show(); 00266 } 00267 00268 00269 KDirSelectDialog::KDirSelectDialog(const KUrl &startDir, bool localOnly, 00270 QWidget *parent) 00271 #ifdef Q_WS_WIN 00272 : KDialog( parent , Qt::WindowMinMaxButtonsHint), 00273 #else 00274 : KDialog( parent ), 00275 #endif 00276 d( new Private( localOnly, this ) ) 00277 { 00278 setCaption( i18nc("@title:window","Select Folder") ); 00279 setButtons( Ok | Cancel | User1 ); 00280 setButtonGuiItem( User1, KGuiItem( i18nc("@action:button","New Folder..."), "folder-new" ) ); 00281 setDefaultButton(Ok); 00282 button(Ok)->setFocus(); 00283 00284 QFrame *page = new QFrame(this); 00285 setMainWidget(page); 00286 QHBoxLayout *hlay = new QHBoxLayout( page); 00287 hlay->setMargin(0); 00288 QVBoxLayout *mainLayout = new QVBoxLayout(); 00289 d->m_actions=new KActionCollection(this); 00290 d->m_actions->addAssociatedWidget(this); 00291 d->m_placesView = new KFilePlacesView( page ); 00292 d->m_placesView->setModel(new KFilePlacesModel(d->m_placesView)); 00293 d->m_placesView->setObjectName( QLatin1String( "speedbar" ) ); 00294 d->m_placesView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 00295 d->m_placesView->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); 00296 connect( d->m_placesView, SIGNAL( urlChanged( const KUrl& )), 00297 SLOT( setCurrentUrl( const KUrl& )) ); 00298 hlay->addWidget( d->m_placesView ); 00299 hlay->addLayout( mainLayout ); 00300 00301 d->m_treeView = new KFileTreeView(page); 00302 d->m_treeView->setDirOnlyMode(true); 00303 d->m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); 00304 00305 for (int i = 1; i < d->m_treeView->model()->columnCount(); ++i) 00306 d->m_treeView->hideColumn(i); 00307 00308 d->m_urlCombo = new KHistoryComboBox( page); 00309 d->m_urlCombo->setLayoutDirection( Qt::LeftToRight ); 00310 d->m_urlCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength); 00311 d->m_urlCombo->setTrapReturnKey( true ); 00312 d->m_urlCombo->setPixmapProvider( new KUrlPixmapProvider() ); 00313 KUrlCompletion *comp = new KUrlCompletion(); 00314 comp->setMode( KUrlCompletion::DirCompletion ); 00315 d->m_urlCombo->setCompletionObject( comp, true ); 00316 d->m_urlCombo->setAutoDeleteCompletionObject( true ); 00317 d->m_urlCombo->setDuplicatesEnabled( false ); 00318 00319 d->m_contextMenu = new KMenu( this ); 00320 00321 KAction* newFolder = new KAction( i18nc("@action:inmenu","New Folder..."), this); 00322 d->m_actions->addAction( newFolder->objectName(), newFolder ); 00323 newFolder->setIcon( KIcon( "folder-new" ) ); 00324 newFolder->setShortcut( Qt::Key_F10); 00325 connect( newFolder, SIGNAL( triggered( bool ) ), this, SLOT( slotNewFolder() ) ); 00326 d->m_contextMenu->addAction( newFolder ); 00327 00328 d->moveToTrash = new KAction( i18nc( "@action:inmenu","Move to Trash" ), this ); 00329 d->m_actions->addAction( d->moveToTrash->objectName(), d->moveToTrash ); 00330 d->moveToTrash->setIcon( KIcon( "user-trash" ) ); 00331 d->moveToTrash->setShortcut(KShortcut(Qt::Key_Delete)); 00332 connect( d->moveToTrash, SIGNAL( triggered( bool ) ), this, SLOT( slotMoveToTrash() ) ); 00333 d->m_contextMenu->addAction( d->moveToTrash ); 00334 00335 d->deleteAction = new KAction( i18nc("@action:inmenu","Delete"), this ); 00336 d->m_actions->addAction( d->deleteAction->objectName(), d->deleteAction ); 00337 d->deleteAction->setIcon( KIcon( "edit-delete" ) ); 00338 d->deleteAction->setShortcut( KShortcut( Qt::SHIFT + Qt::Key_Delete ) ); 00339 connect( d->deleteAction, SIGNAL( triggered( bool ) ), this, SLOT( slotDelete() ) ); 00340 d->m_contextMenu->addAction( d->deleteAction ); 00341 00342 d->m_contextMenu->addSeparator(); 00343 00344 d->showHiddenFoldersAction = new KToggleAction( i18nc("@option:check", "Show Hidden Folders"), this ); 00345 d->m_actions->addAction( d->showHiddenFoldersAction->objectName(), d->showHiddenFoldersAction ); 00346 d->showHiddenFoldersAction->setShortcut( Qt::Key_F8 ); 00347 connect( d->showHiddenFoldersAction, SIGNAL( triggered( bool ) ), d->m_treeView, SLOT( setShowHiddenFiles( bool ) ) ); 00348 d->m_contextMenu->addAction( d->showHiddenFoldersAction ); 00349 d->m_contextMenu->addSeparator(); 00350 00351 KAction* propertiesAction = new KAction( i18nc("@action:inmenu","Properties"), this); 00352 d->m_actions->addAction(propertiesAction->objectName(), propertiesAction); 00353 propertiesAction->setIcon(KIcon("document-properties")); 00354 propertiesAction->setShortcut(KShortcut(Qt::ALT + Qt::Key_Return)); 00355 connect( propertiesAction, SIGNAL( triggered( bool ) ), this, SLOT( slotProperties() ) ); 00356 d->m_contextMenu->addAction( propertiesAction ); 00357 00358 d->m_startURL = KFileDialog::getStartUrl( startDir, d->m_recentDirClass ); 00359 if ( localOnly && !d->m_startURL.isLocalFile() ) 00360 { 00361 d->m_startURL = KUrl(); 00362 QString docPath = KGlobalSettings::documentPath(); 00363 if (QDir(docPath).exists()) 00364 d->m_startURL.setPath( docPath ); 00365 else 00366 d->m_startURL.setPath( QDir::homePath() ); 00367 } 00368 00369 d->m_startDir = d->m_startURL; 00370 d->m_rootUrl = d->m_treeView->rootUrl(); 00371 00372 d->readConfig( KGlobal::config(), "DirSelect Dialog" ); 00373 00374 mainLayout->addWidget( d->m_treeView, 1 ); 00375 mainLayout->addWidget( d->m_urlCombo, 0 ); 00376 00377 connect( d->m_treeView, SIGNAL( currentChanged(const KUrl&)), 00378 SLOT( slotCurrentChanged() )); 00379 connect( d->m_treeView, SIGNAL( activated(const QModelIndex&)), 00380 SLOT( slotExpand(const QModelIndex&) )); 00381 connect( d->m_treeView, SIGNAL( customContextMenuRequested( const QPoint & )), 00382 SLOT( slotContextMenuRequested( const QPoint & ))); 00383 00384 connect( d->m_urlCombo, SIGNAL( editTextChanged( const QString& ) ), 00385 SLOT( slotComboTextChanged( const QString& ) )); 00386 connect( d->m_urlCombo, SIGNAL( activated( const QString& )), 00387 SLOT( slotUrlActivated( const QString& ))); 00388 connect( d->m_urlCombo, SIGNAL( returnPressed( const QString& )), 00389 SLOT( slotUrlActivated( const QString& ))); 00390 00391 connect(this, SIGNAL(user1Clicked()), this, SLOT(slotNewFolder())); 00392 00393 setCurrentUrl(d->m_startURL); 00394 } 00395 00396 00397 KDirSelectDialog::~KDirSelectDialog() 00398 { 00399 delete d; 00400 } 00401 00402 KUrl KDirSelectDialog::url() const 00403 { 00404 KUrl comboUrl(d->m_urlCombo->currentText()); 00405 00406 if ( comboUrl.isValid() ) { 00407 KIO::StatJob *statJob = KIO::stat(comboUrl, KIO::HideProgressInfo); 00408 const bool ok = KIO::NetAccess::synchronousRun(statJob, 0); 00409 if (ok && statJob->statResult().isDir()) { 00410 return comboUrl; 00411 } 00412 } 00413 00414 kDebug() << comboUrl.path() << " is not an accessible directory"; 00415 return d->m_treeView->currentUrl(); 00416 } 00417 00418 QAbstractItemView* KDirSelectDialog::view() const 00419 { 00420 return d->m_treeView; 00421 } 00422 00423 bool KDirSelectDialog::localOnly() const 00424 { 00425 return d->m_localOnly; 00426 } 00427 00428 KUrl KDirSelectDialog::startDir() const 00429 { 00430 return d->m_startDir; 00431 } 00432 00433 void KDirSelectDialog::setCurrentUrl( const KUrl& url ) 00434 { 00435 if ( !url.isValid() ) 00436 return; 00437 00438 if (url.protocol() != d->m_rootUrl.protocol()) { 00439 KUrl u( url ); 00440 u.cd("/");//NOTE portability? 00441 d->m_treeView->setRootUrl( u ); 00442 d->m_rootUrl = u; 00443 } 00444 00445 //Check if url represents a hidden folder and enable showing them 00446 QString fileName = url.fileName(); 00447 //TODO a better hidden file check? 00448 bool isHidden = fileName.length() > 1 && fileName[0] == '.' && 00449 (fileName.length() > 2 ? fileName[1] != '.' : true); 00450 bool showHiddenFiles = isHidden && !d->m_treeView->showHiddenFiles(); 00451 if (showHiddenFiles) { 00452 d->showHiddenFoldersAction->setChecked(true); 00453 d->m_treeView->setShowHiddenFiles(true); 00454 } 00455 00456 d->m_treeView->setCurrentUrl( url ); 00457 } 00458 00459 void KDirSelectDialog::accept() 00460 { 00461 KUrl selectedUrl = url(); 00462 if (!selectedUrl.isValid()) { 00463 return; 00464 } 00465 00466 if (!d->m_recentDirClass.isEmpty()) { 00467 KRecentDirs::add(d->m_recentDirClass, selectedUrl.url()); 00468 } 00469 00470 d->m_urlCombo->addToHistory( selectedUrl.prettyUrl() ); 00471 KFileDialog::setStartDir( url() ); 00472 00473 KDialog::accept(); 00474 } 00475 00476 void KDirSelectDialog::hideEvent( QHideEvent *event ) 00477 { 00478 d->saveConfig( KGlobal::config(), "DirSelect Dialog" ); 00479 00480 KDialog::hideEvent(event); 00481 } 00482 00483 // static 00484 KUrl KDirSelectDialog::selectDirectory( const KUrl& startDir, 00485 bool localOnly, 00486 QWidget *parent, 00487 const QString& caption) 00488 { 00489 KDirSelectDialog myDialog( startDir, localOnly, parent); 00490 00491 if ( !caption.isNull() ) 00492 myDialog.setCaption( caption ); 00493 00494 if ( myDialog.exec() == QDialog::Accepted ) 00495 return KIO::NetAccess::mostLocalUrl(myDialog.url(),parent); 00496 else 00497 return KUrl(); 00498 } 00499 00500 #include "kdirselectdialog.moc"
KDE 4.6 API Reference