00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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 )
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
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;
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 showButtonSeparator(false);
00282 setDefaultButton(Ok);
00283 button(Ok)->setFocus();
00284
00285 QFrame *page = new QFrame(this);
00286 setMainWidget(page);
00287 QHBoxLayout *hlay = new QHBoxLayout( page);
00288 hlay->setMargin(0);
00289 QVBoxLayout *mainLayout = new QVBoxLayout();
00290 d->m_actions=new KActionCollection(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("/");
00441 d->m_treeView->setRootUrl( u );
00442 d->m_rootUrl = u;
00443 }
00444
00445
00446 QString fileName = url.fileName();
00447
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
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"