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