summaryrefslogtreecommitdiffstats
path: root/src/app/treeview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/treeview.cpp')
-rw-r--r--src/app/treeview.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/src/app/treeview.cpp b/src/app/treeview.cpp
new file mode 100644
index 0000000..ddf24a5
--- /dev/null
+++ b/src/app/treeview.cpp
@@ -0,0 +1,342 @@
+// vim: set tabstop=4 shiftwidth=4 noexpandtab:
+/*
+Gwenview - A simple image viewer for KDE
+Copyright 2000-2004 Aur�ien G�eau
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+#include "treeview.moc"
+
+// Qt
+#include <qheader.h>
+#include <qtimer.h>
+
+// KDE
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kmimetype.h>
+#include <kurldrag.h>
+
+// Local
+#include "../gvcore/fileoperation.h"
+
+namespace Gwenview {
+
+#undef ENABLE_LOG
+#undef LOG
+//#define ENABLE_LOG
+#ifdef ENABLE_LOG
+#define LOG(x) kdDebug() << k_funcinfo << x << endl
+#else
+#define LOG(x) ;
+#endif
+
+const int AUTO_OPEN_DELAY=1000;
+const int DND_ICON_COUNT=8;
+const char* DND_PREFIX="dnd";
+
+
+struct TreeView::Private {
+ TreeView* mView;
+ KFileTreeBranch* mBranch;
+ KFileTreeViewItem* mDropTarget;
+ QTimer* mAutoOpenTimer;
+
+ KFileTreeViewItem* findViewItem(KFileTreeViewItem* parent,const QString& text) {
+ QListViewItem* item;
+
+ for (item=parent->firstChild();item;item=item->nextSibling()) {
+ if (item->text(0)==text) {
+ return static_cast<KFileTreeViewItem*>(item);
+ }
+ }
+ return 0L;
+ }
+
+ void setURLInternal(const KURL& url) {
+ LOG(url.prettyURL() );
+ QString path=url.path();
+
+ if (!mBranch || !mBranch->rootUrl().isParentOf(url)) {
+ mView->createBranch(url);
+ return;
+ }
+
+ // The request URL is a child of the branch, expand the branch to reach
+ // the child
+ LOG("Expanding to reach child");
+ if(mBranch->rootUrl().path()!="/") {
+ path.remove(0,mBranch->rootUrl().path().length());
+ }
+ LOG("Path=" << path);
+
+ // Finds the deepest existing view item
+ QStringList folderParts=QStringList::split('/',path);
+ QStringList::Iterator folderIter=folderParts.begin();
+ QStringList::Iterator endFolderIter=folderParts.end();
+ KFileTreeViewItem* viewItem=mBranch->root();
+ for(;folderIter!=endFolderIter;++folderIter) {
+
+ KFileTreeViewItem* nextViewItem=findViewItem(viewItem,*folderIter);
+ if (!nextViewItem) break;
+ viewItem=nextViewItem;
+ }
+ LOG("Deepest existing view item=" << viewItem->url());
+
+ // If this is the wanted item, select it,
+ // otherwise set the url as the next to select
+ if (viewItem->url().equals(url,true)) {
+ LOG("We are done");
+ mView->setCurrentItem(viewItem);
+ mView->ensureItemVisible(viewItem);
+ mView->slotSetNextUrlToSelect(KURL());
+ } else {
+ LOG("We continue");
+ mView->slotSetNextUrlToSelect(url);
+ }
+
+ LOG("Opening deepest existing view item");
+ viewItem->setOpen(true);
+ }
+};
+
+
+TreeView::TreeView(QWidget* parent)
+: KFileTreeView(parent) {
+ d=new Private;
+ d->mView=this;
+ d->mBranch=0;
+ d->mDropTarget=0;
+ d->mAutoOpenTimer=new QTimer(this);
+
+ // Look
+ addColumn(QString::null);
+ header()->hide();
+ setAllColumnsShowFocus(true);
+ setRootIsDecorated(false);
+ setFullWidth(true);
+
+ // Drag'n'drop
+ setDragEnabled(true);
+ setDropVisualizer(false);
+ setDropHighlighter(true);
+ setAcceptDrops(true);
+
+ connect(d->mAutoOpenTimer, SIGNAL(timeout()),
+ this, SLOT(autoOpenDropTarget()));
+}
+
+
+TreeView::~TreeView() {
+ delete d;
+}
+
+
+void TreeView::setURL(const KURL& url) {
+ LOG(url.prettyURL());
+ if (currentURL().equals(url,true)) return;
+ if (m_nextUrlToSelect.equals(url,true)) return;
+ slotSetNextUrlToSelect(url);
+
+ // Do not update the view if it's hidden, the url has been stored with
+ // slotSetNextUrlToSelect. The view will expand to it next time it's shown.
+ if (!isVisible()) {
+ LOG("We are hidden, just store the url");
+ return;
+ }
+
+ d->setURLInternal(url);
+}
+
+
+void TreeView::slotTreeViewPopulateFinished(KFileTreeViewItem* item) {
+ QListViewItem* child;
+ if (!item) return;
+ KURL url=item->url();
+
+ if (d->mDropTarget) {
+ startAnimation(d->mDropTarget,DND_PREFIX,DND_ICON_COUNT);
+ }
+
+ LOG("itemURL=" << url);
+ LOG("m_nextUrlToSelect=" << m_nextUrlToSelect);
+
+ // We reached the URL to select, get out
+ if (url.equals(m_nextUrlToSelect, true)) {
+ slotSetNextUrlToSelect(KURL());
+ return;
+ }
+
+ // This URL is not a parent of a wanted URL, get out
+ if (!url.isParentOf(m_nextUrlToSelect)) return;
+
+ // Find the next child item and open it
+ LOG("Looking for next child");
+ for (child=item->firstChild(); child; child=child->nextSibling()) {
+ url=static_cast<KFileTreeViewItem*>(child)->url();
+ if (url.isParentOf(m_nextUrlToSelect)) {
+ LOG("Opening child with URL=" << url);
+ ensureItemVisible(child);
+ child->setOpen(true);
+ return;
+ }
+ }
+}
+
+
+void TreeView::createBranch(const KURL& url) {
+ if (d->mBranch) {
+ removeBranch(d->mBranch);
+ }
+ QString title=url.prettyURL(0, KURL::StripFileProtocol);
+ d->mBranch=addBranch(url, title, SmallIcon(KMimeType::iconForURL(url)) );
+ setDirOnlyMode(d->mBranch, true);
+ d->mBranch->setChildRecurse(false);
+ d->mBranch->root()->setOpen(true);
+
+ connect(d->mBranch, SIGNAL(populateFinished(KFileTreeViewItem*) ),
+ this, SLOT(slotTreeViewPopulateFinished(KFileTreeViewItem*)) );
+}
+
+
+
+/**
+ * Override this method to make sure that the item is selected, opened and
+ * visible
+ */
+void TreeView::slotNewTreeViewItems(KFileTreeBranch* branch, const KFileTreeViewItemList& itemList) {
+ if( ! branch ) return;
+ LOG("");
+ if(m_nextUrlToSelect.isEmpty()) return;
+
+ KFileTreeViewItemListIterator it( itemList );
+
+ for(;it.current(); ++it ) {
+ KURL url = (*it)->url();
+
+ // This is an URL to select
+ // (We block signals to avoid simulating a click on the dir item)
+ if (m_nextUrlToSelect.equals(url,true)) {
+ blockSignals(true);
+ setCurrentItem(*it);
+ blockSignals(false);
+
+ ensureItemVisible(*it);
+ (*it)->setOpen(true);
+ m_nextUrlToSelect = KURL();
+ return;
+ }
+ }
+}
+
+
+/**
+ * Override showEvent to make sure the view shows the correct
+ * dir when it's shown. Since the view doesn't update if it's
+ * hidden
+ */
+void TreeView::showEvent(QShowEvent* event) {
+ LOG("m_nextUrlToSelect=" << m_nextUrlToSelect.pathOrURL());
+ if (m_nextUrlToSelect.isValid() && !currentURL().equals(m_nextUrlToSelect,true)) {
+ d->setURLInternal(m_nextUrlToSelect);
+ }
+ QWidget::showEvent(event);
+}
+
+
+void TreeView::contentsDragMoveEvent(QDragMoveEvent* event) {
+ if (!KURLDrag::canDecode(event)) {
+ event->ignore();
+ return;
+ }
+
+ // Get a pointer to the new drop item
+ QPoint point(0,event->pos().y());
+ KFileTreeViewItem* newDropTarget=static_cast<KFileTreeViewItem*>( itemAt(contentsToViewport(point)) );
+ if (!newDropTarget) {
+ event->ignore();
+ d->mAutoOpenTimer->stop();
+ if (d->mDropTarget) {
+ stopAnimation(d->mDropTarget);
+ d->mDropTarget=0L;
+ }
+ return;
+ }
+
+ event->accept();
+ if (newDropTarget==d->mDropTarget) return;
+ if (d->mDropTarget) {
+ stopAnimation(d->mDropTarget);
+ }
+
+ // Restart auto open timer if we are over a new item
+ d->mAutoOpenTimer->stop();
+ d->mDropTarget=newDropTarget;
+ startAnimation(newDropTarget,DND_PREFIX,DND_ICON_COUNT);
+ d->mAutoOpenTimer->start(AUTO_OPEN_DELAY,true);
+}
+
+
+void TreeView::contentsDragLeaveEvent(QDragLeaveEvent*) {
+ d->mAutoOpenTimer->stop();
+ if (d->mDropTarget) {
+ stopAnimation(d->mDropTarget);
+ d->mDropTarget=0L;
+ }
+}
+
+
+void TreeView::contentsDropEvent(QDropEvent* event) {
+ d->mAutoOpenTimer->stop();
+
+ // Get data from drop (do it before showing menu to avoid mDropTarget changes)
+ if (!d->mDropTarget) return;
+ KURL dest=d->mDropTarget->url();
+
+ KURL::List urls;
+ if (!KURLDrag::decode(event,urls)) return;
+
+ // Show popup
+ bool wasMoved;
+ FileOperation::openDropURLMenu(this, urls, dest, &wasMoved);
+
+ if (wasMoved) {
+ // If the current url was in the list, set the drop target as the new
+ // current item
+ KURL current=currentURL();
+ KURL::List::ConstIterator it=urls.begin();
+ for (; it!=urls.end(); ++it) {
+ if (current.equals(*it,true)) {
+ setCurrentItem(d->mDropTarget);
+ break;
+ }
+ }
+ }
+
+ // Reset drop target
+ if (d->mDropTarget) {
+ stopAnimation(d->mDropTarget);
+ d->mDropTarget=0L;
+ }
+}
+
+
+void TreeView::autoOpenDropTarget() {
+ if (d->mDropTarget) {
+ d->mDropTarget->setOpen(true);
+ }
+}
+} // namespace