akregator/src

feedlistview.cpp

00001 /*
00002     This file is part of Akregator.
00003 
00004     Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of TQt, and distribute the resulting executable,
00022     without including the source code for TQt in the source distribution.
00023 */
00024 
00025 #include "dragobjects.h"
00026 #include "folder.h"
00027 #include "folderitem.h"
00028 #include "tagfolder.h"
00029 #include "tagfolderitem.h"
00030 #include "feedlistview.h"
00031 #include "feed.h"
00032 #include "feeditem.h"
00033 #include "feedlist.h"
00034 #include "tag.h"
00035 #include "tagnode.h"
00036 #include "tagnodeitem.h"
00037 #include "tagnodelist.h"
00038 #include "treenode.h"
00039 #include "treenodeitem.h"
00040 #include "treenodevisitor.h"
00041 
00042 #include <kdebug.h>
00043 #include <kiconeffect.h>
00044 #include <kiconloader.h>
00045 #include <tdelocale.h>
00046 #include <tdemultipledrag.h>
00047 #include <kstringhandler.h>
00048 #include <kurldrag.h>
00049 
00050 #include <tqfont.h>
00051 #include <tqheader.h>
00052 #include <tqpainter.h>
00053 #include <tqptrdict.h>
00054 #include <tqtimer.h>
00055 #include <tqwhatsthis.h>
00056 
00057 namespace Akregator {
00058 
00059 class NodeListView::NodeListViewPrivate
00060 {
00061     public:
00063     TQPtrDict<TreeNodeItem> itemDict;
00064     NodeList* nodeList;
00065     bool showTagFolders;
00066 
00067     // Drag and Drop variables
00068     TQListViewItem *parent;
00069     TQListViewItem *afterme;
00070     TQTimer autoopentimer;
00071     ConnectNodeVisitor* connectNodeVisitor;
00072     DisconnectNodeVisitor* disconnectNodeVisitor;
00073     CreateItemVisitor* createItemVisitor;
00074     DeleteItemVisitor* deleteItemVisitor;
00075 };
00076 
00077 class NodeListView::ConnectNodeVisitor : public TreeNodeVisitor
00078 {
00079     public:
00080         ConnectNodeVisitor(NodeListView* view) : m_view(view) {}
00081         virtual ~ConnectNodeVisitor() {}
00082 
00083         virtual bool visitTreeNode(TreeNode* node)
00084         {
00085             connect(node, TQT_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQT_SLOT(slotNodeDestroyed(TreeNode*) ));
00086             connect(node, TQT_SIGNAL(signalChanged(TreeNode*)), m_view, TQT_SLOT(slotNodeChanged(TreeNode*) ));
00087             return true;
00088         }
00089 
00090         virtual bool visitFolder(Folder* node)
00091         {
00092             visitTreeNode(node);
00093             connect(node, TQT_SIGNAL(signalChildAdded(TreeNode*)), m_view, TQT_SLOT(slotNodeAdded(TreeNode*) ));
00094             connect(node, TQT_SIGNAL(signalChildRemoved(Folder*, TreeNode*)), m_view, TQT_SLOT(slotNodeRemoved(Folder*, TreeNode*) ));
00095             return true;
00096         }
00097         
00098         virtual bool visitFeed(Feed* node)
00099         {
00100             visitTreeNode(node);
00101             
00102             connect(node, TQT_SIGNAL(fetchStarted(Feed*)), m_view, TQT_SLOT(slotFeedFetchStarted(Feed*)));
00103             connect(node, TQT_SIGNAL(fetchAborted(Feed*)), m_view, TQT_SLOT(slotFeedFetchAborted(Feed*)));
00104             connect(node, TQT_SIGNAL(fetchError(Feed*)), m_view, TQT_SLOT(slotFeedFetchError(Feed*)));
00105             connect(node, TQT_SIGNAL(fetched(Feed*)), m_view, TQT_SLOT(slotFeedFetchCompleted(Feed*)));
00106             return true;
00107         }
00108     private:
00109 
00110         NodeListView* m_view;
00111     
00112 };
00113 
00114 class NodeListView::DisconnectNodeVisitor : public TreeNodeVisitor
00115 {
00116     public:
00117         DisconnectNodeVisitor(NodeListView* view) : m_view(view) {}
00118         virtual ~DisconnectNodeVisitor() {}
00119 
00120         virtual bool visitTagNode(TagNode* node)
00121         {
00122             disconnect(node, TQT_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQT_SLOT(slotNodeDestroyed(TreeNode*) ));
00123             disconnect(node, TQT_SIGNAL(signalChanged(TreeNode*)), m_view, TQT_SLOT(slotNodeChanged(TreeNode*) ));
00124             return true;
00125         }
00126         
00127         virtual bool visitFolder(Folder* node)
00128         {
00129             disconnect(node, TQT_SIGNAL(signalChildAdded(TreeNode*)), m_view, TQT_SLOT(slotNodeAdded(TreeNode*) ));
00130             disconnect(node, TQT_SIGNAL(signalChildRemoved(Folder*, TreeNode*)), m_view, TQT_SLOT(slotNodeRemoved(Folder*, TreeNode*) ));
00131             
00132             disconnect(node, TQT_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQT_SLOT(slotNodeDestroyed(TreeNode*) ));
00133             disconnect(node, TQT_SIGNAL(signalChanged(TreeNode*)), m_view, TQT_SLOT(slotNodeChanged(TreeNode*) ));
00134             return true;
00135         }
00136         
00137         virtual bool visitFeed(Feed* node)
00138         {
00139 
00140             disconnect(node, TQT_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQT_SLOT(slotNodeDestroyed(TreeNode*) ));
00141             disconnect(node, TQT_SIGNAL(signalChanged(TreeNode*)), m_view, TQT_SLOT(slotNodeChanged(TreeNode*) ));
00142             disconnect(node, TQT_SIGNAL(fetchStarted(Feed*)), m_view, TQT_SLOT(slotFeedFetchStarted(Feed*)));
00143             disconnect(node, TQT_SIGNAL(fetchAborted(Feed*)), m_view, TQT_SLOT(slotFeedFetchAborted(Feed*)));
00144             disconnect(node, TQT_SIGNAL(fetchError(Feed*)), m_view, TQT_SLOT(slotFeedFetchError(Feed*)));
00145             disconnect(node, TQT_SIGNAL(fetched(Feed*)), m_view, TQT_SLOT(slotFeedFetchCompleted(Feed*)));
00146             return true;
00147         }
00148     private:
00149 
00150         NodeListView* m_view;
00151 };
00152 
00153 class NodeListView::DeleteItemVisitor : public TreeNodeVisitor
00154 {
00155     public:
00156         
00157         DeleteItemVisitor(NodeListView* view) : m_view(view) {}
00158         virtual ~DeleteItemVisitor() {}
00159         
00160         virtual bool visitTreeNode(TreeNode* node)
00161         {
00162             TreeNodeItem* item = m_view->d->itemDict.take(node);
00163     
00164             if (!item)
00165                 return true;
00166     
00167             if ( m_selectNeighbour && item->isSelected() )
00168             {
00169                 if (item->itemBelow())
00170                     m_view->setSelected(item->itemBelow(), true);
00171                 else if (item->itemAbove())
00172                     m_view->setSelected(item->itemAbove(), true);
00173                 else
00174                     m_view->setSelected(item, false);
00175             }
00176             
00177             m_view->disconnectFromNode(node);
00178             delete item;
00179             return true;
00180         
00181         }
00182         
00183         virtual bool visitFolder(Folder* node)
00184         {
00185             // delete child items recursively before deleting parent
00186             TQValueList<TreeNode*> children = node->children();
00187             for (TQValueList<TreeNode*>::ConstIterator it =  children.begin(); it != children.end(); ++it )
00188                 visit(*it);
00189             
00190             visitTreeNode(node);
00191             
00192             return true;
00193         }
00194         
00195         void deleteItem(TreeNode* node, bool selectNeighbour)
00196         {
00197             m_selectNeighbour = selectNeighbour;
00198             visit(node);
00199         }
00200         
00201     private:
00202         NodeListView* m_view;
00203         bool m_selectNeighbour;
00204 };
00205 
00206 class NodeListView::CreateItemVisitor : public TreeNodeVisitor
00207 {
00208     public:
00209         CreateItemVisitor(NodeListView* view) : m_view(view) {}
00210         virtual ~CreateItemVisitor() {}
00211 
00212         virtual bool visitTagNode(TagNode* node)
00213         {
00214             if (m_view->findNodeItem(node))
00215                 return true;
00216             
00217             TagNodeItem* item = 0;
00218             TreeNode* prev = node->prevSibling();
00219             FolderItem* parentItem = static_cast<FolderItem*>(m_view->findNodeItem(node->parent()));
00220             if (parentItem)
00221             {
00222                 if (prev)
00223                 {
00224                     item = new TagNodeItem( parentItem, m_view->findNodeItem(prev), node);
00225                 }
00226                 else
00227                     item = new TagNodeItem( parentItem, node);
00228             }
00229             else
00230             {
00231                 if (prev)
00232                 {
00233                     item = new TagNodeItem(m_view, m_view->findNodeItem(prev), node);
00234                 }
00235                 else
00236                     item = new TagNodeItem(m_view, node);
00237             }                
00238             item->nodeChanged();     
00239             m_view->d->itemDict.insert(node, item);
00240             m_view->connectToNode(node);
00241             if (parentItem)
00242                 parentItem->sortChildItems(0, true);
00243             return true;
00244         }
00245 
00246         virtual bool visitTagFolder(TagFolder* node)
00247         {
00248             if (m_view->findNodeItem(node))
00249                 return true;
00250          
00251             TagFolderItem* item = 0;
00252             TreeNode* prev = node->prevSibling();
00253             FolderItem* parentItem = static_cast<FolderItem*>(m_view->findNodeItem(node->parent()));
00254             if (parentItem)
00255             {
00256                 if (prev)
00257                 {
00258                     item = new TagFolderItem( parentItem, m_view->findNodeItem(prev), node);
00259                 }
00260                 else
00261                     item = new TagFolderItem(parentItem, node);
00262             }
00263             else
00264             {
00265                 if (prev)
00266                 {
00267                     item = new TagFolderItem(m_view, m_view->findNodeItem(prev), node);
00268                 }
00269                 else
00270                     item = new TagFolderItem(m_view, node);
00271 
00272             }
00273             m_view->d->itemDict.insert(node, item);
00274             TQValueList<TreeNode*> children = node->children();
00275 
00276             // add children recursively
00277             for (TQValueList<TreeNode*>::ConstIterator it =  children.begin(); it != children.end(); ++it )
00278                 visit(*it);
00279 
00280             m_view->connectToNode(node);
00281             return true;
00282         }
00283         
00284         virtual bool visitFolder(Folder* node)
00285         {
00286             if (m_view->findNodeItem(node))
00287                 return true;
00288                      
00289             FolderItem* item = 0;
00290             TreeNode* prev = node->prevSibling();
00291             FolderItem* parentItem = static_cast<FolderItem*>(m_view->findNodeItem(node->parent()));
00292             if (parentItem)
00293             {
00294                 if (prev)
00295                 {
00296                     item = new FolderItem( parentItem, m_view->findNodeItem(prev), node);
00297                 }
00298                 else
00299                     item = new FolderItem(parentItem, node);
00300             }
00301             else
00302             {
00303                 if (prev)
00304                 {
00305                     item = new FolderItem(m_view, m_view->findNodeItem(prev), node);
00306                 }
00307                 else
00308                     item = new FolderItem(m_view, node);
00309             }
00310             m_view->d->itemDict.insert(node, item);
00311             
00312             // add children recursively
00313             TQValueList<TreeNode*> children = node->children();
00314             for (TQValueList<TreeNode*>::ConstIterator it =  children.begin(); it != children.end(); ++it )
00315                 visit(*it);
00316 
00317             m_view->connectToNode(node);
00318             return true;
00319         }
00320         
00321         virtual bool visitFeed(Feed* node)
00322         {
00323             if (m_view->findNodeItem(node))
00324                 return true;
00325          
00326             FeedItem* item = 0;
00327             TreeNode* prev = node->prevSibling();
00328             FolderItem* parentItem = static_cast<FolderItem*>(m_view->findNodeItem(node->parent()));
00329             
00330             if (parentItem)
00331             {
00332                 if (prev)
00333                 {
00334                     item = new FeedItem( parentItem, m_view->findNodeItem(prev), node);
00335                 }
00336                 else
00337                     item = new FeedItem( parentItem, node);
00338             }
00339             else
00340             {
00341                 if (prev)
00342                 {
00343                     item = new FeedItem(m_view, m_view->findNodeItem(prev), node);
00344                 }
00345                 else
00346                     item = new FeedItem(m_view, node);
00347             }
00348 
00349             item->nodeChanged();     
00350             m_view->d->itemDict.insert(node, item);
00351             m_view->connectToNode(node);
00352             return true;
00353         }
00354         
00355     private:
00356         NodeListView* m_view;
00357 };
00358 
00359 NodeListView::NodeListView( TQWidget *parent, const char *name)
00360         : TDEListView(parent, name), d(new NodeListViewPrivate)
00361 {
00362     d->showTagFolders = true;
00363     d->connectNodeVisitor = new ConnectNodeVisitor(this),
00364     d->disconnectNodeVisitor = new DisconnectNodeVisitor(this);
00365     d->createItemVisitor = new CreateItemVisitor(this);
00366     d->deleteItemVisitor = new DeleteItemVisitor(this);
00367 
00368     setMinimumSize(150, 150);
00369     addColumn(i18n("Feeds"));
00370     setRootIsDecorated(false);
00371     setItemsRenameable(false); // NOTE: setting this this to true collides with setRenameEnabled() in items and breaks in-place renaming in strange ways. Do not enable!
00372     setItemMargin(2);
00373 
00374     setFullWidth(true);
00375     setSorting(-1);
00376     setDragAutoScroll(true);
00377     setDropVisualizer(true);
00378     //setDropHighlighter(false);
00379 
00380     setDragEnabled(true);
00381     setAcceptDrops(true);
00382     setItemsMovable(true);
00383     
00384     connect( this, TQT_SIGNAL(dropped(TQDropEvent*, TQListViewItem*)), this, TQT_SLOT(slotDropped(TQDropEvent*, TQListViewItem*)) );
00385     connect( this, TQT_SIGNAL(selectionChanged(TQListViewItem*)), this, TQT_SLOT(slotSelectionChanged(TQListViewItem*)) );
00386     connect( this, TQT_SIGNAL(itemRenamed(TQListViewItem*, int, const TQString&)), this, TQT_SLOT(slotItemRenamed(TQListViewItem*, int, const TQString&)) );
00387     connect( this, TQT_SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)), this, TQT_SLOT(slotContextMenu(TDEListView*, TQListViewItem*, const TQPoint&)) );
00388     connect( &(d->autoopentimer), TQT_SIGNAL( timeout() ), this, TQT_SLOT( openFolder() ) );
00389 
00390     clear();
00391     
00392     TQWhatsThis::add(this, i18n("<h2>Feeds tree</h2>"
00393         "Here you can browse tree of feeds. "
00394         "You can also add feeds or feed groups (folders) "
00395         "using right-click menu, or reorganize them using "
00396         "drag and drop."));
00397     setUpdatesEnabled(true);
00398 }
00399 
00400 NodeListView::~NodeListView()
00401 {
00402     delete d->connectNodeVisitor;
00403     delete d->disconnectNodeVisitor;
00404     delete d->createItemVisitor;
00405     delete d->deleteItemVisitor;
00406     delete d;
00407     d = 0;
00408 }
00409 
00410 void NodeListView::setNodeList(NodeList* nodeList)
00411 {
00412     if (nodeList == d->nodeList)
00413          return;
00414 
00415     clear();
00416 
00417     disconnectFromNodeList(d->nodeList);
00418     
00419     if (!nodeList)
00420         return;
00421 
00422     d->nodeList = nodeList;
00423     connectToNodeList(nodeList);
00424   
00425     
00426     Folder* rootNode = nodeList->rootNode();
00427     if (!rootNode)
00428         return;
00429 
00430     slotNodeAdded(rootNode);
00431     slotRootNodeChanged(rootNode);
00432 }
00433 
00434 Folder* NodeListView::rootNode()
00435 {
00436     return d->nodeList ? d->nodeList->rootNode() : 0;
00437 }
00438 
00439 TreeNode* NodeListView::selectedNode()
00440 {
00441     TreeNodeItem* item = dynamic_cast<TreeNodeItem*> (selectedItem());
00442     
00443     return ( item ? item->node() : 0) ;
00444 }
00445 
00446 void NodeListView::setSelectedNode(TreeNode* node)
00447 {
00448     TreeNodeItem* item = findNodeItem(node);
00449     if ( node && item )
00450         setSelected(item, true);
00451 }
00452 
00453 TreeNode* NodeListView::findNodeByTitle(const TQString& title)
00454 {
00455     TreeNodeItem* item = dynamic_cast<TreeNodeItem*>(findItemByTitle(title, 0));
00456     if (!item)
00457         return 0;
00458     else 
00459         return item->node();
00460 }
00461 
00462 TreeNodeItem* NodeListView::findNodeItem(TreeNode* node)
00463 {
00464     return d->itemDict.find(node);
00465 }
00466 
00467 TreeNodeItem* NodeListView::findItemByTitle(const TQString& text, int column, ComparisonFlags compare) const
00468 { 
00469     return dynamic_cast<TreeNodeItem*> (TDEListView::findItem(text, column, compare)); 
00470 }
00471 
00472 void NodeListView::ensureNodeVisible(TreeNode* node)
00473 {
00474     ensureItemVisible(findNodeItem(node));
00475 }
00476 
00477 void NodeListView::startNodeRenaming(TreeNode* node)
00478 {
00479     TreeNodeItem* item = findNodeItem(node);
00480     if (item)
00481     {   
00482         item->startRename(0);
00483     }
00484 }
00485 
00486 void NodeListView::clear()
00487 {
00488     TQPtrDictIterator<TreeNodeItem> it(d->itemDict);
00489     for( ; it.current(); ++it )
00490         disconnectFromNode( it.current()->node() );
00491     d->itemDict.clear();
00492     d->nodeList = 0;
00493     
00494     TDEListView::clear();
00495 }
00496 
00497 void NodeListView::drawContentsOffset( TQPainter * p, int ox, int oy,
00498                                        int cx, int cy, int cw, int ch )
00499 {
00500     bool oldUpdatesEnabled = isUpdatesEnabled();
00501     setUpdatesEnabled(false);
00502     TDEListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
00503     setUpdatesEnabled(oldUpdatesEnabled);
00504 }
00505 
00506 void NodeListView::slotDropped( TQDropEvent *e, TQListViewItem*
00507 /*after*/)
00508 {
00509     d->autoopentimer.stop();
00510 
00511     if (e->source() != viewport())
00512     {
00513         openFolder();
00514 
00515         if (KURLDrag::canDecode(e))
00516         {
00517             FolderItem* parent = dynamic_cast<FolderItem*> (d->parent);
00518             TreeNodeItem* afterMe = 0;
00519             
00520             if(d->afterme)
00521                 afterMe = dynamic_cast<TreeNodeItem*> (d->afterme);
00522             
00523             KURL::List urls;
00524             KURLDrag::decode( e, urls );
00525             e->accept();
00526             emit signalDropped( urls, afterMe ? afterMe->node() : 0, parent ? parent->node() : 0);
00527         }
00528     }
00529     else
00530     {
00531     }
00532 }
00533 
00534 void NodeListView::movableDropEvent(TQListViewItem* /*parent*/, TQListViewItem* /*afterme*/)
00535 {
00536     d->autoopentimer.stop();
00537     if (d->parent)
00538     {    
00539         openFolder();
00540 
00541         Folder* parentNode = (dynamic_cast<FolderItem*> (d->parent))->node();
00542         TreeNode* afterMeNode = 0; 
00543         TreeNode* current = selectedNode();
00544 
00545         if (d->afterme)
00546             afterMeNode = (dynamic_cast<TreeNodeItem*> (d->afterme))->node();
00547 
00548         current->parent()->removeChild(current);
00549         parentNode->insertChild(current, afterMeNode);
00550         TDEListView::movableDropEvent(d->parent, d->afterme);
00551     }    
00552 }
00553 
00554 void NodeListView::setShowTagFolders(bool enabled)
00555 {
00556     d->showTagFolders = enabled;
00557 }
00558 
00559 void NodeListView::contentsDragMoveEvent(TQDragMoveEvent* event)
00560 {
00561     TQPoint vp = contentsToViewport(event->pos());
00562     TQListViewItem *i = itemAt(vp);
00563 
00564     TQListViewItem *qiparent;
00565     TQListViewItem *qiafterme;
00566     findDrop( event->pos(), qiparent, qiafterme );
00567 
00568     if (event->source() == viewport()) {
00569         // disable any drops where the result would be top level nodes 
00570         if (i && !i->parent())
00571         {
00572             event->ignore();
00573             d->autoopentimer.stop();
00574             return;
00575         }
00576 
00577         // prevent dragging nodes from All Feeds to My Tags or vice versa
00578         TQListViewItem* root1 = i;
00579         while (root1 && root1->parent())
00580             root1 = root1->parent();
00581 
00582         TQListViewItem* root2 = selectedItem();
00583         while (root2 && root2->parent())
00584             root2 = root2->parent();
00585 
00586         if (root1 != root2)
00587         {
00588             event->ignore();
00589             d->autoopentimer.stop();
00590             return;
00591         }
00592 
00593         // don't drop node into own subtree
00594         TQListViewItem* p = qiparent;
00595         while (p)
00596             if (p == selectedItem())
00597             {
00598                 event->ignore();
00599                 d->autoopentimer.stop();
00600                 return;
00601             }
00602             else
00603             {
00604                 p = p->parent();
00605             }
00606 
00607         // disable drags onto the item itself
00608         if (selectedItem() == i)
00609         {
00610             event->ignore();
00611             d->autoopentimer.stop();
00612             return;
00613         }
00614     }
00615 
00616     // what the hell was this good for? -fo
00617     //    if (!i || event->pos().x() > header()->cellPos(header()->mapToIndex(0)) +
00618     //            treeStepSize() * (i->depth() + 1) + itemMargin() ||
00619     //            event->pos().x() < header()->cellPos(header()->mapToIndex(0)))
00620     //   {} else
00621  
00622     // do we want to move inside the old parent or do we want to move to a new parent
00623     if (i && (itemAt(vp - TQPoint(0,5)) == i && itemAt(vp + TQPoint(0,5)) == i))
00624     {
00625         setDropVisualizer(false);
00626         setDropHighlighter(true);
00627         cleanDropVisualizer();
00628 
00629         TreeNode *iNode = (dynamic_cast<TreeNodeItem*> (i))->node();
00630         if (iNode->isGroup())
00631         {
00632             if (i != d->parent)
00633                 d->autoopentimer.start(750);
00634 
00635             d->parent = i;
00636             d->afterme = 0;
00637         }
00638         else
00639         {
00640             event->ignore();
00641             d->autoopentimer.stop();
00642             d->afterme = i;
00643             return;
00644         }
00645     }
00646     else
00647     {
00648         setDropVisualizer(true);
00649         setDropHighlighter(false);
00650         cleanItemHighlighter();
00651         d->parent = qiparent;
00652         d->afterme = qiafterme;
00653         d->autoopentimer.stop();
00654     }
00655 
00656     // the rest is handled by TDEListView.
00657     TDEListView::contentsDragMoveEvent(event);
00658 }
00659 
00660 bool NodeListView::acceptDrag(TQDropEvent *e) const
00661 {
00662     if (!acceptDrops() || !itemsMovable())
00663         return false;
00664 
00665     if (e->source() != viewport())
00666     {
00667         return KURLDrag::canDecode(e);
00668     }
00669     else
00670     {
00671         // disable dragging of top-level nodes (All Feeds, My Tags)
00672         if (selectedItem() && !selectedItem()->parent())
00673             return false;
00674         else
00675             return true;
00676     }
00677 
00678     return true;
00679 }
00680 
00681 void NodeListView::slotItemUp()
00682 {
00683     if (selectedItem() && selectedItem()->itemAbove())
00684     {
00685         setSelected( selectedItem()->itemAbove(), true );
00686         ensureItemVisible(selectedItem());
00687     }   
00688 }
00689 
00690 void NodeListView::slotItemDown()
00691 {
00692     if (selectedItem() && selectedItem()->itemBelow())
00693     {    
00694         setSelected( selectedItem()->itemBelow(), true );
00695         ensureItemVisible(selectedItem());
00696     }
00697 }
00698 
00699 void NodeListView::slotItemBegin()
00700 {
00701     setSelected( firstChild(), true );
00702     ensureItemVisible(firstChild());
00703 }
00704 
00705 void NodeListView::slotItemEnd()
00706 {
00707     TQListViewItem* elt = firstChild();
00708     if (elt)
00709         while (elt->itemBelow())
00710             elt = elt->itemBelow();
00711     setSelected( elt, true );
00712     ensureItemVisible(elt);
00713 }
00714 
00715 void NodeListView::slotItemLeft()
00716 {
00717     TQListViewItem* sel = selectedItem();
00718     
00719     if (!sel || sel == findNodeItem(rootNode()))
00720         return;
00721     
00722     if (sel->isOpen())
00723         sel->setOpen(false);
00724     else
00725     {
00726         if (sel->parent())
00727             setSelected( sel->parent(), true );
00728     }
00729         
00730     ensureItemVisible( selectedItem() );    
00731 }
00732 
00733 void NodeListView::slotItemRight()
00734 {
00735     TQListViewItem* sel = selectedItem();
00736     if (!sel)
00737     {
00738         setSelected( firstChild(), true );
00739         sel = firstChild();
00740     }
00741     if (sel->isExpandable() && !sel->isOpen())
00742         sel->setOpen(true);
00743     else
00744     {
00745         if (sel->firstChild())
00746             setSelected( sel->firstChild(), true );
00747     }
00748     ensureItemVisible( selectedItem() );
00749 }
00750 
00751 void NodeListView::slotPrevFeed()
00752 {
00753     for (TQListViewItemIterator it( selectedItem()); it.current(); --it )
00754     {
00755         TreeNodeItem* tni = dynamic_cast<TreeNodeItem*>(*it);
00756         if (tni && !tni->isSelected() && !tni->node()->isGroup() )
00757         {
00758             setSelected(tni, true);
00759             ensureItemVisible(tni);
00760             return;
00761         }     
00762     }
00763 }
00764     
00765 void NodeListView::slotNextFeed()
00766 {
00767     for (TQListViewItemIterator it( selectedItem()); it.current(); ++it )
00768     {
00769         TreeNodeItem* tni = dynamic_cast<TreeNodeItem*>(*it);
00770         if ( tni && !tni->isSelected() && !tni->node()->isGroup() )
00771         {
00772             setSelected(tni, true);
00773             ensureItemVisible(tni);
00774             return;
00775         }     
00776     }
00777 }
00778 
00779 void NodeListView::slotPrevUnreadFeed()
00780 {
00781     if (!firstChild() || !firstChild()->firstChild())
00782         return;
00783     if ( !selectedItem() )
00784         slotNextUnreadFeed(); 
00785 
00786     TQListViewItemIterator it( selectedItem() );
00787     
00788     for ( ; it.current(); --it )
00789     {
00790         TreeNodeItem* tni = dynamic_cast<TreeNodeItem*> (it.current());
00791         if (!tni)
00792             break;
00793         if ( !tni->isSelected() && !tni->node()->isGroup() && tni->node()->unread() > 0)
00794         {
00795             setSelected(tni, true);
00796             ensureItemVisible(tni);
00797             return;
00798         }
00799     }
00800     // reached when there is no unread feed above the selected one
00801     // => cycle: go to end of list...
00802     if (rootNode()->unread() > 0)
00803     {
00804 
00805         it = TQListViewItemIterator(lastItem());
00806     
00807         for ( ; it.current(); --it)
00808         {
00809 
00810             TreeNodeItem* tni = dynamic_cast<TreeNodeItem*> (it.current());
00811 
00812             if (!tni)
00813                 break;
00814 
00815             if (!tni->isSelected() && !tni->node()->isGroup() && tni->node()->unread() > 0)
00816             {
00817                 setSelected(tni, true);
00818                 ensureItemVisible(tni);
00819                 return;
00820             }
00821         }
00822     }
00823 }
00824 
00825 void NodeListView::slotNextUnreadFeed()
00826 {
00827     TQListViewItemIterator it;
00828     
00829     if ( !selectedItem() )
00830     {
00831         // if all feeds doesnt exists or is empty, return
00832         if (!firstChild() || !firstChild()->firstChild())
00833             return;    
00834         else 
00835             it = TQListViewItemIterator( firstChild()->firstChild());
00836     }
00837     else
00838         it = TQListViewItemIterator( selectedItem() );
00839     
00840     for ( ; it.current(); ++it )
00841     {
00842         TreeNodeItem* tni = dynamic_cast<TreeNodeItem*> (it.current());
00843         if (!tni)
00844             break;
00845         if ( !tni->isSelected() && !tni->node()->isGroup() && tni->node()->unread() > 0)
00846         {
00847             setSelected(tni, true);
00848             ensureItemVisible(tni);
00849             return;
00850         }
00851     }
00852     // if reached, we are at the end of the list++
00853     if (rootNode()->unread() > 0)
00854     {
00855         clearSelection();
00856         slotNextUnreadFeed();
00857     }
00858 }
00859 
00860 void NodeListView::slotSelectionChanged(TQListViewItem* item)
00861 {
00862     TreeNodeItem* ni = dynamic_cast<TreeNodeItem*> (item);
00863     
00864     if (ni)
00865     {
00866         emit signalNodeSelected(ni->node());
00867     }
00868 }
00869 
00870 void NodeListView::slotItemRenamed(TQListViewItem* item, int col, const TQString& text)
00871 {
00872     TreeNodeItem* ni = dynamic_cast<TreeNodeItem*> (item);
00873     if ( !ni || !ni->node() )
00874         return;
00875     if (col == 0)
00876     {
00877         if (text != ni->node()->title())
00878         {
00879             ni->node()->setTitle(text);
00880         }
00881     }
00882 }
00883 void NodeListView::slotContextMenu(TDEListView* list, TQListViewItem* item, const TQPoint& p)
00884 {    
00885     TreeNodeItem* ti = dynamic_cast<TreeNodeItem*>(item);
00886     emit signalContextMenu(list, ti ? ti->node() : 0, p);
00887     if (ti)
00888         ti->showContextMenu(p);
00889 }
00890 
00891 void NodeListView::slotFeedFetchStarted(Feed* feed)
00892 {
00893     // Disable icon to show it is fetching.
00894     if (!feed->favicon().isNull())
00895     {
00896         TreeNodeItem* item = findNodeItem(feed);
00897         if (item)
00898         {
00899             TDEIconEffect iconEffect;
00900             TQPixmap tempIcon = iconEffect.apply(feed->favicon(), TDEIcon::Small, TDEIcon::DisabledState);
00901             item->setPixmap(0, tempIcon);
00902         }
00903     }
00904 
00905 }
00906 
00907 void NodeListView::slotFeedFetchAborted(Feed* feed)
00908 {
00909     TreeNodeItem* item = findNodeItem(feed);
00910     if (item)
00911         item->nodeChanged();
00912 }
00913 
00914 void NodeListView::slotFeedFetchError(Feed* feed)
00915 {
00916     TreeNodeItem* item = findNodeItem(feed);
00917     if (item)
00918         item->nodeChanged();
00919 }
00920 
00921 void NodeListView::slotFeedFetchCompleted(Feed* feed)
00922 {
00923     TreeNodeItem* item = findNodeItem(feed);
00924     if (item)
00925         item->nodeChanged();
00926 }
00927       
00928 void NodeListView::slotNodeAdded(TreeNode* node)
00929 {
00930     if (node)
00931         d->createItemVisitor->visit(node);
00932 }
00933 
00934 void NodeListView::slotNodeRemoved(Folder* /*parent*/, TreeNode* node)
00935 {
00936     if (node)
00937         d->deleteItemVisitor->deleteItem(node, false);
00938 }
00939 
00940 void NodeListView::connectToNode(TreeNode* node)
00941 {
00942     if (node)
00943         d->connectNodeVisitor->visit(node);
00944 }
00945 
00946 void NodeListView::connectToNodeList(NodeList* list)
00947 {
00948     if (!list)
00949         return;
00950     
00951     connect(list, TQT_SIGNAL(signalDestroyed(NodeList*)), this, TQT_SLOT(slotNodeListDestroyed(NodeList*)) );
00952     connect(list->rootNode(), TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotRootNodeChanged(TreeNode*)));
00953 }
00954 
00955 void NodeListView::disconnectFromNodeList(NodeList* list)
00956 {
00957     if (!list)
00958         return;
00959     
00960     disconnect(list, TQT_SIGNAL(signalDestroyed(NodeList*)), this, TQT_SLOT(slotNodeListDestroyed(NodeList*)) );
00961     disconnect(list->rootNode(), TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotRootNodeChanged(TreeNode*)));
00962 }
00963 
00964 void NodeListView::disconnectFromNode(TreeNode* node)
00965 {
00966     if (node)
00967         d->disconnectNodeVisitor->visit(node);
00968 }
00969 
00970 void NodeListView::slotNodeListDestroyed(NodeList* list)
00971 {
00972     if (list != d->nodeList)
00973         return;
00974 
00975     setNodeList(0);
00976 }
00977 
00978 void NodeListView::slotNodeDestroyed(TreeNode* node)
00979 {
00980     if (node)
00981         d->deleteItemVisitor->deleteItem(node, true);
00982 }
00983 
00984 void NodeListView::slotRootNodeChanged(TreeNode* rootNode)
00985 {
00986     emit signalRootNodeChanged(this, rootNode);
00987 }
00988 
00989 void NodeListView::slotNodeChanged(TreeNode* node)
00990 {
00991     TreeNodeItem* item = findNodeItem(node);
00992     if (item)
00993     {    
00994         item->nodeChanged();
00995         triggerUpdate();
00996     }    
00997 }
00998 
00999 TQDragObject *NodeListView::dragObject()
01000 {
01001     KMultipleDrag *md = new KMultipleDrag(viewport());
01002     TQDragObject *obj = TDEListView::dragObject();
01003     if (obj) {
01004         md->addDragObject(obj);
01005     }
01006     TreeNodeItem *i = dynamic_cast<TreeNodeItem*>(currentItem());
01007     if (i) {
01008         md->setPixmap(*(i->pixmap(0)));
01009         FeedItem *fi = dynamic_cast<FeedItem*>(i);
01010         if (fi) {
01011             md->addDragObject(new KURLDrag(KURL(fi->node()->xmlUrl()), 0L));
01012         }
01013     }
01014     return md;
01015 }
01016 
01017 void NodeListView::openFolder() {
01018     d->autoopentimer.stop();
01019     if (d->parent && !d->parent->isOpen())
01020     {
01021         d->parent->setOpen(true);
01022     }
01023 }
01024 
01025 } // namespace Akregator
01026 
01027 #include "feedlistview.moc"