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 <klocale.h> 00046 #include <kmultipledrag.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 00082 virtual bool visitTreeNode(TreeNode* node) 00083 { 00084 connect(node, TQT_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQT_SLOT(slotNodeDestroyed(TreeNode*) )); 00085 connect(node, TQT_SIGNAL(signalChanged(TreeNode*)), m_view, TQT_SLOT(slotNodeChanged(TreeNode*) )); 00086 return true; 00087 } 00088 00089 virtual bool visitFolder(Folder* node) 00090 { 00091 visitTreeNode(node); 00092 connect(node, TQT_SIGNAL(signalChildAdded(TreeNode*)), m_view, TQT_SLOT(slotNodeAdded(TreeNode*) )); 00093 connect(node, TQT_SIGNAL(signalChildRemoved(Folder*, TreeNode*)), m_view, TQT_SLOT(slotNodeRemoved(Folder*, TreeNode*) )); 00094 return true; 00095 } 00096 00097 virtual bool visitFeed(Feed* node) 00098 { 00099 visitTreeNode(node); 00100 00101 connect(node, TQT_SIGNAL(fetchStarted(Feed*)), m_view, TQT_SLOT(slotFeedFetchStarted(Feed*))); 00102 connect(node, TQT_SIGNAL(fetchAborted(Feed*)), m_view, TQT_SLOT(slotFeedFetchAborted(Feed*))); 00103 connect(node, TQT_SIGNAL(fetchError(Feed*)), m_view, TQT_SLOT(slotFeedFetchError(Feed*))); 00104 connect(node, TQT_SIGNAL(fetched(Feed*)), m_view, TQT_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, TQT_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQT_SLOT(slotNodeDestroyed(TreeNode*) )); 00121 disconnect(node, TQT_SIGNAL(signalChanged(TreeNode*)), m_view, TQT_SLOT(slotNodeChanged(TreeNode*) )); 00122 return true; 00123 } 00124 00125 virtual bool visitFolder(Folder* node) 00126 { 00127 disconnect(node, TQT_SIGNAL(signalChildAdded(TreeNode*)), m_view, TQT_SLOT(slotNodeAdded(TreeNode*) )); 00128 disconnect(node, TQT_SIGNAL(signalChildRemoved(Folder*, TreeNode*)), m_view, TQT_SLOT(slotNodeRemoved(Folder*, TreeNode*) )); 00129 00130 disconnect(node, TQT_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQT_SLOT(slotNodeDestroyed(TreeNode*) )); 00131 disconnect(node, TQT_SIGNAL(signalChanged(TreeNode*)), m_view, TQT_SLOT(slotNodeChanged(TreeNode*) )); 00132 return true; 00133 } 00134 00135 virtual bool visitFeed(Feed* node) 00136 { 00137 00138 disconnect(node, TQT_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQT_SLOT(slotNodeDestroyed(TreeNode*) )); 00139 disconnect(node, TQT_SIGNAL(signalChanged(TreeNode*)), m_view, TQT_SLOT(slotNodeChanged(TreeNode*) )); 00140 disconnect(node, TQT_SIGNAL(fetchStarted(Feed*)), m_view, TQT_SLOT(slotFeedFetchStarted(Feed*))); 00141 disconnect(node, TQT_SIGNAL(fetchAborted(Feed*)), m_view, TQT_SLOT(slotFeedFetchAborted(Feed*))); 00142 disconnect(node, TQT_SIGNAL(fetchError(Feed*)), m_view, TQT_SLOT(slotFeedFetchError(Feed*))); 00143 disconnect(node, TQT_SIGNAL(fetched(Feed*)), m_view, TQT_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 TQValueList<TreeNode*> children = node->children(); 00184 for (TQValueList<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 TQValueList<TreeNode*> children = node->children(); 00271 00272 // add children recursively 00273 for (TQValueList<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 TQValueList<TreeNode*> children = node->children(); 00310 for (TQValueList<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( TQWidget *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, TQT_SIGNAL(dropped(TQDropEvent*, TQListViewItem*)), this, TQT_SLOT(slotDropped(TQDropEvent*, TQListViewItem*)) ); 00381 connect( this, TQT_SIGNAL(selectionChanged(TQListViewItem*)), this, TQT_SLOT(slotSelectionChanged(TQListViewItem*)) ); 00382 connect( this, TQT_SIGNAL(itemRenamed(TQListViewItem*, int, const TQString&)), this, TQT_SLOT(slotItemRenamed(TQListViewItem*, int, const TQString&)) ); 00383 connect( this, TQT_SIGNAL(contextMenu(KListView*, TQListViewItem*, const TQPoint&)), this, TQT_SLOT(slotContextMenu(KListView*, TQListViewItem*, const TQPoint&)) ); 00384 connect( &(d->autoopentimer), TQT_SIGNAL( timeout() ), this, TQT_SLOT( openFolder() ) ); 00385 00386 clear(); 00387 00388 TQWhatsThis::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 TQString& 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 TQString& 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 TQPtrDictIterator<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( TQPainter * 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( TQDropEvent *e, TQListViewItem* 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(TQListViewItem* /*parent*/, TQListViewItem* /*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(TQDragMoveEvent* event) 00556 { 00557 TQPoint vp = contentsToViewport(event->pos()); 00558 TQListViewItem *i = itemAt(vp); 00559 00560 TQListViewItem *qiparent; 00561 TQListViewItem *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 TQListViewItem* root1 = i; 00575 while (root1 && root1->parent()) 00576 root1 = root1->parent(); 00577 00578 TQListViewItem* 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 TQListViewItem* 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 - TQPoint(0,5)) == i && itemAt(vp + TQPoint(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(TQDropEvent *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 TQListViewItem* 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 TQListViewItem* 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 TQListViewItem* 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 (TQListViewItemIterator 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 (TQListViewItemIterator 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 TQListViewItemIterator 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 = TQListViewItemIterator(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 TQListViewItemIterator 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 = TQListViewItemIterator( firstChild()->firstChild()); 00832 } 00833 else 00834 it = TQListViewItemIterator( 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(TQListViewItem* 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(TQListViewItem* item, int col, const TQString& 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, TQListViewItem* item, const TQPoint& 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 TQPixmap 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, TQT_SIGNAL(signalDestroyed(NodeList*)), this, TQT_SLOT(slotNodeListDestroyed(NodeList*)) ); 00948 connect(list->rootNode(), TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotRootNodeChanged(TreeNode*))); 00949 } 00950 00951 void NodeListView::disconnectFromNodeList(NodeList* list) 00952 { 00953 if (!list) 00954 return; 00955 00956 disconnect(list, TQT_SIGNAL(signalDestroyed(NodeList*)), this, TQT_SLOT(slotNodeListDestroyed(NodeList*)) ); 00957 disconnect(list->rootNode(), TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_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 TQDragObject *NodeListView::dragObject() 00996 { 00997 KMultipleDrag *md = new KMultipleDrag(viewport()); 00998 TQDragObject *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"