kdirselectdialog.cpp
00001 /* 00002 Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org> 00003 Copyright (C) 2001 Michael Jarrett <michaelj@corel.com> 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 version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include <tqdir.h> 00021 #include <tqlayout.h> 00022 #include <tqpopupmenu.h> 00023 #include <tqstringlist.h> 00024 #include <tqvaluestack.h> 00025 00026 #include <tdeactionclasses.h> 00027 #include <tdeapplication.h> 00028 #include <kcombobox.h> 00029 #include <tdeconfig.h> 00030 #include <tdefiledialog.h> 00031 #include <tdefilespeedbar.h> 00032 #include <tdeglobalsettings.h> 00033 #include <kiconloader.h> 00034 #include <tdelocale.h> 00035 #include <kprotocolinfo.h> 00036 #include <tderecentdirs.h> 00037 #include <kshell.h> 00038 #include <kurl.h> 00039 #include <kurlcompletion.h> 00040 #include <kurlpixmapprovider.h> 00041 #include <kinputdialog.h> 00042 #include <tdeio/netaccess.h> 00043 #include <tdeio/renamedlg.h> 00044 #include <tdemessagebox.h> 00045 00046 #include "tdefiletreeview.h" 00047 #include "kdirselectdialog.h" 00048 00049 // ### add mutator for treeview! 00050 00051 class KDirSelectDialog::KDirSelectDialogPrivate 00052 { 00053 public: 00054 KDirSelectDialogPrivate() 00055 { 00056 urlCombo = 0L; 00057 branch = 0L; 00058 comboLocked = false; 00059 } 00060 00061 KFileSpeedBar *speedBar; 00062 KHistoryCombo *urlCombo; 00063 KFileTreeBranch *branch; 00064 TQString recentDirClass; 00065 KURL startURL; 00066 TQValueStack<KURL> dirsToList; 00067 00068 bool comboLocked : 1; 00069 }; 00070 00071 static KURL rootUrl(const KURL &url) 00072 { 00073 KURL root = url; 00074 root.setPath( "/" ); 00075 00076 if (!kapp->authorizeURLAction("list", KURL(), root)) 00077 { 00078 root = KURL::fromPathOrURL( TQDir::homeDirPath() ); 00079 if (!kapp->authorizeURLAction("list", KURL(), root)) 00080 { 00081 root = url; 00082 } 00083 } 00084 return root; 00085 } 00086 00087 KDirSelectDialog::KDirSelectDialog(const TQString &startDir, bool localOnly, 00088 TQWidget *parent, const char *name, 00089 bool modal) 00090 : KDialogBase( parent, name, modal, i18n("Select Folder"), 00091 Ok|Cancel|User1, Ok, false, 00092 KGuiItem( i18n("New Folder..."), "folder-new" ) ), 00093 m_localOnly( localOnly ) 00094 { 00095 d = new KDirSelectDialogPrivate; 00096 d->branch = 0L; 00097 00098 TQFrame *page = makeMainWidget(); 00099 TQHBoxLayout *hlay = new TQHBoxLayout( page, 0, spacingHint() ); 00100 m_mainLayout = new TQVBoxLayout(); 00101 d->speedBar = new KFileSpeedBar( page, "speedbar" ); 00102 connect( d->speedBar, TQT_SIGNAL( activated( const KURL& )), 00103 TQT_SLOT( setCurrentURL( const KURL& )) ); 00104 hlay->addWidget( d->speedBar, 0 ); 00105 hlay->addLayout( m_mainLayout, 1 ); 00106 00107 // Create dir list 00108 m_treeView = new KFileTreeView( page ); 00109 m_treeView->addColumn( i18n("Folders") ); 00110 m_treeView->setColumnWidthMode( 0, TQListView::Maximum ); 00111 m_treeView->setResizeMode( TQListView::AllColumns ); 00112 00113 d->urlCombo = new KHistoryCombo( page, "url combo" ); 00114 d->urlCombo->setTrapReturnKey( true ); 00115 d->urlCombo->setPixmapProvider( new KURLPixmapProvider() ); 00116 KURLCompletion *comp = new KURLCompletion(); 00117 comp->setMode( KURLCompletion::DirCompletion ); 00118 d->urlCombo->setCompletionObject( comp, true ); 00119 d->urlCombo->setAutoDeleteCompletionObject( true ); 00120 d->urlCombo->setDuplicatesEnabled( false ); 00121 connect( d->urlCombo, TQT_SIGNAL( textChanged( const TQString& ) ), 00122 TQT_SLOT( slotComboTextChanged( const TQString& ) )); 00123 00124 m_contextMenu = new TQPopupMenu( this ); 00125 TDEAction* newFolder = new TDEAction( i18n("New Folder..."), "folder-new", 0, TQT_TQOBJECT(this), TQT_SLOT( slotMkdir() ), TQT_TQOBJECT(this)); 00126 newFolder->plug(m_contextMenu); 00127 m_contextMenu->insertSeparator(); 00128 m_showHiddenFolders = new TDEToggleAction ( i18n( "Show Hidden Folders" ), 0, TQT_TQOBJECT(this), 00129 TQT_SLOT( slotShowHiddenFoldersToggled() ), TQT_TQOBJECT(this)); 00130 m_showHiddenFolders->plug(m_contextMenu); 00131 00132 d->startURL = KFileDialog::getStartURL( startDir, d->recentDirClass ); 00133 if ( localOnly && !d->startURL.isLocalFile() ) 00134 { 00135 d->startURL = KURL(); 00136 TQString docPath = TDEGlobalSettings::documentPath(); 00137 if (TQDir(docPath).exists()) 00138 d->startURL.setPath( docPath ); 00139 else 00140 d->startURL.setPath( TQDir::homeDirPath() ); 00141 } 00142 00143 KURL root = rootUrl(d->startURL); 00144 00145 m_startDir = d->startURL.url(); 00146 00147 d->branch = createBranch( root ); 00148 00149 readConfig( TDEGlobal::config(), "DirSelect Dialog" ); 00150 00151 m_mainLayout->addWidget( m_treeView, 1 ); 00152 m_mainLayout->addWidget( d->urlCombo, 0 ); 00153 00154 connect( m_treeView, TQT_SIGNAL( currentChanged( TQListViewItem * )), 00155 TQT_SLOT( slotCurrentChanged() )); 00156 connect( m_treeView, TQT_SIGNAL( contextMenu( TDEListView *, TQListViewItem *, const TQPoint & )), 00157 TQT_SLOT( slotContextMenu( TDEListView *, TQListViewItem *, const TQPoint & ))); 00158 00159 connect( d->urlCombo, TQT_SIGNAL( activated( const TQString& )), 00160 TQT_SLOT( slotURLActivated( const TQString& ))); 00161 connect( d->urlCombo, TQT_SIGNAL( returnPressed( const TQString& )), 00162 TQT_SLOT( slotURLActivated( const TQString& ))); 00163 00164 setCurrentURL( d->startURL ); 00165 } 00166 00167 00168 KDirSelectDialog::~KDirSelectDialog() 00169 { 00170 delete d; 00171 } 00172 00173 void KDirSelectDialog::setCurrentURL( const KURL& url ) 00174 { 00175 if ( !url.isValid() ) 00176 return; 00177 00178 KURL root = rootUrl(url); 00179 00180 d->startURL = url; 00181 if ( !d->branch || 00182 url.protocol() != d->branch->url().protocol() || 00183 url.host() != d->branch->url().host() ) 00184 { 00185 if ( d->branch ) 00186 { 00187 // removing the root-item causes the currentChanged() signal to be 00188 // emitted, but we don't want to update the location-combo yet. 00189 d->comboLocked = true; 00190 view()->removeBranch( d->branch ); 00191 d->comboLocked = false; 00192 } 00193 00194 d->branch = createBranch( root ); 00195 } 00196 00197 d->branch->disconnect( TQT_SIGNAL( populateFinished( KFileTreeViewItem * )), 00198 this, TQT_SLOT( slotNextDirToList( KFileTreeViewItem *))); 00199 connect( d->branch, TQT_SIGNAL( populateFinished( KFileTreeViewItem * )), 00200 TQT_SLOT( slotNextDirToList( KFileTreeViewItem * ) )); 00201 00202 KURL dirToList = root; 00203 d->dirsToList.clear(); 00204 TQString path = url.path(+1); 00205 int pos = path.length(); 00206 00207 if ( path.isEmpty() ) // e.g. ftp://host.com/ -> just list the root dir 00208 d->dirsToList.push( root ); 00209 00210 else 00211 { 00212 while ( pos > 0 ) 00213 { 00214 pos = path.findRev( '/', pos -1 ); 00215 if ( pos >= 0 ) 00216 { 00217 dirToList.setPath( path.left( pos +1 ) ); 00218 d->dirsToList.push( dirToList ); 00219 // tqDebug( "List: %s", dirToList.url().latin1()); 00220 } 00221 } 00222 } 00223 00224 if ( !d->dirsToList.isEmpty() ) 00225 openNextDir( d->branch->root() ); 00226 } 00227 00228 void KDirSelectDialog::openNextDir( KFileTreeViewItem * /*parent*/ ) 00229 { 00230 if ( !d->branch ) 00231 return; 00232 00233 KURL url = d->dirsToList.pop(); 00234 00235 KFileTreeViewItem *item = view()->findItem( d->branch, url.path().mid(1)); 00236 if ( item ) 00237 { 00238 if ( !item->isOpen() ) 00239 item->setOpen( true ); 00240 else // already open -> go to next one 00241 slotNextDirToList( item ); 00242 } 00243 // else 00244 // tqDebug("###### openNextDir: item not found!"); 00245 } 00246 00247 void KDirSelectDialog::slotNextDirToList( KFileTreeViewItem *item ) 00248 { 00249 // scroll to make item the topmost item 00250 view()->ensureItemVisible( item ); 00251 TQRect r = view()->itemRect( item ); 00252 if ( r.isValid() ) 00253 { 00254 int x, y; 00255 view()->viewportToContents( view()->contentsX(), r.y(), x, y ); 00256 view()->setContentsPos( x, y ); 00257 } 00258 00259 if ( !d->dirsToList.isEmpty() ) 00260 openNextDir( item ); 00261 else 00262 { 00263 d->branch->disconnect( TQT_SIGNAL( populateFinished( KFileTreeViewItem * )), 00264 this, TQT_SLOT( slotNextDirToList( KFileTreeViewItem *))); 00265 view()->setCurrentItem( item ); 00266 item->setSelected( true ); 00267 } 00268 } 00269 00270 void KDirSelectDialog::readConfig( TDEConfig *config, const TQString& group ) 00271 { 00272 d->urlCombo->clear(); 00273 00274 TDEConfigGroup conf( config, group ); 00275 d->urlCombo->setHistoryItems( conf.readPathListEntry( "History Items" )); 00276 00277 TQSize defaultSize( 400, 450 ); 00278 resize( conf.readSizeEntry( "DirSelectDialog Size", &defaultSize )); 00279 } 00280 00281 void KDirSelectDialog::saveConfig( TDEConfig *config, const TQString& group ) 00282 { 00283 TDEConfigGroup conf( config, group ); 00284 conf.writePathEntry( "History Items", d->urlCombo->historyItems(), ',', 00285 true, true); 00286 conf.writeEntry( "DirSelectDialog Size", size(), true, true ); 00287 00288 d->speedBar->save( config ); 00289 00290 config->sync(); 00291 } 00292 00293 void KDirSelectDialog::slotUser1() 00294 { 00295 slotMkdir(); 00296 } 00297 00298 void KDirSelectDialog::accept() 00299 { 00300 KFileTreeViewItem *item = m_treeView->currentKFileTreeViewItem(); 00301 if ( !item ) 00302 return; 00303 00304 if ( !d->recentDirClass.isEmpty() ) 00305 { 00306 KURL dir = item->url(); 00307 if ( !item->isDir() ) 00308 dir = dir.upURL(); 00309 00310 TDERecentDirs::add(d->recentDirClass, dir.url()); 00311 } 00312 00313 d->urlCombo->addToHistory( item->url().prettyURL() ); 00314 KFileDialog::setStartDir( url() ); 00315 00316 KDialogBase::accept(); 00317 saveConfig( TDEGlobal::config(), "DirSelect Dialog" ); 00318 } 00319 00320 00321 KURL KDirSelectDialog::url() const 00322 { 00323 return m_treeView->currentURL(); 00324 } 00325 00326 void KDirSelectDialog::slotCurrentChanged() 00327 { 00328 if ( d->comboLocked ) 00329 return; 00330 00331 KFileTreeViewItem *current = view()->currentKFileTreeViewItem(); 00332 KURL u = current ? current->url() : (d->branch ? d->branch->rootUrl() : KURL()); 00333 00334 if ( u.isValid() ) 00335 { 00336 if ( u.isLocalFile() ) 00337 d->urlCombo->setEditText( u.path() ); 00338 00339 else // remote url 00340 d->urlCombo->setEditText( u.prettyURL() ); 00341 } 00342 else 00343 d->urlCombo->setEditText( TQString::null ); 00344 } 00345 00346 void KDirSelectDialog::slotURLActivated( const TQString& text ) 00347 { 00348 if ( text.isEmpty() ) 00349 return; 00350 00351 KURL url = KURL::fromPathOrURL( text ); 00352 d->urlCombo->addToHistory( url.prettyURL() ); 00353 00354 if ( localOnly() && !url.isLocalFile() ) 00355 return; // ### messagebox 00356 00357 KURL oldURL = m_treeView->currentURL(); 00358 if ( oldURL.isEmpty() ) 00359 oldURL = KURL::fromPathOrURL( m_startDir ); 00360 00361 setCurrentURL( url ); 00362 } 00363 00364 KFileTreeBranch * KDirSelectDialog::createBranch( const KURL& url ) 00365 { 00366 TQString title = url.isLocalFile() ? url.path() : url.prettyURL(); 00367 KFileTreeBranch *branch = view()->addBranch( url, title, m_showHiddenFolders->isChecked() ); 00368 branch->setChildRecurse( false ); 00369 view()->setDirOnlyMode( branch, true ); 00370 00371 return branch; 00372 } 00373 00374 void KDirSelectDialog::slotComboTextChanged( const TQString& text ) 00375 { 00376 if ( d->branch ) 00377 { 00378 KURL url = KURL::fromPathOrURL( KShell::tildeExpand( text ) ); 00379 KFileTreeViewItem *item = d->branch->findTVIByURL( url ); 00380 if ( item ) 00381 { 00382 view()->setCurrentItem( item ); 00383 view()->setSelected( item, true ); 00384 view()->ensureItemVisible( item ); 00385 return; 00386 } 00387 } 00388 00389 TQListViewItem *item = view()->currentItem(); 00390 if ( item ) 00391 { 00392 item->setSelected( false ); 00393 // 2002/12/27, deselected item is not repainted, so force it 00394 item->repaint(); 00395 } 00396 } 00397 00398 void KDirSelectDialog::slotContextMenu( TDEListView *, TQListViewItem *, const TQPoint& pos ) 00399 { 00400 m_contextMenu->popup( pos ); 00401 } 00402 00403 void KDirSelectDialog::slotMkdir() 00404 { 00405 bool ok; 00406 TQString where = url().pathOrURL(); 00407 TQString name = i18n( "New Folder" ); 00408 if ( url().isLocalFile() && TQFileInfo( url().path(+1) + name ).exists() ) 00409 name = TDEIO::RenameDlg::suggestName( url(), name ); 00410 00411 TQString directory = TDEIO::encodeFileName( KInputDialog::getText( i18n( "New Folder" ), 00412 i18n( "Create new folder in:\n%1" ).arg( where ), 00413 name, &ok, this)); 00414 if (!ok) 00415 return; 00416 00417 bool selectDirectory = true; 00418 bool writeOk = false; 00419 bool exists = false; 00420 KURL folderurl( url() ); 00421 00422 TQStringList dirs = TQStringList::split( TQDir::separator(), directory ); 00423 TQStringList::ConstIterator it = dirs.begin(); 00424 00425 for ( ; it != dirs.end(); ++it ) 00426 { 00427 folderurl.addPath( *it ); 00428 exists = TDEIO::NetAccess::exists( folderurl, false, 0 ); 00429 writeOk = !exists && TDEIO::NetAccess::mkdir( folderurl, topLevelWidget() ); 00430 } 00431 00432 if ( exists ) // url was already existant 00433 { 00434 TQString which = folderurl.isLocalFile() ? folderurl.path() : folderurl.prettyURL(); 00435 KMessageBox::sorry(this, i18n("A file or folder named %1 already exists.").arg(which)); 00436 selectDirectory = false; 00437 } 00438 else if ( !writeOk ) { 00439 KMessageBox::sorry(this, i18n("You do not have permission to create that folder." )); 00440 } 00441 else if ( selectDirectory ) { 00442 setCurrentURL( folderurl ); 00443 } 00444 } 00445 00446 void KDirSelectDialog::slotShowHiddenFoldersToggled() 00447 { 00448 KURL currentURL = url(); 00449 00450 d->comboLocked = true; 00451 view()->removeBranch( d->branch ); 00452 d->comboLocked = false; 00453 00454 KURL root = rootUrl(d->startURL); 00455 d->branch = createBranch( root ); 00456 00457 setCurrentURL( currentURL ); 00458 } 00459 00460 // static 00461 KURL KDirSelectDialog::selectDirectory( const TQString& startDir, 00462 bool localOnly, 00463 TQWidget *parent, 00464 const TQString& caption) 00465 { 00466 KDirSelectDialog myDialog( startDir, localOnly, parent, 00467 "kdirselect dialog", true ); 00468 00469 if ( !caption.isNull() ) 00470 myDialog.setCaption( caption ); 00471 00472 if ( myDialog.exec() == TQDialog::Accepted ) 00473 return TDEIO::NetAccess::mostLocalURL(myDialog.url(),parent); 00474 else 00475 return KURL(); 00476 } 00477 00478 void KDirSelectDialog::virtual_hook( int id, void* data ) 00479 { KDialogBase::virtual_hook( id, data ); } 00480 00481 #include "kdirselectdialog.moc"