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