akregator/src

feedlistview.cpp
1/*
2 This file is part of Akregator.
3
4 Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
20 As a special exception, permission is given to link this program
21 with any edition of TQt, and distribute the resulting executable,
22 without including the source code for TQt in the source distribution.
23*/
24
25#include "dragobjects.h"
26#include "folder.h"
27#include "folderitem.h"
28#include "tagfolder.h"
29#include "tagfolderitem.h"
30#include "feedlistview.h"
31#include "feed.h"
32#include "feeditem.h"
33#include "feedlist.h"
34#include "tag.h"
35#include "tagnode.h"
36#include "tagnodeitem.h"
37#include "tagnodelist.h"
38#include "treenode.h"
39#include "treenodeitem.h"
40#include "treenodevisitor.h"
41
42#include <kdebug.h>
43#include <kiconeffect.h>
44#include <kiconloader.h>
45#include <tdelocale.h>
46#include <tdemultipledrag.h>
47#include <kstringhandler.h>
48#include <kurldrag.h>
49
50#include <tqfont.h>
51#include <tqheader.h>
52#include <tqpainter.h>
53#include <tqptrdict.h>
54#include <tqtimer.h>
55#include <tqwhatsthis.h>
56
57namespace Akregator {
58
59class NodeListView::NodeListViewPrivate
60{
61 public:
63 TQPtrDict<TreeNodeItem> itemDict;
64 NodeList* nodeList;
65 bool showTagFolders;
66
67 // Drag and Drop variables
68 TQListViewItem *parent;
69 TQListViewItem *afterme;
70 TQTimer autoopentimer;
71 ConnectNodeVisitor* connectNodeVisitor;
72 DisconnectNodeVisitor* disconnectNodeVisitor;
73 CreateItemVisitor* createItemVisitor;
74 DeleteItemVisitor* deleteItemVisitor;
75};
76
77class NodeListView::ConnectNodeVisitor : public TreeNodeVisitor
78{
79 public:
80 ConnectNodeVisitor(NodeListView* view) : m_view(view) {}
81 virtual ~ConnectNodeVisitor() {}
82
83 virtual bool visitTreeNode(TreeNode* node)
84 {
85 connect(node, TQ_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQ_SLOT(slotNodeDestroyed(TreeNode*) ));
86 connect(node, TQ_SIGNAL(signalChanged(TreeNode*)), m_view, TQ_SLOT(slotNodeChanged(TreeNode*) ));
87 return true;
88 }
89
90 virtual bool visitFolder(Folder* node)
91 {
92 visitTreeNode(node);
93 connect(node, TQ_SIGNAL(signalChildAdded(TreeNode*)), m_view, TQ_SLOT(slotNodeAdded(TreeNode*) ));
94 connect(node, TQ_SIGNAL(signalChildRemoved(Folder*, TreeNode*)), m_view, TQ_SLOT(slotNodeRemoved(Folder*, TreeNode*) ));
95 return true;
96 }
97
98 virtual bool visitFeed(Feed* node)
99 {
100 visitTreeNode(node);
101
102 connect(node, TQ_SIGNAL(fetchStarted(Feed*)), m_view, TQ_SLOT(slotFeedFetchStarted(Feed*)));
103 connect(node, TQ_SIGNAL(fetchAborted(Feed*)), m_view, TQ_SLOT(slotFeedFetchAborted(Feed*)));
104 connect(node, TQ_SIGNAL(fetchError(Feed*)), m_view, TQ_SLOT(slotFeedFetchError(Feed*)));
105 connect(node, TQ_SIGNAL(fetched(Feed*)), m_view, TQ_SLOT(slotFeedFetchCompleted(Feed*)));
106 return true;
107 }
108 private:
109
110 NodeListView* m_view;
111
112};
113
114class NodeListView::DisconnectNodeVisitor : public TreeNodeVisitor
115{
116 public:
117 DisconnectNodeVisitor(NodeListView* view) : m_view(view) {}
118 virtual ~DisconnectNodeVisitor() {}
119
120 virtual bool visitTagNode(TagNode* node)
121 {
122 disconnect(node, TQ_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQ_SLOT(slotNodeDestroyed(TreeNode*) ));
123 disconnect(node, TQ_SIGNAL(signalChanged(TreeNode*)), m_view, TQ_SLOT(slotNodeChanged(TreeNode*) ));
124 return true;
125 }
126
127 virtual bool visitFolder(Folder* node)
128 {
129 disconnect(node, TQ_SIGNAL(signalChildAdded(TreeNode*)), m_view, TQ_SLOT(slotNodeAdded(TreeNode*) ));
130 disconnect(node, TQ_SIGNAL(signalChildRemoved(Folder*, TreeNode*)), m_view, TQ_SLOT(slotNodeRemoved(Folder*, TreeNode*) ));
131
132 disconnect(node, TQ_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQ_SLOT(slotNodeDestroyed(TreeNode*) ));
133 disconnect(node, TQ_SIGNAL(signalChanged(TreeNode*)), m_view, TQ_SLOT(slotNodeChanged(TreeNode*) ));
134 return true;
135 }
136
137 virtual bool visitFeed(Feed* node)
138 {
139
140 disconnect(node, TQ_SIGNAL(signalDestroyed(TreeNode*)), m_view, TQ_SLOT(slotNodeDestroyed(TreeNode*) ));
141 disconnect(node, TQ_SIGNAL(signalChanged(TreeNode*)), m_view, TQ_SLOT(slotNodeChanged(TreeNode*) ));
142 disconnect(node, TQ_SIGNAL(fetchStarted(Feed*)), m_view, TQ_SLOT(slotFeedFetchStarted(Feed*)));
143 disconnect(node, TQ_SIGNAL(fetchAborted(Feed*)), m_view, TQ_SLOT(slotFeedFetchAborted(Feed*)));
144 disconnect(node, TQ_SIGNAL(fetchError(Feed*)), m_view, TQ_SLOT(slotFeedFetchError(Feed*)));
145 disconnect(node, TQ_SIGNAL(fetched(Feed*)), m_view, TQ_SLOT(slotFeedFetchCompleted(Feed*)));
146 return true;
147 }
148 private:
149
150 NodeListView* m_view;
151};
152
153class NodeListView::DeleteItemVisitor : public TreeNodeVisitor
154{
155 public:
156
157 DeleteItemVisitor(NodeListView* view) : m_view(view) {}
158 virtual ~DeleteItemVisitor() {}
159
160 virtual bool visitTreeNode(TreeNode* node)
161 {
162 TreeNodeItem* item = m_view->d->itemDict.take(node);
163
164 if (!item)
165 return true;
166
167 if ( m_selectNeighbour && item->isSelected() )
168 {
169 if (item->itemBelow())
170 m_view->setSelected(item->itemBelow(), true);
171 else if (item->itemAbove())
172 m_view->setSelected(item->itemAbove(), true);
173 else
174 m_view->setSelected(item, false);
175 }
176
177 m_view->disconnectFromNode(node);
178 delete item;
179 return true;
180
181 }
182
183 virtual bool visitFolder(Folder* node)
184 {
185 // delete child items recursively before deleting parent
186 TQValueList<TreeNode*> children = node->children();
187 for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != children.end(); ++it )
188 visit(*it);
189
190 visitTreeNode(node);
191
192 return true;
193 }
194
195 void deleteItem(TreeNode* node, bool selectNeighbour)
196 {
197 m_selectNeighbour = selectNeighbour;
198 visit(node);
199 }
200
201 private:
202 NodeListView* m_view;
203 bool m_selectNeighbour;
204};
205
206class NodeListView::CreateItemVisitor : public TreeNodeVisitor
207{
208 public:
209 CreateItemVisitor(NodeListView* view) : m_view(view) {}
210 virtual ~CreateItemVisitor() {}
211
212 virtual bool visitTagNode(TagNode* node)
213 {
214 if (m_view->findNodeItem(node))
215 return true;
216
217 TagNodeItem* item = 0;
218 TreeNode* prev = node->prevSibling();
219 FolderItem* parentItem = static_cast<FolderItem*>(m_view->findNodeItem(node->parent()));
220 if (parentItem)
221 {
222 if (prev)
223 {
224 item = new TagNodeItem( parentItem, m_view->findNodeItem(prev), node);
225 }
226 else
227 item = new TagNodeItem( parentItem, node);
228 }
229 else
230 {
231 if (prev)
232 {
233 item = new TagNodeItem(m_view, m_view->findNodeItem(prev), node);
234 }
235 else
236 item = new TagNodeItem(m_view, node);
237 }
238 item->nodeChanged();
239 m_view->d->itemDict.insert(node, item);
240 m_view->connectToNode(node);
241 if (parentItem)
242 parentItem->sortChildItems(0, true);
243 return true;
244 }
245
246 virtual bool visitTagFolder(TagFolder* node)
247 {
248 if (m_view->findNodeItem(node))
249 return true;
250
251 TagFolderItem* item = 0;
252 TreeNode* prev = node->prevSibling();
253 FolderItem* parentItem = static_cast<FolderItem*>(m_view->findNodeItem(node->parent()));
254 if (parentItem)
255 {
256 if (prev)
257 {
258 item = new TagFolderItem( parentItem, m_view->findNodeItem(prev), node);
259 }
260 else
261 item = new TagFolderItem(parentItem, node);
262 }
263 else
264 {
265 if (prev)
266 {
267 item = new TagFolderItem(m_view, m_view->findNodeItem(prev), node);
268 }
269 else
270 item = new TagFolderItem(m_view, node);
271
272 }
273 m_view->d->itemDict.insert(node, item);
274 TQValueList<TreeNode*> children = node->children();
275
276 // add children recursively
277 for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != children.end(); ++it )
278 visit(*it);
279
280 m_view->connectToNode(node);
281 return true;
282 }
283
284 virtual bool visitFolder(Folder* node)
285 {
286 if (m_view->findNodeItem(node))
287 return true;
288
289 FolderItem* item = 0;
290 TreeNode* prev = node->prevSibling();
291 FolderItem* parentItem = static_cast<FolderItem*>(m_view->findNodeItem(node->parent()));
292 if (parentItem)
293 {
294 if (prev)
295 {
296 item = new FolderItem( parentItem, m_view->findNodeItem(prev), node);
297 }
298 else
299 item = new FolderItem(parentItem, node);
300 }
301 else
302 {
303 if (prev)
304 {
305 item = new FolderItem(m_view, m_view->findNodeItem(prev), node);
306 }
307 else
308 item = new FolderItem(m_view, node);
309 }
310 m_view->d->itemDict.insert(node, item);
311
312 // add children recursively
313 TQValueList<TreeNode*> children = node->children();
314 for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != children.end(); ++it )
315 visit(*it);
316
317 m_view->connectToNode(node);
318 return true;
319 }
320
321 virtual bool visitFeed(Feed* node)
322 {
323 if (m_view->findNodeItem(node))
324 return true;
325
326 FeedItem* item = 0;
327 TreeNode* prev = node->prevSibling();
328 FolderItem* parentItem = static_cast<FolderItem*>(m_view->findNodeItem(node->parent()));
329
330 if (parentItem)
331 {
332 if (prev)
333 {
334 item = new FeedItem( parentItem, m_view->findNodeItem(prev), node);
335 }
336 else
337 item = new FeedItem( parentItem, node);
338 }
339 else
340 {
341 if (prev)
342 {
343 item = new FeedItem(m_view, m_view->findNodeItem(prev), node);
344 }
345 else
346 item = new FeedItem(m_view, node);
347 }
348
349 item->nodeChanged();
350 m_view->d->itemDict.insert(node, item);
351 m_view->connectToNode(node);
352 return true;
353 }
354
355 private:
356 NodeListView* m_view;
357};
358
359NodeListView::NodeListView( TQWidget *parent, const char *name)
360 : TDEListView(parent, name), d(new NodeListViewPrivate)
361{
362 d->showTagFolders = true;
363 d->connectNodeVisitor = new ConnectNodeVisitor(this),
364 d->disconnectNodeVisitor = new DisconnectNodeVisitor(this);
365 d->createItemVisitor = new CreateItemVisitor(this);
366 d->deleteItemVisitor = new DeleteItemVisitor(this);
367
368 setMinimumSize(150, 150);
369 addColumn(i18n("Feeds"));
370 setRootIsDecorated(false);
371 setItemsRenameable(false); // NOTE: setting this this to true collides with setRenameEnabled() in items and breaks in-place renaming in strange ways. Do not enable!
372 setItemMargin(2);
373
374 setFullWidth(true);
375 setSorting(-1);
376 setDragAutoScroll(true);
377 setDropVisualizer(true);
378 //setDropHighlighter(false);
379
380 setDragEnabled(true);
381 setAcceptDrops(true);
382 setItemsMovable(true);
383
384 connect( this, TQ_SIGNAL(dropped(TQDropEvent*, TQListViewItem*)), this, TQ_SLOT(slotDropped(TQDropEvent*, TQListViewItem*)) );
385 connect( this, TQ_SIGNAL(selectionChanged(TQListViewItem*)), this, TQ_SLOT(slotSelectionChanged(TQListViewItem*)) );
386 connect( this, TQ_SIGNAL(itemRenamed(TQListViewItem*, int, const TQString&)), this, TQ_SLOT(slotItemRenamed(TQListViewItem*, int, const TQString&)) );
387 connect( this, TQ_SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)), this, TQ_SLOT(slotContextMenu(TDEListView*, TQListViewItem*, const TQPoint&)) );
388 connect( &(d->autoopentimer), TQ_SIGNAL( timeout() ), this, TQ_SLOT( openFolder() ) );
389
390 clear();
391
392 TQWhatsThis::add(this, i18n("<h2>Feeds tree</h2>"
393 "Here you can browse tree of feeds. "
394 "You can also add feeds or feed groups (folders) "
395 "using right-click menu, or reorganize them using "
396 "drag and drop."));
397 setUpdatesEnabled(true);
398}
399
400NodeListView::~NodeListView()
401{
402 delete d->connectNodeVisitor;
403 delete d->disconnectNodeVisitor;
404 delete d->createItemVisitor;
405 delete d->deleteItemVisitor;
406 delete d;
407 d = 0;
408}
409
410void NodeListView::setNodeList(NodeList* nodeList)
411{
412 if (nodeList == d->nodeList)
413 return;
414
415 clear();
416
417 disconnectFromNodeList(d->nodeList);
418
419 if (!nodeList)
420 return;
421
422 d->nodeList = nodeList;
423 connectToNodeList(nodeList);
424
425
426 Folder* rootNode = nodeList->rootNode();
427 if (!rootNode)
428 return;
429
430 slotNodeAdded(rootNode);
431 slotRootNodeChanged(rootNode);
432}
433
434Folder* NodeListView::rootNode()
435{
436 return d->nodeList ? d->nodeList->rootNode() : 0;
437}
438
439TreeNode* NodeListView::selectedNode()
440{
441 TreeNodeItem* item = dynamic_cast<TreeNodeItem*> (selectedItem());
442
443 return ( item ? item->node() : 0) ;
444}
445
446void NodeListView::setSelectedNode(TreeNode* node)
447{
448 TreeNodeItem* item = findNodeItem(node);
449 if ( node && item )
450 setSelected(item, true);
451}
452
453TreeNode* NodeListView::findNodeByTitle(const TQString& title)
454{
455 TreeNodeItem* item = dynamic_cast<TreeNodeItem*>(findItemByTitle(title, 0));
456 if (!item)
457 return 0;
458 else
459 return item->node();
460}
461
462TreeNodeItem* NodeListView::findNodeItem(TreeNode* node)
463{
464 return d->itemDict.find(node);
465}
466
467TreeNodeItem* NodeListView::findItemByTitle(const TQString& text, int column, ComparisonFlags compare) const
468{
469 return dynamic_cast<TreeNodeItem*> (TDEListView::findItem(text, column, compare));
470}
471
472void NodeListView::ensureNodeVisible(TreeNode* node)
473{
474 ensureItemVisible(findNodeItem(node));
475}
476
477void NodeListView::startNodeRenaming(TreeNode* node)
478{
479 TreeNodeItem* item = findNodeItem(node);
480 if (item)
481 {
482 item->startRename(0);
483 }
484}
485
486void NodeListView::clear()
487{
488 TQPtrDictIterator<TreeNodeItem> it(d->itemDict);
489 for( ; it.current(); ++it )
490 disconnectFromNode( it.current()->node() );
491 d->itemDict.clear();
492 d->nodeList = 0;
493
494 TDEListView::clear();
495}
496
497void NodeListView::drawContentsOffset( TQPainter * p, int ox, int oy,
498 int cx, int cy, int cw, int ch )
499{
500 bool oldUpdatesEnabled = isUpdatesEnabled();
501 setUpdatesEnabled(false);
502 TDEListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
503 setUpdatesEnabled(oldUpdatesEnabled);
504}
505
506void NodeListView::slotDropped( TQDropEvent *e, TQListViewItem*
507/*after*/)
508{
509 d->autoopentimer.stop();
510
511 if (e->source() != viewport())
512 {
513 openFolder();
514
515 if (KURLDrag::canDecode(e))
516 {
517 FolderItem* parent = dynamic_cast<FolderItem*> (d->parent);
518 TreeNodeItem* afterMe = 0;
519
520 if(d->afterme)
521 afterMe = dynamic_cast<TreeNodeItem*> (d->afterme);
522
523 KURL::List urls;
524 KURLDrag::decode( e, urls );
525 e->accept();
526 emit signalDropped( urls, afterMe ? afterMe->node() : 0, parent ? parent->node() : 0);
527 }
528 }
529 else
530 {
531 }
532}
533
534void NodeListView::movableDropEvent(TQListViewItem* /*parent*/, TQListViewItem* /*afterme*/)
535{
536 d->autoopentimer.stop();
537 if (d->parent)
538 {
539 openFolder();
540
541 Folder* parentNode = (dynamic_cast<FolderItem*> (d->parent))->node();
542 TreeNode* afterMeNode = 0;
543 TreeNode* current = selectedNode();
544
545 if (d->afterme)
546 afterMeNode = (dynamic_cast<TreeNodeItem*> (d->afterme))->node();
547
548 current->parent()->removeChild(current);
549 parentNode->insertChild(current, afterMeNode);
550 TDEListView::movableDropEvent(d->parent, d->afterme);
551 }
552}
553
554void NodeListView::setShowTagFolders(bool enabled)
555{
556 d->showTagFolders = enabled;
557}
558
559void NodeListView::contentsDragMoveEvent(TQDragMoveEvent* event)
560{
561 TQPoint vp = contentsToViewport(event->pos());
562 TQListViewItem *i = itemAt(vp);
563
564 TQListViewItem *qiparent;
565 TQListViewItem *qiafterme;
566 findDrop( event->pos(), qiparent, qiafterme );
567
568 if (event->source() == viewport()) {
569 // disable any drops where the result would be top level nodes
570 if (i && !i->parent())
571 {
572 event->ignore();
573 d->autoopentimer.stop();
574 return;
575 }
576
577 // prevent dragging nodes from All Feeds to My Tags or vice versa
578 TQListViewItem* root1 = i;
579 while (root1 && root1->parent())
580 root1 = root1->parent();
581
582 TQListViewItem* root2 = selectedItem();
583 while (root2 && root2->parent())
584 root2 = root2->parent();
585
586 if (root1 != root2)
587 {
588 event->ignore();
589 d->autoopentimer.stop();
590 return;
591 }
592
593 // don't drop node into own subtree
594 TQListViewItem* p = qiparent;
595 while (p)
596 if (p == selectedItem())
597 {
598 event->ignore();
599 d->autoopentimer.stop();
600 return;
601 }
602 else
603 {
604 p = p->parent();
605 }
606
607 // disable drags onto the item itself
608 if (selectedItem() == i)
609 {
610 event->ignore();
611 d->autoopentimer.stop();
612 return;
613 }
614 }
615
616 // what the hell was this good for? -fo
617 // if (!i || event->pos().x() > header()->cellPos(header()->mapToIndex(0)) +
618 // treeStepSize() * (i->depth() + 1) + itemMargin() ||
619 // event->pos().x() < header()->cellPos(header()->mapToIndex(0)))
620 // {} else
621
622 // do we want to move inside the old parent or do we want to move to a new parent
623 if (i && (itemAt(vp - TQPoint(0,5)) == i && itemAt(vp + TQPoint(0,5)) == i))
624 {
625 setDropVisualizer(false);
626 setDropHighlighter(true);
627 cleanDropVisualizer();
628
629 TreeNode *iNode = (dynamic_cast<TreeNodeItem*> (i))->node();
630 if (iNode->isGroup())
631 {
632 if (i != d->parent)
633 d->autoopentimer.start(750);
634
635 d->parent = i;
636 d->afterme = 0;
637 }
638 else
639 {
640 event->ignore();
641 d->autoopentimer.stop();
642 d->afterme = i;
643 return;
644 }
645 }
646 else
647 {
648 setDropVisualizer(true);
649 setDropHighlighter(false);
650 cleanItemHighlighter();
651 d->parent = qiparent;
652 d->afterme = qiafterme;
653 d->autoopentimer.stop();
654 }
655
656 // the rest is handled by TDEListView.
657 TDEListView::contentsDragMoveEvent(event);
658}
659
660bool NodeListView::acceptDrag(TQDropEvent *e) const
661{
662 if (!acceptDrops() || !itemsMovable())
663 return false;
664
665 if (e->source() != viewport())
666 {
667 return KURLDrag::canDecode(e);
668 }
669 else
670 {
671 // disable dragging of top-level nodes (All Feeds, My Tags)
672 if (selectedItem() && !selectedItem()->parent())
673 return false;
674 else
675 return true;
676 }
677
678 return true;
679}
680
681void NodeListView::slotItemUp()
682{
683 if (selectedItem() && selectedItem()->itemAbove())
684 {
685 setSelected( selectedItem()->itemAbove(), true );
686 ensureItemVisible(selectedItem());
687 }
688}
689
690void NodeListView::slotItemDown()
691{
692 if (selectedItem() && selectedItem()->itemBelow())
693 {
694 setSelected( selectedItem()->itemBelow(), true );
695 ensureItemVisible(selectedItem());
696 }
697}
698
699void NodeListView::slotItemBegin()
700{
701 setSelected( firstChild(), true );
702 ensureItemVisible(firstChild());
703}
704
705void NodeListView::slotItemEnd()
706{
707 TQListViewItem* elt = firstChild();
708 if (elt)
709 while (elt->itemBelow())
710 elt = elt->itemBelow();
711 setSelected( elt, true );
712 ensureItemVisible(elt);
713}
714
715void NodeListView::slotItemLeft()
716{
717 TQListViewItem* sel = selectedItem();
718
719 if (!sel || sel == findNodeItem(rootNode()))
720 return;
721
722 if (sel->isOpen())
723 sel->setOpen(false);
724 else
725 {
726 if (sel->parent())
727 setSelected( sel->parent(), true );
728 }
729
730 ensureItemVisible( selectedItem() );
731}
732
733void NodeListView::slotItemRight()
734{
735 TQListViewItem* sel = selectedItem();
736 if (!sel)
737 {
738 setSelected( firstChild(), true );
739 sel = firstChild();
740 }
741 if (sel->isExpandable() && !sel->isOpen())
742 sel->setOpen(true);
743 else
744 {
745 if (sel->firstChild())
746 setSelected( sel->firstChild(), true );
747 }
748 ensureItemVisible( selectedItem() );
749}
750
751void NodeListView::slotPrevFeed()
752{
753 for (TQListViewItemIterator it( selectedItem()); it.current(); --it )
754 {
755 TreeNodeItem* tni = dynamic_cast<TreeNodeItem*>(*it);
756 if (tni && !tni->isSelected() && !tni->node()->isGroup() )
757 {
758 setSelected(tni, true);
759 ensureItemVisible(tni);
760 return;
761 }
762 }
763}
764
765void NodeListView::slotNextFeed()
766{
767 for (TQListViewItemIterator it( selectedItem()); it.current(); ++it )
768 {
769 TreeNodeItem* tni = dynamic_cast<TreeNodeItem*>(*it);
770 if ( tni && !tni->isSelected() && !tni->node()->isGroup() )
771 {
772 setSelected(tni, true);
773 ensureItemVisible(tni);
774 return;
775 }
776 }
777}
778
779void NodeListView::slotPrevUnreadFeed()
780{
781 if (!firstChild() || !firstChild()->firstChild())
782 return;
783 if ( !selectedItem() )
784 slotNextUnreadFeed();
785
786 TQListViewItemIterator it( selectedItem() );
787
788 for ( ; it.current(); --it )
789 {
790 TreeNodeItem* tni = dynamic_cast<TreeNodeItem*> (it.current());
791 if (!tni)
792 break;
793 if ( !tni->isSelected() && !tni->node()->isGroup() && tni->node()->unread() > 0)
794 {
795 setSelected(tni, true);
796 ensureItemVisible(tni);
797 return;
798 }
799 }
800 // reached when there is no unread feed above the selected one
801 // => cycle: go to end of list...
802 if (rootNode()->unread() > 0)
803 {
804
805 it = TQListViewItemIterator(lastItem());
806
807 for ( ; it.current(); --it)
808 {
809
810 TreeNodeItem* tni = dynamic_cast<TreeNodeItem*> (it.current());
811
812 if (!tni)
813 break;
814
815 if (!tni->isSelected() && !tni->node()->isGroup() && tni->node()->unread() > 0)
816 {
817 setSelected(tni, true);
818 ensureItemVisible(tni);
819 return;
820 }
821 }
822 }
823}
824
825void NodeListView::slotNextUnreadFeed()
826{
827 TQListViewItemIterator it;
828
829 if ( !selectedItem() )
830 {
831 // if all feeds doesnt exists or is empty, return
832 if (!firstChild() || !firstChild()->firstChild())
833 return;
834 else
835 it = TQListViewItemIterator( firstChild()->firstChild());
836 }
837 else
838 it = TQListViewItemIterator( selectedItem() );
839
840 for ( ; it.current(); ++it )
841 {
842 TreeNodeItem* tni = dynamic_cast<TreeNodeItem*> (it.current());
843 if (!tni)
844 break;
845 if ( !tni->isSelected() && !tni->node()->isGroup() && tni->node()->unread() > 0)
846 {
847 setSelected(tni, true);
848 ensureItemVisible(tni);
849 return;
850 }
851 }
852 // if reached, we are at the end of the list++
853 if (rootNode()->unread() > 0)
854 {
855 clearSelection();
856 slotNextUnreadFeed();
857 }
858}
859
860void NodeListView::slotSelectionChanged(TQListViewItem* item)
861{
862 TreeNodeItem* ni = dynamic_cast<TreeNodeItem*> (item);
863
864 if (ni)
865 {
866 emit signalNodeSelected(ni->node());
867 }
868}
869
870void NodeListView::slotItemRenamed(TQListViewItem* item, int col, const TQString& text)
871{
872 TreeNodeItem* ni = dynamic_cast<TreeNodeItem*> (item);
873 if ( !ni || !ni->node() )
874 return;
875 if (col == 0)
876 {
877 if (text != ni->node()->title())
878 {
879 ni->node()->setTitle(text);
880 }
881 }
882}
883void NodeListView::slotContextMenu(TDEListView* list, TQListViewItem* item, const TQPoint& p)
884{
885 TreeNodeItem* ti = dynamic_cast<TreeNodeItem*>(item);
886 emit signalContextMenu(list, ti ? ti->node() : 0, p);
887 if (ti)
888 ti->showContextMenu(p);
889}
890
891void NodeListView::slotFeedFetchStarted(Feed* feed)
892{
893 // Disable icon to show it is fetching.
894 if (!feed->favicon().isNull())
895 {
896 TreeNodeItem* item = findNodeItem(feed);
897 if (item)
898 {
899 TDEIconEffect iconEffect;
900 TQPixmap tempIcon = iconEffect.apply(feed->favicon(), TDEIcon::Small, TDEIcon::DisabledState);
901 item->setPixmap(0, tempIcon);
902 }
903 }
904
905}
906
907void NodeListView::slotFeedFetchAborted(Feed* feed)
908{
909 TreeNodeItem* item = findNodeItem(feed);
910 if (item)
911 item->nodeChanged();
912}
913
914void NodeListView::slotFeedFetchError(Feed* feed)
915{
916 TreeNodeItem* item = findNodeItem(feed);
917 if (item)
918 item->nodeChanged();
919}
920
921void NodeListView::slotFeedFetchCompleted(Feed* feed)
922{
923 TreeNodeItem* item = findNodeItem(feed);
924 if (item)
925 item->nodeChanged();
926}
927
928void NodeListView::slotNodeAdded(TreeNode* node)
929{
930 if (node)
931 d->createItemVisitor->visit(node);
932}
933
934void NodeListView::slotNodeRemoved(Folder* /*parent*/, TreeNode* node)
935{
936 if (node)
937 d->deleteItemVisitor->deleteItem(node, false);
938}
939
940void NodeListView::connectToNode(TreeNode* node)
941{
942 if (node)
943 d->connectNodeVisitor->visit(node);
944}
945
946void NodeListView::connectToNodeList(NodeList* list)
947{
948 if (!list)
949 return;
950
951 connect(list, TQ_SIGNAL(signalDestroyed(NodeList*)), this, TQ_SLOT(slotNodeListDestroyed(NodeList*)) );
952 connect(list->rootNode(), TQ_SIGNAL(signalChanged(TreeNode*)), this, TQ_SLOT(slotRootNodeChanged(TreeNode*)));
953}
954
955void NodeListView::disconnectFromNodeList(NodeList* list)
956{
957 if (!list)
958 return;
959
960 disconnect(list, TQ_SIGNAL(signalDestroyed(NodeList*)), this, TQ_SLOT(slotNodeListDestroyed(NodeList*)) );
961 disconnect(list->rootNode(), TQ_SIGNAL(signalChanged(TreeNode*)), this, TQ_SLOT(slotRootNodeChanged(TreeNode*)));
962}
963
964void NodeListView::disconnectFromNode(TreeNode* node)
965{
966 if (node)
967 d->disconnectNodeVisitor->visit(node);
968}
969
970void NodeListView::slotNodeListDestroyed(NodeList* list)
971{
972 if (list != d->nodeList)
973 return;
974
975 setNodeList(0);
976}
977
978void NodeListView::slotNodeDestroyed(TreeNode* node)
979{
980 if (node)
981 d->deleteItemVisitor->deleteItem(node, true);
982}
983
984void NodeListView::slotRootNodeChanged(TreeNode* rootNode)
985{
986 emit signalRootNodeChanged(this, rootNode);
987}
988
989void NodeListView::slotNodeChanged(TreeNode* node)
990{
991 TreeNodeItem* item = findNodeItem(node);
992 if (item)
993 {
994 item->nodeChanged();
995 triggerUpdate();
996 }
997}
998
999TQDragObject *NodeListView::dragObject()
1000{
1001 KMultipleDrag *md = new KMultipleDrag(viewport());
1002 TQDragObject *obj = TDEListView::dragObject();
1003 if (obj) {
1004 md->addDragObject(obj);
1005 }
1006 TreeNodeItem *i = dynamic_cast<TreeNodeItem*>(currentItem());
1007 if (i) {
1008 md->setPixmap(*(i->pixmap(0)));
1009 FeedItem *fi = dynamic_cast<FeedItem*>(i);
1010 if (fi) {
1011 md->addDragObject(new KURLDrag(KURL(fi->node()->xmlUrl()), 0L));
1012 }
1013 }
1014 return md;
1015}
1016
1017void NodeListView::openFolder() {
1018 d->autoopentimer.stop();
1019 if (d->parent && !d->parent->isOpen())
1020 {
1021 d->parent->setOpen(true);
1022 }
1023}
1024
1025} // namespace Akregator
1026
1027#include "feedlistview.moc"