2 Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
3 Copyright (C) 2001 Michael Jarrett <michaelj@corel.com>
4 Copyright (C) 2009 Shaun Reich <shaun.reich@kdemail.net>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License version 2 as published by the Free Software Foundation.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include "kdirselectdialog.h"
23 #include <QtCore/QDir>
24 #include <QtCore/QStringList>
25 #include <QtGui/QLayout>
27 #include <kactioncollection.h>
28 #include <kapplication.h>
29 #include <kauthorized.h>
31 #include <kconfiggroup.h>
32 #include <khistorycombobox.h>
33 #include <kfiledialog.h>
34 #include <kfiletreeview.h>
35 #include <kfileitemdelegate.h>
36 #include <kglobalsettings.h>
38 #include <kinputdialog.h>
40 #include <kio/deletejob.h>
41 #include <kio/copyjob.h>
42 #include <kio/netaccess.h>
43 #include <kio/renamedialog.h>
44 #include <jobuidelegate.h>
46 #include <kmessagebox.h>
47 #include <krecentdirs.h>
48 #include <ktoggleaction.h>
49 #include <kurlcompletion.h>
50 #include <kurlpixmapprovider.h>
52 #include <kpropertiesdialog.h>
53 #include <kpushbutton.h>
56 #include "kfileplacesview.h"
57 #include "kfileplacesmodel.h"
58 // ### add mutator for treeview!
62 class KDirSelectDialog::Private
65 Private( bool localOnly
, KDirSelectDialog
*parent
)
67 m_localOnly( localOnly
),
68 m_comboLocked( false ),
73 void readConfig(const KSharedConfigPtr
&config
, const QString
& group
);
74 void saveConfig(KSharedConfigPtr config
, const QString
& group
);
77 void slotCurrentChanged();
78 void slotExpand(const QModelIndex
&);
79 void slotUrlActivated(const QString
&);
80 void slotComboTextChanged(const QString
&);
81 void slotContextMenuRequested(const QPoint
&);
83 void slotMoveToTrash();
85 void slotProperties();
87 KDirSelectDialog
*m_parent
;
89 bool m_comboLocked
: 1;
92 KFileTreeView
*m_treeView
;
94 KActionCollection
*m_actions
;
95 KFilePlacesView
*m_placesView
;
96 KHistoryComboBox
*m_urlCombo
;
97 QString m_recentDirClass
;
100 KAction
* deleteAction
;
103 void KDirSelectDialog::Private::readConfig(const KSharedConfig::Ptr
&config
, const QString
& group
)
107 KConfigGroup
conf( config
, group
);
108 m_urlCombo
->setHistoryItems( conf
.readPathEntry( "History Items", QStringList() ));
110 m_parent
->resize( conf
.readEntry( "DirSelectDialog Size", QSize( 400, 450 ) ) );
113 void KDirSelectDialog::Private::saveConfig(KSharedConfig::Ptr config
, const QString
& group
)
115 KConfigGroup
conf( config
, group
);
116 KConfigGroup::WriteConfigFlags
flags(KConfigGroup::Persistent
|KConfigGroup::Global
);
117 conf
.writePathEntry( "History Items", m_urlCombo
->historyItems(), flags
);
118 conf
.writeEntry( "DirSelectDialog Size", m_parent
->size(), flags
);
123 void KDirSelectDialog::Private::slotMkdir()
126 QString where
= m_parent
->url().pathOrUrl();
127 QString name
= i18nc("folder name", "New Folder" );
128 if ( m_parent
->url().isLocalFile() && QFileInfo( m_parent
->url().path(KUrl::AddTrailingSlash
) + name
).exists() )
129 name
= KIO::RenameDialog::suggestName( m_parent
->url(), name
);
131 QString directory
= KIO::encodeFileName( KInputDialog::getText( i18nc("@title:window", "New Folder" ),
132 i18nc("@label:textbox", "Create new folder in:\n%1" , where
),
133 name
, &ok
, m_parent
));
137 bool selectDirectory
= true;
138 bool writeOk
= false;
140 KUrl
folderurl( m_parent
->url() );
142 const QStringList dirs
= directory
.split( QDir::separator(), QString::SkipEmptyParts
);
143 QStringList::ConstIterator it
= dirs
.begin();
145 for ( ; it
!= dirs
.end(); ++it
)
147 folderurl
.addPath( *it
);
148 exists
= KIO::NetAccess::exists( folderurl
, KIO::NetAccess::DestinationSide
, 0 );
149 writeOk
= !exists
&& KIO::NetAccess::mkdir( folderurl
, m_parent
->topLevelWidget() );
152 if ( exists
) // url was already existent
154 QString which
= folderurl
.isLocalFile() ? folderurl
.path() : folderurl
.prettyUrl();
155 KMessageBox::sorry(m_parent
, i18n("A file or folder named %1 already exists.", which
));
156 selectDirectory
= false;
158 else if ( !writeOk
) {
159 KMessageBox::sorry(m_parent
, i18n("You do not have permission to create that folder." ));
161 else if ( selectDirectory
) {
162 m_parent
->setCurrentUrl( folderurl
);
166 void KDirSelectDialog::Private::slotCurrentChanged()
171 const KUrl u
= m_treeView
->currentUrl();
175 if ( u
.isLocalFile() )
176 m_urlCombo
->setEditText( u
.toLocalFile() );
179 m_urlCombo
->setEditText( u
.prettyUrl() );
182 m_urlCombo
->setEditText( QString() );
185 void KDirSelectDialog::Private::slotUrlActivated( const QString
& text
)
187 if ( text
.isEmpty() )
191 m_urlCombo
->addToHistory( url
.prettyUrl() );
193 if ( m_parent
->localOnly() && !url
.isLocalFile() )
194 return; //FIXME: messagebox for the user
196 KUrl oldUrl
= m_treeView
->currentUrl();
197 if ( oldUrl
.isEmpty() )
200 m_parent
->setCurrentUrl( oldUrl
);
203 void KDirSelectDialog::Private::slotComboTextChanged( const QString
& text
)
205 m_treeView
->blockSignals(true);
206 m_treeView
->setCurrentUrl( KUrl( text
) );
207 m_treeView
->blockSignals(false);
210 void KDirSelectDialog::Private::slotContextMenuRequested( const QPoint
& pos
)
212 m_contextMenu
->popup( m_treeView
->viewport()->mapToGlobal(pos
) );
215 void KDirSelectDialog::Private::slotExpand(const QModelIndex
&index
)
217 m_treeView
->setExpanded(index
, !m_treeView
->isExpanded(index
));
220 void KDirSelectDialog::Private::slotNewFolder()
225 void KDirSelectDialog::Private::slotMoveToTrash()
227 const KUrl url
= m_treeView
->selectedUrl();
228 KIO::JobUiDelegate job
;
229 if (job
.askDeleteConfirmation(KUrl::List() << url
, KIO::JobUiDelegate::Trash
, KIO::JobUiDelegate::DefaultConfirmation
)) {
230 KIO::CopyJob
* copyJob
= KIO::trash(url
);
231 copyJob
->ui()->setWindow(this->m_parent
);
232 copyJob
->ui()->setAutoErrorHandlingEnabled(true);
236 void KDirSelectDialog::Private::slotDelete()
238 const KUrl url
= m_treeView
->selectedUrl();
239 KIO::JobUiDelegate job
;
240 if (job
.askDeleteConfirmation(KUrl::List() << url
, KIO::JobUiDelegate::Delete
, KIO::JobUiDelegate::DefaultConfirmation
)) {
241 KIO::DeleteJob
* deleteJob
= KIO::del(url
);
242 deleteJob
->ui()->setWindow(this->m_parent
);
243 deleteJob
->ui()->setAutoErrorHandlingEnabled(true);
247 void KDirSelectDialog::Private::slotProperties()
249 KPropertiesDialog
* dialog
= 0;
250 dialog
= new KPropertiesDialog(m_treeView
->selectedUrl(), this->m_parent
);
251 dialog
->setAttribute(Qt::WA_DeleteOnClose
);
256 KDirSelectDialog::KDirSelectDialog(const KUrl
&startDir
, bool localOnly
,
259 : KDialog( parent
, Qt::WindowMinMaxButtonsHint
),
263 d( new Private( localOnly
, this ) )
265 setCaption( i18nc("@title:window","Select Folder") );
266 setButtons( Ok
| Cancel
| User1
);
267 setButtonGuiItem( User1
, KGuiItem( i18nc("@action:button","New Folder..."), "folder-new" ) );
268 showButtonSeparator(false);
269 setDefaultButton(Ok
);
270 button(Ok
)->setFocus();
272 QFrame
*page
= new QFrame(this);
274 QHBoxLayout
*hlay
= new QHBoxLayout( page
);
276 hlay
->setSpacing(spacingHint());
277 QVBoxLayout
*mainLayout
= new QVBoxLayout();
278 d
->m_actions
=new KActionCollection(this);
279 d
->m_placesView
= new KFilePlacesView( page
);
280 d
->m_placesView
->setModel(new KFilePlacesModel(d
->m_placesView
));
281 d
->m_placesView
->setObjectName( QLatin1String( "speedbar" ) );
282 d
->m_placesView
->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff
);
283 d
->m_placesView
->setSizePolicy(QSizePolicy::Minimum
, QSizePolicy::Minimum
);
284 connect( d
->m_placesView
, SIGNAL( urlChanged( const KUrl
& )),
285 SLOT( setCurrentUrl( const KUrl
& )) );
286 hlay
->addWidget( d
->m_placesView
);
287 hlay
->addLayout( mainLayout
);
289 d
->m_treeView
= new KFileTreeView(page
);
290 d
->m_treeView
->setDirOnlyMode(true);
291 d
->m_treeView
->setContextMenuPolicy(Qt::CustomContextMenu
);
293 for (int i
= 1; i
< d
->m_treeView
->model()->columnCount(); ++i
)
294 d
->m_treeView
->hideColumn(i
);
296 d
->m_urlCombo
= new KHistoryComboBox( page
);
297 d
->m_urlCombo
->setLayoutDirection( Qt::LeftToRight
);
298 d
->m_urlCombo
->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength
);
299 d
->m_urlCombo
->setTrapReturnKey( true );
300 d
->m_urlCombo
->setPixmapProvider( new KUrlPixmapProvider() );
301 KUrlCompletion
*comp
= new KUrlCompletion();
302 comp
->setMode( KUrlCompletion::DirCompletion
);
303 d
->m_urlCombo
->setCompletionObject( comp
, true );
304 d
->m_urlCombo
->setAutoDeleteCompletionObject( true );
305 d
->m_urlCombo
->setDuplicatesEnabled( false );
307 d
->m_contextMenu
= new KMenu( this );
309 KAction
* newFolder
= new KAction( i18nc("@action:inmenu","New Folder..."), this);
310 d
->m_actions
->addAction( newFolder
->objectName(), newFolder
);
311 newFolder
->setIcon( KIcon( "folder-new" ) );
312 newFolder
->setShortcut( Qt::Key_F10
);
313 connect( newFolder
, SIGNAL( triggered( bool ) ), this, SLOT( slotNewFolder() ) );
314 d
->m_contextMenu
->addAction( newFolder
);
316 d
->moveToTrash
= new KAction( i18nc( "@action:inmenu","Move to trash" ), this );
317 d
->m_actions
->addAction( d
->moveToTrash
->objectName(), d
->moveToTrash
);
318 d
->moveToTrash
->setIcon( KIcon( "user-trash" ) );
319 d
->moveToTrash
->setShortcut(KShortcut(Qt::Key_Delete
));
320 connect( d
->moveToTrash
, SIGNAL( triggered( bool ) ), this, SLOT( slotMoveToTrash() ) );
321 d
->m_contextMenu
->addAction( d
->moveToTrash
);
323 d
->deleteAction
= new KAction( i18nc("@action:inmenu","Delete"), this );
324 d
->m_actions
->addAction( d
->deleteAction
->objectName(), d
->deleteAction
);
325 d
->deleteAction
->setIcon( KIcon( "edit-delete" ) );
326 d
->deleteAction
->setShortcut( KShortcut( Qt::SHIFT
+ Qt::Key_Delete
) );
327 connect( d
->deleteAction
, SIGNAL( triggered( bool ) ), this, SLOT( slotDelete() ) );
328 d
->m_contextMenu
->addAction( d
->deleteAction
);
330 d
->m_contextMenu
->addSeparator();
332 KToggleAction
*showHiddenFolders
= new KToggleAction( i18nc("@option:check", "Show Hidden Folders"), this );
333 d
->m_actions
->addAction( showHiddenFolders
->objectName(), showHiddenFolders
);
334 connect( showHiddenFolders
, SIGNAL( triggered( bool ) ), d
->m_treeView
, SLOT( setShowHiddenFiles( bool ) ) );
335 d
->m_contextMenu
->addAction( showHiddenFolders
);
336 d
->m_contextMenu
->addSeparator();
338 KAction
* propertiesAction
= new KAction( i18nc("@action:inmenu","Properties"), this);
339 d
->m_actions
->addAction(propertiesAction
->objectName(), propertiesAction
);
340 propertiesAction
->setIcon(KIcon("document-properties"));
341 propertiesAction
->setShortcut(KShortcut(Qt::ALT
+ Qt::Key_Return
));
342 connect( propertiesAction
, SIGNAL( triggered( bool ) ), this, SLOT( slotProperties() ) );
343 d
->m_contextMenu
->addAction( propertiesAction
);
345 d
->m_startURL
= KFileDialog::getStartUrl( startDir
, d
->m_recentDirClass
);
346 if ( localOnly
&& !d
->m_startURL
.isLocalFile() )
348 d
->m_startURL
= KUrl();
349 QString docPath
= KGlobalSettings::documentPath();
350 if (QDir(docPath
).exists())
351 d
->m_startURL
.setPath( docPath
);
353 d
->m_startURL
.setPath( QDir::homePath() );
356 d
->m_startDir
= d
->m_startURL
;
357 d
->m_rootUrl
= d
->m_treeView
->rootUrl();
359 d
->readConfig( KGlobal::config(), "DirSelect Dialog" );
361 mainLayout
->addWidget( d
->m_treeView
, 1 );
362 mainLayout
->addWidget( d
->m_urlCombo
, 0 );
364 connect( d
->m_treeView
, SIGNAL( currentChanged(const KUrl
&)),
365 SLOT( slotCurrentChanged() ));
366 connect( d
->m_treeView
, SIGNAL( activated(const QModelIndex
&)),
367 SLOT( slotExpand(const QModelIndex
&) ));
368 connect( d
->m_treeView
, SIGNAL( customContextMenuRequested( const QPoint
& )),
369 SLOT( slotContextMenuRequested( const QPoint
& )));
371 connect( d
->m_urlCombo
, SIGNAL( editTextChanged( const QString
& ) ),
372 SLOT( slotComboTextChanged( const QString
& ) ));
373 connect( d
->m_urlCombo
, SIGNAL( activated( const QString
& )),
374 SLOT( slotUrlActivated( const QString
& )));
375 connect( d
->m_urlCombo
, SIGNAL( returnPressed( const QString
& )),
376 SLOT( slotUrlActivated( const QString
& )));
378 connect(this, SIGNAL(user1Clicked()), this, SLOT(slotNewFolder()));
380 setCurrentUrl(d
->m_startURL
);
384 KDirSelectDialog::~KDirSelectDialog()
389 KUrl
KDirSelectDialog::url() const
391 KUrl
comboUrl(d
->m_urlCombo
->currentText());
393 if ( comboUrl
.isValid() ) {
394 KIO::StatJob
*statJob
= KIO::stat(comboUrl
, KIO::HideProgressInfo
);
395 const bool ok
= KIO::NetAccess::synchronousRun(statJob
, 0);
396 if (ok
&& statJob
->statResult().isDir()) {
401 kDebug() << comboUrl
.path() << " is not an accessible directory";
402 return d
->m_treeView
->currentUrl();
405 QAbstractItemView
* KDirSelectDialog::view() const
407 return d
->m_treeView
;
410 bool KDirSelectDialog::localOnly() const
412 return d
->m_localOnly
;
415 KUrl
KDirSelectDialog::startDir() const
417 return d
->m_startDir
;
420 void KDirSelectDialog::setCurrentUrl( const KUrl
& url
)
422 if ( !url
.isValid() )
425 if (url
.protocol() != d
->m_rootUrl
.protocol()) {
427 u
.cd("/");//NOTE portability?
428 d
->m_treeView
->setRootUrl( u
);
432 d
->m_treeView
->setCurrentUrl( url
);
435 void KDirSelectDialog::accept()
437 KUrl selectedUrl
= url();
438 if (!selectedUrl
.isValid()) {
442 if (!d
->m_recentDirClass
.isEmpty()) {
443 KRecentDirs::add(d
->m_recentDirClass
, selectedUrl
.url());
446 d
->m_urlCombo
->addToHistory( selectedUrl
.prettyUrl() );
447 KFileDialog::setStartDir( url() );
452 void KDirSelectDialog::hideEvent( QHideEvent
*event
)
454 d
->saveConfig( KGlobal::config(), "DirSelect Dialog" );
456 KDialog::hideEvent(event
);
460 KUrl
KDirSelectDialog::selectDirectory( const KUrl
& startDir
,
463 const QString
& caption
)
465 KDirSelectDialog
myDialog( startDir
, localOnly
, parent
);
467 if ( !caption
.isNull() )
468 myDialog
.setCaption( caption
);
470 if ( myDialog
.exec() == QDialog::Accepted
)
471 return KIO::NetAccess::mostLocalUrl(myDialog
.url(),parent
);
476 #include "kdirselectdialog.moc"