summaryrefslogtreecommitdiffstats
path: root/src/sidebar/sq_treeview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sidebar/sq_treeview.cpp')
-rw-r--r--src/sidebar/sq_treeview.cpp678
1 files changed, 678 insertions, 0 deletions
diff --git a/src/sidebar/sq_treeview.cpp b/src/sidebar/sq_treeview.cpp
new file mode 100644
index 0000000..22207a9
--- /dev/null
+++ b/src/sidebar/sq_treeview.cpp
@@ -0,0 +1,678 @@
+/***************************************************************************
+ sq_treeview.cpp - description
+ -------------------
+ begin : Mon Mar 15 2004
+ copyright : (C) 2004 by Baryshev Dmitry
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tqdir.h>
+#include <tqheader.h>
+#include <tqtimer.h>
+#include <tqcursor.h>
+
+#include <tdelocale.h>
+#include <kurldrag.h>
+#include <kurl.h>
+#include <kdirwatch.h>
+
+#include "ksquirrel.h"
+#include "sq_iconloader.h"
+#include "sq_widgetstack.h"
+#include "sq_filethumbview.h"
+#include "sq_config.h"
+#include "sq_treeview.h"
+#include "sq_treeviewitem.h"
+#include "sq_threaddirlister.h"
+#include "sq_navigatordropmenu.h"
+#include "sq_treeviewmenu.h"
+#include "sq_hloptions.h"
+
+#include "sq_directorybasket.h"
+
+SQ_TreeView * SQ_TreeView::m_instance = 0;
+
+SQ_FileTreeViewBranch::SQ_FileTreeViewBranch(KFileTreeView *parent, const KURL &url,
+ const TQString &name, const TQPixmap &pix) : KFileTreeBranch(parent, url, name, pix)
+{}
+
+SQ_FileTreeViewBranch::~SQ_FileTreeViewBranch()
+{}
+
+KFileTreeViewItem* SQ_FileTreeViewBranch::createTreeViewItem(KFileTreeViewItem *parent, KFileItem *fileItem)
+{
+ KFileTreeViewItem *tvi = 0;
+
+ if(parent && fileItem)
+ tvi = new SQ_TreeViewItem(parent, fileItem, this);
+
+ return tvi;
+}
+
+/******************************************************************************************************/
+
+SQ_TreeView::SQ_TreeView(TQWidget *parent, const char *name) : KFileTreeView(parent, name)
+{
+ m_instance = this;
+
+ itemToBeOpened = 0;
+ m_animTimer = new TQTimer(this);
+ scanTimer = new TQTimer(this);
+ m_ignoreClick = false;
+
+ connect(m_animTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotAnimation()));
+ connect(scanTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotDelayedScan()));
+
+ dw = 0;
+ m_recurs = No;
+ lister = new SQ_ThreadDirLister(this);
+ setupRecursion();
+
+ setFrameShape(TQFrame::NoFrame);
+ addColumn("Name");
+ addColumn("Check");
+
+ header()->hide();
+ header()->moveSection(1, 0);
+ setColumnWidthMode(1, TQListView::Manual);
+ setColumnWidth(1, 18);
+
+ root = new SQ_FileTreeViewBranch(this, TQDir::rootDirPath(), TQString(),
+ SQ_IconLoader::instance()->loadIcon("folder_red", TDEIcon::Desktop, TDEIcon::SizeSmall));
+
+ // some hacks to create our SQ_TreeViewItem as root item
+ SQ_TreeViewItem *ritem = new SQ_TreeViewItem(this,
+ new KFileItem(TQDir::rootDirPath(),
+ "inode/directory", S_IFDIR),
+ root);
+
+ ritem->setText(0, i18n("root"));
+ ritem->setExpandable(true);
+
+ // oops :)
+ delete root->root();
+
+ // set new root
+ root->setRoot(ritem);
+
+ addBranch(root);
+
+ // don't show files
+ setDirOnlyMode(root, true);
+
+ // show '+'
+ setRootIsDecorated(true);
+
+ // connect signals
+
+ // Space and Return will open item
+ connect(this, TQ_SIGNAL(spacePressed(TQListViewItem*)), this, TQ_SIGNAL(executed(TQListViewItem*)));
+ connect(this, TQ_SIGNAL(returnPressed(TQListViewItem*)), this, TQ_SIGNAL(executed(TQListViewItem*)));
+ connect(this, TQ_SIGNAL(currentChanged(TQListViewItem *)), this, TQ_SLOT(slotCurrentChanged(TQListViewItem*)));
+
+ connect(this, TQ_SIGNAL(executed(TQListViewItem*)), this, TQ_SLOT(slotItemExecuted(TQListViewItem*)));
+ connect(this, TQ_SIGNAL(newURL(const KURL&)), this, TQ_SLOT(slotNewURL(const KURL&)));
+ connect(root, TQ_SIGNAL(populateFinished(KFileTreeViewItem *)), this, TQ_SLOT(slotOpened(KFileTreeViewItem *)));
+ connect(root, TQ_SIGNAL(deleteItem(KFileItem *)), this, TQ_SLOT(slotDeleteItemMy(KFileItem *)));
+
+ setCurrentItem(root->root());
+ root->setChildRecurse(false);
+
+ SQ_Config::instance()->setGroup("Fileview");
+ int sync_type = SQ_Config::instance()->readNumEntry("sync type", 0);
+
+ // load url, if needed
+ if(sync_type != 1)
+ emitNewURL(SQ_WidgetStack::instance()->url());
+
+ setAcceptDrops(true);
+
+ connect(this, TQ_SIGNAL(dropped(TQDropEvent *, TQListViewItem *, TQListViewItem *)),
+ this, TQ_SLOT(slotDropped(TQDropEvent *, TQListViewItem *, TQListViewItem *)));
+
+ connect(this, TQ_SIGNAL(contextMenu(TDEListView *, TQListViewItem *, const TQPoint &)),
+ this, TQ_SLOT(slotContextMenu(TDEListView *, TQListViewItem *, const TQPoint &)));
+
+ menu = new SQ_TreeViewMenu(this);
+
+ if(SQ_HLOptions::instance()->have_directorybasket)
+ {
+ menu->insertSeparator();
+ menu->insertItem(i18n("Add to Folder Basket"), this, TQ_SLOT(slotAddToFolderBasket()));
+ }
+}
+
+SQ_TreeView::~SQ_TreeView()
+{
+ lister->terminate();
+ lister->wait();
+
+ delete lister;
+}
+
+void SQ_TreeView::slotCurrentChanged(TQListViewItem *item)
+{
+ SQ_TreeViewItem *tvi = static_cast<SQ_TreeViewItem *>(item);
+
+ if(tvi) cURL = tvi->url();
+}
+
+void SQ_TreeView::setRecursion(int b)
+{
+ // avoid duplicate calls
+ if(m_recurs == b)
+ return;
+
+ TQListViewItemIterator it(this);
+ SQ_TreeViewItem *tvi;
+
+ // ignore root item
+ ++it;
+
+ // turn recursion on
+ if(m_recurs == No && b)
+ {
+ dw = new KDirWatch(this);
+ connect(dw, TQ_SIGNAL(dirty(const TQString &)), this, TQ_SLOT(slotDirty(const TQString &)));
+
+ dw->blockSignals(true);
+ lister->lock();
+ while(it.current())
+ {
+ tvi = static_cast<SQ_TreeViewItem *>(it.current());
+
+ if(tvi)
+ {
+ tvi->setParams((m_recurs == Files || m_recurs == FilesDirs),
+ (m_recurs == Dirs || m_recurs == FilesDirs));
+
+ lister->appendURL(tvi->url());
+ dw->addDir(tvi->path());
+ }
+
+ ++it;
+ }
+ lister->unlock();
+ dw->blockSignals(false);
+
+ m_recurs = b;
+
+ if(!lister->running())
+ scanTimer->start(1, true);
+ }
+ // turn recursion off
+ else
+ {
+ delete dw;
+ dw = 0;
+
+ m_recurs = b;
+ while(it.current())
+ {
+ tvi = static_cast<SQ_TreeViewItem *>(it.current());
+
+ // reset item names
+ if(tvi)
+ {
+ tvi->setParams((m_recurs == Files || m_recurs == FilesDirs),
+ (m_recurs == Dirs || m_recurs == FilesDirs));
+ tvi->setCount(tvi->files(), tvi->dirs());
+ }
+
+ ++it;
+ }
+ }
+}
+
+void SQ_TreeView::slotClearChecked()
+{
+ TQListViewItemIterator it(this);
+ SQ_TreeViewItem *tvi;
+
+ while(it.current())
+ {
+ tvi = static_cast<SQ_TreeViewItem *>(it.current());
+
+ if(tvi && tvi->checked())
+ tvi->setChecked(false);
+
+ ++it;
+ }
+}
+
+/*
+ * Item executed. Let's pass its url to SQ_WidgetStack (if needed).
+ */
+void SQ_TreeView::slotItemExecuted(TQListViewItem *item)
+{
+ if(!item) return;
+
+ item->setOpen(true);
+
+ SQ_Config::instance()->setGroup("Fileview");
+ int sync_type = SQ_Config::instance()->readNumEntry("sync type", 0);
+
+ // current sychronization type doesn't require
+ // passing url to SQ_WidgetStack - return
+ if(sync_type == 1)
+ return;
+
+ KFileTreeViewItem *cur = static_cast<KFileTreeViewItem*>(item);
+ KURL Curl = cur->url();
+
+ // pass url to SQ_WidgetStack
+ SQ_WidgetStack::instance()->setURLForCurrent(Curl, false);
+}
+
+void SQ_TreeView::emitNewURL(const KURL &url)
+{
+ // already selected?
+ if(!url.isLocalFile() || url.equals(currentURL(), true) || url.equals(cURL, true))
+ return;
+
+ cURL = url;
+
+ // tree is invisible.
+ // save url for future use
+ if(!isVisible())
+ {
+ pendingURL = url;
+ pendingURL.adjustPath(1);
+ return;
+ }
+ else
+ pendingURL = KURL();
+
+ emit newURL(url);
+}
+
+/*
+ * Set given item visible, current, and populate it.
+ */
+void SQ_TreeView::populateItem(KFileTreeViewItem *item)
+{
+ if(item->url().equals(cURL, true))
+ {
+ setSelected(item, true);
+ setCurrentItem(item);
+
+ // 1/5 of height give above items
+ // 4/5 of height give below items
+ setContentsPos(contentsX(), itemPos(item)-visibleHeight()/5);
+ }
+
+ itemToBeOpened = item;
+ item->setOpen(true);
+}
+
+/*
+ * Load url.
+ */
+void SQ_TreeView::slotNewURL(const KURL &url)
+{
+ KURL k(url);
+ k.adjustPath(1);
+
+ KURL last = k;
+
+ TQString s;
+
+ // divide url to paths.
+ // for example, "/home/krasu/1/2" will be divided to
+ //
+ // "/home/krasu/1/2"
+ // "/home/krasu/1"
+ // "/home/krasu"
+ // "/home"
+ // "/"
+ //
+ while(true)
+ {
+ s = k.path(); // remove "/"
+ s.remove(0, 1);
+
+ paths.prepend(s);
+ k = k.upURL();
+
+ if(k.equals(last, true))
+ break;
+
+ last = k;
+ }
+
+ while(doSearch())
+ {}
+}
+
+/*
+ * New item is opened. Try to continue loading url.
+ */
+void SQ_TreeView::slotOpened(KFileTreeViewItem *item)
+{
+ if(!item) return;
+
+ // continue searhing...
+ if(item == itemToBeOpened)
+ doSearch();
+}
+
+/*
+ * Search first available url in variable 'paths'. Open found item.
+ * If item was found return true.
+ */
+bool SQ_TreeView::doSearch()
+{
+ // all items are opened
+ if(paths.empty())
+ {
+ itemToBeOpened = 0;
+ return false;
+ }
+
+ TQStringList::iterator it = paths.begin();
+
+ KFileTreeViewItem *found = findItem(root, *it);
+
+ // item not found. It means that
+ //
+ // * we loaded all subpaths - nothing to do
+ // * item we needed is not loaded yet. populateItem() _now_ is trying to open
+ // new subpath, and we will continue searching in slotOpened().
+ //
+ if(!found)
+ return false;
+
+ // ok, item is found
+ //
+ // remove first entry from 'paths'
+ // and try to open item
+ paths.erase(it);
+ populateItem(found);
+
+ // done, but subpaths are pending...
+ return true;
+}
+
+/*
+ * On show event load saved url, if any. See emitNewURL().
+ */
+void SQ_TreeView::showEvent(TQShowEvent *)
+{
+ // if pending url is valid
+ if(!pendingURL.isEmpty())
+ {
+ // set pending url to current url
+ KURL url = pendingURL;
+
+ // reset pending url
+ pendingURL = KURL();
+
+ // finally, load url
+ emit newURL(url);
+ }
+}
+
+void SQ_TreeView::slotNewTreeViewItems(KFileTreeBranch *, const KFileTreeViewItemList &list)
+{
+ if(m_recurs == No)
+ return;
+
+// uuuuuuuggggggghhhhhhh :)
+ KFileTreeViewItemListIterator it(list);
+ KFileTreeViewItem *item;
+
+ lister->lock();
+ while((item = it.current()))
+ {
+ lister->appendURL(item->url());
+ dw->addDir(item->path());
+ ++it;
+ }
+ lister->unlock();
+
+ if(!lister->running())
+ scanTimer->start(1, true);
+}
+
+void SQ_TreeView::slotDelayedScan()
+{
+ if(!lister->running())
+ lister->start();
+}
+
+void SQ_TreeView::customEvent(TQCustomEvent *e)
+{
+ if(!e || e->type() != SQ_ItemsEventId)
+ return;
+
+ SQ_ItemsEvent *ie = static_cast<SQ_ItemsEvent *>(e);
+
+ SQ_TreeViewItem *tvi = static_cast<SQ_TreeViewItem *>(root->findTVIByURL(ie->url()));
+
+ if(tvi)
+ {
+ tvi->setParams((m_recurs == Files || m_recurs == FilesDirs),
+ (m_recurs == Dirs || m_recurs == FilesDirs));
+ tvi->setCount(ie->files(), ie->dirs());
+ }
+}
+
+void SQ_TreeView::slotAnimation()
+{
+ KFileTreeViewItem *it = m_mapFolders.first();
+
+ for(;it;it = m_mapFolders.next())
+ it->setPixmap(0, SmallIcon("clock"));
+}
+
+void SQ_TreeView::startAnimation(KFileTreeViewItem *item, const char *, uint)
+{
+ if(!item)
+ return;
+
+ m_mapFolders.append(item);
+
+ if(!m_animTimer->isActive())
+ m_animTimer->start(50, true);
+}
+
+void SQ_TreeView::stopAnimation(KFileTreeViewItem *item)
+{
+ if(!item)
+ return;
+
+ int f = m_mapFolders.find(item);
+
+ if(f != -1)
+ {
+ item->setPixmap(0, itemIcon(item));
+ m_mapFolders.remove(item);
+ }
+
+ m_animTimer->stop();
+}
+
+void SQ_TreeView::viewportResizeEvent(TQResizeEvent *)
+{
+ setColumnWidth(0, viewport()->width() - columnWidth(1));
+ triggerUpdate();
+}
+
+void SQ_TreeView::clearSelection()
+{
+ if(!m_ignoreClick) KFileTreeView::clearSelection();
+}
+
+void SQ_TreeView::setSelected(TQListViewItem *item, bool selected)
+{
+ if(!m_ignoreClick) KFileTreeView::setSelected(item, selected);
+}
+
+void SQ_TreeView::setCurrentItem(TQListViewItem *item)
+{
+ if(!m_ignoreClick) KFileTreeView::setCurrentItem(item);
+}
+
+void SQ_TreeView::setOpen(TQListViewItem *item, bool open)
+{
+ if(!m_ignoreClick) KFileTreeView::setOpen(item, open);
+}
+
+void SQ_TreeView::contentsMousePressEvent(TQMouseEvent *e)
+{
+ TQListViewItem *item;
+
+ TQPoint point = e->pos();
+ point.setY(point.y() - contentsY());
+
+ if(header()->sectionAt(point.x()) && (item = itemAt(point)))
+ {
+ SQ_TreeViewItem *m = static_cast<SQ_TreeViewItem *>(item);
+
+ if(m)
+ {
+ int state = e->state();
+
+ if(!state)
+ toggle(m, true);
+ else
+ {
+ TQListViewItemIterator it(this);
+
+ // toggle parent item
+ if(state == TQt::ShiftButton) toggle(m, true);
+ else if(state == TQt::ControlButton) toggle(m, false, true);
+ else if(state == TQt::AltButton) toggle(m, false, false);
+
+ SQ_TreeViewItem *tvi = static_cast<SQ_TreeViewItem *>(m->firstChild());
+
+ // toggle all child items
+ while(tvi)
+ {
+ if(state == TQt::ShiftButton) toggle(tvi, false, m->checked());
+ else if(state == TQt::ControlButton) toggle(tvi, false, true);
+ else if(state == TQt::AltButton) toggle(tvi, false, false);
+
+ tvi = static_cast<SQ_TreeViewItem *>(tvi->nextSibling());
+ }
+ }
+ }
+
+ m_ignoreClick = true;
+ }
+
+ KFileTreeView::contentsMousePressEvent(e);
+
+ m_ignoreClick = false;
+}
+
+void SQ_TreeView::contentsMouseDoubleClickEvent(TQMouseEvent *e)
+{
+ if(header()->sectionAt(e->x()))
+ m_ignoreClick = true;
+
+ KFileTreeView::contentsMouseDoubleClickEvent(e);
+
+ m_ignoreClick = false;
+}
+
+void SQ_TreeView::setupRecursion()
+{
+ SQ_Config::instance()->setGroup("Sidebar");
+
+ setRecursion(SQ_Config::instance()->readNumEntry("recursion_type", No));
+}
+
+void SQ_TreeView::toggle(SQ_TreeViewItem *item, bool togg, bool set)
+{
+ if(togg)
+ item->setChecked(!item->checked());
+ else
+ item->setChecked(set);
+
+ if(item->checked())
+ emit urlAdded(item->url());
+ else
+ emit urlRemoved(item->url());
+}
+
+void SQ_TreeView::slotDropped(TQDropEvent *e, TQListViewItem *parent, TQListViewItem *item)
+{
+ if(!item) item = parent;
+
+ KFileTreeViewItem *cur = static_cast<KFileTreeViewItem *>(item);
+
+ if(!cur) return;
+
+ KURL::List list;
+ KURLDrag::decode(e, list);
+
+ SQ_NavigatorDropMenu::instance()->setupFiles(list, cur->url());
+ SQ_NavigatorDropMenu::instance()->exec(TQCursor::pos(), true);
+}
+
+void SQ_TreeView::slotContextMenu(TDEListView *, TQListViewItem *item, const TQPoint &point)
+{
+ if(item)
+ {
+ KFileTreeViewItem *kfi = static_cast<KFileTreeViewItem*>(item);
+ menu->updateDirActions(kfi->isDir());
+ menu->setURL(kfi->url());
+ menu->exec(point);
+ }
+}
+
+void SQ_TreeView::slotDirty(const TQString &path)
+{
+ KURL url;
+ url.setPath(path);
+
+ lister->lock();
+
+ // we don't need update urls that are not yet updated
+ // by threaded lister
+ if(!lister->hasURL(url))
+ lister->appendURL(url);
+ else if(lister->isCurrent(url))
+ {
+ lister->terminate();
+ lister->wait();
+ lister->closeDir();
+ }
+
+ lister->unlock();
+
+ if(!lister->running())
+ scanTimer->start(1000, true);
+}
+
+void SQ_TreeView::slotDeleteItemMy(KFileItem *fi)
+{
+ if(m_recurs != No && fi)
+ dw->removeDir(fi->url().path());
+}
+
+void SQ_TreeView::slotAddToFolderBasket()
+{
+ KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, menu->url());
+
+ KFileItemList list;
+ list.append(&fi);
+
+ SQ_DirectoryBasket::instance()->add(list);
+}
+
+#include "sq_treeview.moc"