00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#include <qapplication.h>
00021
#include <qheader.h>
00022
#include <qtimer.h>
00023
#include <kdebug.h>
00024
#include <kdirnotify_stub.h>
00025
#include <kglobalsettings.h>
00026
#include <kfileitem.h>
00027
#include <kfileview.h>
00028
#include <kmimetype.h>
00029
#include <kstandarddirs.h>
00030
#include <stdlib.h>
00031
#include <assert.h>
00032
#include <kio/job.h>
00033
#include <kio/global.h>
00034
#include <kurldrag.h>
00035
#include <kiconloader.h>
00036
00037
00038
#include "kfiletreeview.h"
00039
#include "kfiletreebranch.h"
00040
#include "kfiletreeviewitem.h"
00041
00042 KFileTreeView::KFileTreeView(
QWidget *parent,
const char *name )
00043 :
KListView( parent,
name ),
00044 m_wantOpenFolderPixmaps( true ),
00045 m_toolTip( this )
00046 {
00047 setDragEnabled(
true);
00048 setSelectionModeExt( KListView::Single );
00049
00050 m_animationTimer =
new QTimer(
this );
00051 connect( m_animationTimer, SIGNAL( timeout() ),
00052
this, SLOT( slotAnimation() ) );
00053
00054 m_currentBeforeDropItem = 0;
00055 m_dropItem = 0;
00056
00057 m_autoOpenTimer =
new QTimer(
this );
00058 connect( m_autoOpenTimer, SIGNAL( timeout() ),
00059
this, SLOT( slotAutoOpenFolder() ) );
00060
00061
00062 connect(
this, SIGNAL( executed(
QListViewItem * ) ),
00063
this, SLOT( slotExecuted(
QListViewItem * ) ) );
00064 connect(
this, SIGNAL( expanded (
QListViewItem *) ),
00065
this, SLOT( slotExpanded( QListViewItem *) ));
00066 connect(
this, SIGNAL( collapsed( QListViewItem *) ),
00067
this, SLOT( slotCollapsed( QListViewItem* )));
00068
00069
00070
00071 connect(
this, SIGNAL( selectionChanged() ),
00072
this, SLOT( slotSelectionChanged() ) );
00073 connect(
this, SIGNAL( onItem( QListViewItem * )),
00074
this, SLOT( slotOnItem( QListViewItem * ) ) );
00075 connect(
this, SIGNAL(itemRenamed(QListViewItem*,
const QString &,
int)),
00076
this, SLOT(slotItemRenamed(QListViewItem*,
const QString &,
int)));
00077
00078
00079 m_bDrag =
false;
00080 m_branches.setAutoDelete(
true );
00081
00082 m_openFolderPixmap = SmallIcon(
"folder_open" );
00083 }
00084
00085 KFileTreeView::~KFileTreeView()
00086 {
00087
00088
00089
00090 hide();
00091
clear();
00092 m_branches.clear();
00093 }
00094
00095
00096
bool KFileTreeView::isValidItem( QListViewItem *item)
00097 {
00098
if (!item)
00099
return false;
00100
QPtrList<QListViewItem> lst;
00101
QListViewItemIterator it(
this );
00102
while ( it.current() )
00103 {
00104
if ( it.current() == item )
00105
return true;
00106 ++it;
00107 }
00108
return false;
00109 }
00110
00111
void KFileTreeView::contentsDragEnterEvent(
QDragEnterEvent *ev )
00112 {
00113
if ( !
acceptDrag( ev ) )
00114 {
00115 ev->ignore();
00116
return;
00117 }
00118 ev->acceptAction();
00119 m_currentBeforeDropItem = selectedItem();
00120
00121 QListViewItem *item = itemAt( contentsToViewport( ev->pos() ) );
00122
if( item )
00123 {
00124 m_dropItem = item;
00125 m_autoOpenTimer->start( KFileView::autoOpenDelay() );
00126 }
00127
else
00128 {
00129 m_dropItem = 0;
00130 }
00131 }
00132
00133
void KFileTreeView::contentsDragMoveEvent(
QDragMoveEvent *e )
00134 {
00135
if( !
acceptDrag( e ) )
00136 {
00137 e->ignore();
00138
return;
00139 }
00140 e->acceptAction();
00141
00142
00143 QListViewItem *afterme;
00144 QListViewItem *parent;
00145
00146
findDrop( e->pos(), parent, afterme );
00147
00148
00149 QListViewItem *item = afterme ? afterme : parent;
00150
00151
if( item && item->isSelectable() )
00152 {
00153 setSelected( item,
true );
00154
if( item != m_dropItem ) {
00155 m_autoOpenTimer->stop();
00156 m_dropItem = item;
00157 m_autoOpenTimer->start( KFileView::autoOpenDelay() );
00158 }
00159 }
00160
else
00161 {
00162 m_autoOpenTimer->stop();
00163 m_dropItem = 0;
00164 }
00165 }
00166
00167
void KFileTreeView::contentsDragLeaveEvent(
QDragLeaveEvent * )
00168 {
00169
00170
if ( isValidItem(m_currentBeforeDropItem) )
00171 {
00172 setSelected( m_currentBeforeDropItem,
true );
00173 ensureItemVisible( m_currentBeforeDropItem );
00174 }
00175
else if ( isValidItem(m_dropItem) )
00176 setSelected( m_dropItem,
false );
00177 m_currentBeforeDropItem = 0;
00178 m_dropItem = 0;
00179
00180 }
00181
00182
void KFileTreeView::contentsDropEvent(
QDropEvent *e )
00183 {
00184
00185 m_autoOpenTimer->stop();
00186 m_dropItem = 0;
00187
00188
kdDebug(250) <<
"contentsDropEvent !" <<
endl;
00189
if( !
acceptDrag( e ) ) {
00190 e->ignore();
00191
return;
00192 }
00193
00194 e->acceptAction();
00195 QListViewItem *afterme;
00196 QListViewItem *parent;
00197
findDrop(e->pos(), parent, afterme);
00198
00199
00200
00201
00202
if (e->source() == viewport() &&
itemsMovable())
00203
movableDropEvent(parent, afterme);
00204
else
00205 {
00206 emit
dropped(e, afterme);
00207 emit
dropped(
this, e, afterme);
00208 emit
dropped(e, parent, afterme);
00209 emit
dropped(
this, e, parent, afterme);
00210
00211
KURL::List urls;
00212
KURLDrag::decode( e, urls );
00213 emit
dropped(
this, e, urls );
00214
00215
KURL parentURL;
00216
if( parent )
00217 parentURL = static_cast<KFileTreeViewItem*>(parent)->
url();
00218
else
00219
00220
00221
return;
00222
00223 emit
dropped( urls, parentURL );
00224 emit
dropped(
this , e, urls, parentURL );
00225 }
00226 }
00227
00228 bool KFileTreeView::acceptDrag(
QDropEvent* e )
const
00229
{
00230
00231
bool ancestOK= acceptDrops();
00232
00233 ancestOK = ancestOK &&
itemsMovable();
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
return ancestOK && KURLDrag::canDecode( e ) &&
00244
00245 ( e->action() == QDropEvent::Copy
00246 || e->action() == QDropEvent::Move
00247 || e->action() == QDropEvent::Link );
00248 }
00249
00250
00251
00252
QDragObject *
KFileTreeView::dragObject()
00253 {
00254
00255
KURL::List urls;
00256
const QPtrList<QListViewItem> fileList =
selectedItems();
00257
QPtrListIterator<QListViewItem> it( fileList );
00258
for ( ; it.current(); ++it )
00259 {
00260 urls.append( static_cast<KFileTreeViewItem*>(it.current())->url() );
00261 }
00262
QPoint hotspot;
00263
QPixmap pixmap;
00264
if( urls.count() > 1 ){
00265 pixmap = DesktopIcon(
"kmultiple", 16 );
00266 }
00267
if( pixmap.isNull() )
00268 pixmap =
currentKFileTreeViewItem()->
fileItem()->
pixmap( 16 );
00269 hotspot.setX( pixmap.width() / 2 );
00270 hotspot.setY( pixmap.height() / 2 );
00271
QDragObject* dragObject =
new KURLDrag( urls,
this );
00272
if( dragObject )
00273 dragObject->setPixmap( pixmap, hotspot );
00274
return dragObject;
00275 }
00276
00277
00278
00279
void KFileTreeView::slotCollapsed( QListViewItem *item )
00280 {
00281
KFileTreeViewItem *kftvi = static_cast<KFileTreeViewItem*>(item);
00282
kdDebug(250) <<
"hit slotCollapsed" <<
endl;
00283
if( kftvi && kftvi->
isDir())
00284 {
00285 item->setPixmap( 0, itemIcon(kftvi));
00286 }
00287 }
00288
00289
void KFileTreeView::slotExpanded( QListViewItem *item )
00290 {
00291
kdDebug(250) <<
"slotExpanded here !" <<
endl;
00292
00293
if( ! item )
return;
00294
00295
KFileTreeViewItem *it = static_cast<KFileTreeViewItem*>(item);
00296
KFileTreeBranch *
branch = it->
branch();
00297
00298
00299
if( it->
isDir() && branch && item->childCount() == 0 )
00300 {
00301
00302
kdDebug(250 ) <<
"starting to open " << it->
url().
prettyURL() <<
endl;
00303 startAnimation( it );
00304
bool branchAnswer = branch->
populate( it->
url(), it );
00305
kdDebug(250) <<
"Branches answer: " << branchAnswer <<
endl;
00306
if( ! branchAnswer )
00307 {
00308
kdDebug(250) <<
"ERR: Could not populate!" <<
endl;
00309 stopAnimation( it );
00310 }
00311 }
00312
00313
00314
if( it->
isDir() && isOpen( item ) )
00315 {
00316
kdDebug(250)<<
"Setting open Pixmap" <<
endl;
00317 item->setPixmap( 0, itemIcon( it ));
00318 }
00319 }
00320
00321
00322
00323
void KFileTreeView::slotExecuted( QListViewItem *item )
00324 {
00325
if ( !item )
00326
return;
00327
00328
00329
00330
if( static_cast<KFileTreeViewItem*>(item)->isDir())
00331 {
00332 item->setOpen( !item->isOpen() );
00333 }
00334 }
00335
00336
00337
void KFileTreeView::slotAutoOpenFolder()
00338 {
00339 m_autoOpenTimer->stop();
00340
00341
if ( !isValidItem(m_dropItem) || m_dropItem->isOpen() )
00342
return;
00343
00344 m_dropItem->setOpen(
true );
00345 m_dropItem->repaint();
00346 }
00347
00348
00349
void KFileTreeView::slotSelectionChanged()
00350 {
00351
if ( !m_dropItem )
00352 {
00353 }
00354 }
00355
00356
00357 KFileTreeBranch*
KFileTreeView::addBranch(
const KURL &path,
const QString& name,
00358
bool showHidden )
00359 {
00360
const QPixmap& folderPix =
KMimeType::mimeType(
"inode/directory")->pixmap( KIcon::Small );
00361
00362
return addBranch( path, name, folderPix, showHidden);
00363 }
00364
00365 KFileTreeBranch*
KFileTreeView::addBranch(
const KURL &path,
const QString& name,
00366
const QPixmap& pix,
bool showHidden )
00367 {
00368
kdDebug(250) <<
"adding another root " << path.
prettyURL() <<
endl;
00369
00370
00371
KFileTreeBranch *newBranch =
new KFileTreeBranch(
this, path, name, pix,
00372 showHidden );
00373
return addBranch(newBranch);
00374 }
00375
00376 KFileTreeBranch *
KFileTreeView::addBranch(
KFileTreeBranch *newBranch)
00377 {
00378 connect( newBranch, SIGNAL(populateFinished(
KFileTreeViewItem* )),
00379
this, SLOT( slotPopulateFinished(
KFileTreeViewItem* )));
00380
00381 connect( newBranch, SIGNAL( newTreeViewItems(
KFileTreeBranch*,
00382
const KFileTreeViewItemList& )),
00383
this, SLOT( slotNewTreeViewItems(
KFileTreeBranch*,
00384
const KFileTreeViewItemList& )));
00385
00386 m_branches.append( newBranch );
00387
return( newBranch );
00388 }
00389
00390 KFileTreeBranch *
KFileTreeView::branch(
const QString& searchName )
00391 {
00392
KFileTreeBranch *branch = 0;
00393
QPtrListIterator<KFileTreeBranch> it( m_branches );
00394
00395
while ( (branch = it.current()) != 0 ) {
00396 ++it;
00397
QString bname = branch->
name();
00398
kdDebug(250) <<
"This is the branches name: " << bname <<
endl;
00399
if( bname == searchName )
00400 {
00401
kdDebug(250) <<
"Found branch " << bname <<
" and return ptr" <<
endl;
00402
return( branch );
00403 }
00404 }
00405
return ( 0L );
00406 }
00407
00408 KFileTreeBranchList&
KFileTreeView::branches()
00409 {
00410
return( m_branches );
00411 }
00412
00413
00414 bool KFileTreeView::removeBranch(
KFileTreeBranch *branch )
00415 {
00416
if(m_branches.contains(branch))
00417 {
00418
delete (branch->
root());
00419 m_branches.remove( branch );
00420
return true;
00421 }
00422
else
00423 {
00424
return false;
00425 }
00426 }
00427
00428 void KFileTreeView::setDirOnlyMode(
KFileTreeBranch* branch,
bool bom )
00429 {
00430
if( branch )
00431 {
00432 branch->
setDirOnlyMode( bom );
00433 }
00434 }
00435
00436
00437
void KFileTreeView::slotPopulateFinished(
KFileTreeViewItem *it )
00438 {
00439
if( it && it->
isDir())
00440 stopAnimation( it );
00441 }
00442
00443
void KFileTreeView::slotNewTreeViewItems(
KFileTreeBranch* branch,
const KFileTreeViewItemList& itemList )
00444 {
00445
if( ! branch )
return;
00446
kdDebug(250) <<
"hitting slotNewTreeViewItems" <<
endl;
00447
00448
00449
00450
00451
00452
00453
00454
00455
if( ! m_nextUrlToSelect.
isEmpty() )
00456 {
00457
KFileTreeViewItemListIterator it( itemList );
00458
00459
bool end =
false;
00460
for( ; !
end && it.current(); ++it )
00461 {
00462
KURL url = (*it)->
url();
00463
00464
if( m_nextUrlToSelect.
equals(url,
true ))
00465 {
00466 setCurrentItem( static_cast<QListViewItem*>(*it) );
00467 m_nextUrlToSelect =
KURL();
00468
end =
true;
00469 }
00470 }
00471 }
00472 }
00473
00474
QPixmap KFileTreeView::itemIcon(
KFileTreeViewItem *item,
int gap )
const
00475
{
00476
QPixmap pix;
00477
kdDebug(250) <<
"Setting icon for column " << gap <<
endl;
00478
00479
if( item )
00480 {
00481
00482
KFileTreeBranch *brnch = item->
branch();
00483
if( item == brnch->
root() )
00484 {
00485 pix = brnch->
pixmap();
00486
if( m_wantOpenFolderPixmaps && brnch->
root()->isOpen() )
00487 {
00488 pix = brnch->
openPixmap();
00489 }
00490 }
00491
else
00492 {
00493
00494 pix = item->
fileItem()->
pixmap( KIcon::SizeSmall );
00495
00496
00497
00498
if( item->
isDir() && m_wantOpenFolderPixmaps )
00499 {
00500
if( isOpen( static_cast<QListViewItem*>(item)))
00501 pix = m_openFolderPixmap;
00502 }
00503 }
00504 }
00505
00506
return pix;
00507 }
00508
00509
00510
void KFileTreeView::slotAnimation()
00511 {
00512 MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.begin();
00513 MapCurrentOpeningFolders::Iterator
end = m_mapCurrentOpeningFolders.end();
00514
for (; it !=
end;)
00515 {
00516
KFileTreeViewItem *item = it.key();
00517
if (!isValidItem(item))
00518 {
00519 MapCurrentOpeningFolders::Iterator deleteIt = it;
00520 ++it;
00521 m_mapCurrentOpeningFolders.remove(item);
00522
continue;
00523 }
00524
00525 uint & iconNumber = it.data().iconNumber;
00526
QString icon = QString::fromLatin1( it.data().iconBaseName ).append( QString::number( iconNumber ) );
00527
00528 item->setPixmap( 0, SmallIcon( icon ));
00529
00530 iconNumber++;
00531
if ( iconNumber > it.data().iconCount )
00532 iconNumber = 1;
00533
00534 ++it;
00535 }
00536 }
00537
00538
00539
void KFileTreeView::startAnimation(
KFileTreeViewItem * item,
const char * iconBaseName, uint iconCount )
00540 {
00541
00542
if( ! item )
00543 {
00544
kdDebug(250) <<
" startAnimation Got called without valid item !" <<
endl;
00545
return;
00546 }
00547
00548 m_mapCurrentOpeningFolders.insert( item,
00549 AnimationInfo( iconBaseName,
00550 iconCount,
00551 itemIcon(item, 0) ) );
00552
if ( !m_animationTimer->isActive() )
00553 m_animationTimer->start( 50 );
00554 }
00555
00556
void KFileTreeView::stopAnimation(
KFileTreeViewItem * item )
00557 {
00558
if( ! item )
return;
00559
00560
kdDebug(250) <<
"Stoping Animation !" <<
endl;
00561
00562 MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.find(item);
00563
if ( it != m_mapCurrentOpeningFolders.end() )
00564 {
00565
if( item->
isDir() && isOpen( item) )
00566 {
00567
kdDebug(250) <<
"Setting folder open pixmap !" <<
endl;
00568 item->setPixmap( 0, itemIcon( item ));
00569 }
00570
else
00571 {
00572 item->setPixmap( 0, it.data().originalPixmap );
00573 }
00574 m_mapCurrentOpeningFolders.remove( item );
00575 }
00576
else
00577 {
00578
if( item )
00579
kdDebug(250)<<
"StopAnimation - could not find item " << item->
url().
prettyURL()<<
endl;
00580
else
00581
kdDebug(250)<<
"StopAnimation - item is zero !" <<
endl;
00582 }
00583
if (m_mapCurrentOpeningFolders.isEmpty())
00584 m_animationTimer->stop();
00585 }
00586
00587 KFileTreeViewItem *
KFileTreeView::currentKFileTreeViewItem()
const
00588
{
00589
return static_cast<KFileTreeViewItem *>( selectedItem() );
00590 }
00591
00592 KURL KFileTreeView::currentURL()
const
00593
{
00594
KFileTreeViewItem *item =
currentKFileTreeViewItem();
00595
if ( item )
00596
return currentKFileTreeViewItem()->
url();
00597
else
00598
return KURL();
00599 }
00600
00601
void KFileTreeView::slotOnItem( QListViewItem *item )
00602 {
00603
KFileTreeViewItem *i = static_cast<KFileTreeViewItem *>( item );
00604
if( i )
00605 {
00606
const KURL url = i->
url();
00607
if ( url.
isLocalFile() )
00608 emit onItem( url.
path() );
00609
else
00610 emit onItem( url.
prettyURL() );
00611 }
00612 }
00613
00614
void KFileTreeView::slotItemRenamed(QListViewItem* item,
const QString &name,
int col)
00615 {
00616 (
void) item;
00617
kdDebug(250) <<
"Do not bother: " <<
name << col <<
endl;
00618 }
00619
00620 KFileTreeViewItem *
KFileTreeView::findItem(
const QString& branchName,
const QString& relUrl )
00621 {
00622
KFileTreeBranch *br =
branch( branchName );
00623
return(
findItem( br, relUrl ));
00624 }
00625
00626 KFileTreeViewItem *
KFileTreeView::findItem(
KFileTreeBranch* brnch,
const QString& relUrl )
00627 {
00628
KFileTreeViewItem *ret = 0;
00629
if( brnch )
00630 {
00631
KURL url = brnch->
rootUrl();
00632
00633
if( ! relUrl.isEmpty() && relUrl != QString::fromLatin1(
"/") )
00634 {
00635
QString partUrl( relUrl );
00636
00637
if( partUrl.endsWith(
"/"))
00638 partUrl.truncate( relUrl.length()-1 );
00639
00640 url.
addPath( partUrl );
00641
00642
kdDebug(250) <<
"assembled complete dir string " << url.
prettyURL() <<
endl;
00643
00644
KFileItem *fi = brnch->
findByURL( url );
00645
if( fi )
00646 {
00647 ret = static_cast<KFileTreeViewItem*>( fi->
extraData( brnch ));
00648
kdDebug(250) <<
"Found item !" <<ret <<
endl;
00649 }
00650 }
00651
else
00652 {
00653 ret = brnch->
root();
00654 }
00655 }
00656
return( ret );
00657 }
00658
00661
00662
00663
void KFileTreeViewToolTip::maybeTip(
const QPoint & )
00664 {
00665
#if 0
00666
QListViewItem *item = m_view->itemAt( point );
00667
if ( item ) {
00668
QString text = static_cast<KFileViewItem*>( item )->toolTipText();
00669
if ( !text.isEmpty() )
00670 tip ( m_view->itemRect( item ), text );
00671 }
00672
#endif
00673
}
00674
00675
void KFileTreeView::virtual_hook(
int id,
void* data )
00676 {
KListView::virtual_hook(
id, data ); }
00677
00678
#include "kfiletreeview.moc"