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