diff options
Diffstat (limited to 'src/sidebar/sq_treeview.cpp')
-rw-r--r-- | src/sidebar/sq_treeview.cpp | 678 |
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 + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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" |