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