diff options
Diffstat (limited to 'src/sidebar/sq_categorybrowsermenu.cpp')
-rw-r--r-- | src/sidebar/sq_categorybrowsermenu.cpp | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/src/sidebar/sq_categorybrowsermenu.cpp b/src/sidebar/sq_categorybrowsermenu.cpp new file mode 100644 index 0000000..d071eb3 --- /dev/null +++ b/src/sidebar/sq_categorybrowsermenu.cpp @@ -0,0 +1,521 @@ +/* + * Copyright (C) 2006 Baryshev Dmitry, KSquirrel project + * + * Originally based on browser_mnu.cpp by (C) Matthias Elter + * from kde-3.2.3 + */ + +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <tqpixmap.h> +#include <tqdir.h> + +#include <tdeglobal.h> +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeapplication.h> +#include <kprocess.h> +#include <kiconloader.h> +#include <ksimpleconfig.h> +#include <kdesktopfile.h> +#include <kmimetype.h> +#include <tdeglobalsettings.h> +#include <tdeio/global.h> +#include <krun.h> +#include <konq_operations.h> +#include <tdefileitem.h> +#include <kdirwatch.h> +#include <kstringhandler.h> +#include <kurldrag.h> + +#include "sq_dir.h" +#include "sq_categoriesview.h" +#include "sq_categorybrowsermenu.h" + +#define CICON(a) (*_icons)[a] + +TQMap<TQString, TQPixmap> *SQ_CategoryBrowserMenu::_icons = 0; + +SQ_CategoryBrowserMenu::SQ_CategoryBrowserMenu(TQString path, TQWidget *parent, const char *name, int startid) + : KPanelMenu(path, parent, name) + , _mimecheckTimer(0) + , _startid(startid) + , _dirty(false) +{ + _subMenus.setAutoDelete(true); + _lastpress = TQPoint(-1, -1); + setAcceptDrops(true); // Should depend on permissions of path. + + // we are not interested for dirty events on files inside the + // directory (see slotClearIfNeeded) + connect( &_dirWatch, TQ_SIGNAL(dirty(const TQString&)), + this, TQ_SLOT(slotClearIfNeeded(const TQString&)) ); + connect( &_dirWatch, TQ_SIGNAL(created(const TQString&)), + this, TQ_SLOT(slotClear()) ); + connect( &_dirWatch, TQ_SIGNAL(deleted(const TQString&)), + this, TQ_SLOT(slotClear()) ); +} + +SQ_CategoryBrowserMenu::~SQ_CategoryBrowserMenu() +{} + +void SQ_CategoryBrowserMenu::slotClearIfNeeded(const TQString& p) +{ + if (p == path()) + slotClear(); +} + + +void SQ_CategoryBrowserMenu::initialize() +{ + _lastpress = TQPoint(-1, -1); + + // don't change menu if already visible + if (isVisible()) + return; + + if (_dirty) { + // directory content changed while menu was visible + slotClear(); + setInitialized(false); + _dirty = false; + } + + if (initialized()) return; + setInitialized(true); + + // start watching if not already done + if (!_dirWatch.contains(path())) + _dirWatch.addDir( path() ); + + // setup icon map + initIconMap(); + + // read configuration + TDEConfig *c = TDEGlobal::config(); + c->setGroup("menus"); + _showhidden = c->readBoolEntry("ShowHiddenFiles", false); + _maxentries = c->readNumEntry("MaxEntries2", 30); + + // clear maps + _filemap.clear(); + _mimemap.clear(); + + int filter = TQDir::Dirs | TQDir::Files; + if(_showhidden) + filter |= TQDir::Hidden; + + TQDir dir(path(), TQString(), TQDir::DirsFirst | TQDir::Name | TQDir::IgnoreCase, filter); + + // does the directory exist? + if (!dir.exists()) { + insertItem(i18n("Failed to Read Folder")); + return; + } + + // get entry list + const TQFileInfoList *list = dir.entryInfoList(); + + // no list -> read error + if (!list) { + insertItem(i18n("Failed to Read Folder")); + return; + } + + KURL url; + url.setPath(path()); + if (!kapp->authorizeURLAction("list", KURL(), url)) + { + insertItem(i18n("Not Authorized to Read Folder")); + return; + } + + // insert file manager and terminal entries + // only the first part menu got them + if(_startid == 0) + { + SQ_Dir dir(SQ_Dir::Categories); + + if(dir.root() != path()) + { + insertTitle(path().right(path().length() - dir.root().length())); + insertItem(CICON("bookmark_add"), i18n("Add here"), this, TQ_SLOT(slotAddToCategory())); + } + } + + bool first_entry = true; + bool dirfile_separator = false; + int item_count = 0; + int run_id = _startid; + + // get list iterator + TQFileInfoListIterator it(*list); + + // jump to startid + it += _startid; + + // iterate over entry list + for (; it.current(); ++it) + { + // bump id + run_id++; + + TQFileInfo *fi = it.current(); + // handle directories + if (fi->isDir()) + { + TQString name = fi->fileName(); + + // ignore . and .. entries + if (name == "." || name == "..") continue; + + TQPixmap icon; + TQString path = fi->absFilePath(); + + // parse .directory if it does exist + if (TQFile::exists(path + "/.directory")) { + + KSimpleConfig c(path + "/.directory", true); + c.setDesktopGroup(); + icon = TDEGlobal::iconLoader()->loadIcon(c.readEntry("Icon"), + TDEIcon::Small, TDEIcon::SizeSmall, + TDEIcon::DefaultState, 0, true); + if(icon.isNull()) + icon = CICON("folder"); + name = c.readEntry("Name", name); + } + + // use cached folder icon for directories without special icon + if (icon.isNull()) + icon = CICON("folder"); + + // insert separator if we are the first menu entry + if(first_entry) { + if (_startid == 0) + insertSeparator(); + first_entry = false; + } + + // append menu entry + append(icon, KStringHandler::cEmSqueeze( name, fontMetrics(), 20 ), + new SQ_CategoryBrowserMenu(path, this)); + + // bump item count + item_count++; + + dirfile_separator = true; + } +/* + // handle files + else if(fi->isFile()) + { + TQString name = fi->fileName(); + TQString title = TDEIO::decodeFileName(name); + + // ignore .directory and .order files + if (name == ".directory" || name == ".order") continue; + + TQPixmap icon; + TQString path = fi->absFilePath(); + + bool mimecheck = false; + + // .desktop files + if(KDesktopFile::isDesktopFile(path)) + { + KSimpleConfig c(path, true); + c.setDesktopGroup(); + title = c.readEntry("Name", title); + + TQString s = c.readEntry("Icon"); + if(!_icons->contains(s)) { + icon = TDEGlobal::iconLoader()->loadIcon(s, TDEIcon::Small, TDEIcon::SizeSmall, + TDEIcon::DefaultState, 0, true); + + if(icon.isNull()) { + TQString type = c.readEntry("Type", "Application"); + if (type == "Directory") + icon = CICON("folder"); + else if (type == "Mimetype") + icon = CICON("txt"); + else if (type == "FSDevice") + icon = CICON("chardevice"); + else + icon = CICON("exec"); + } + else + _icons->insert(s, icon); + } + else + icon = CICON(s); + } + else { + // set unknown icon + icon = CICON("unknown"); + + // mark for delayed mimetime check + mimecheck = true; + } + + // insert separator if we are the first menu entry + if(first_entry) { + if(_startid == 0) + insertSeparator(); + first_entry = false; + } + + // insert separator if we we first file after at least one directory + if (dirfile_separator) { + insertSeparator(); + dirfile_separator = false; + } + + // append file entry + append(icon, title, name, mimecheck); + + // bump item count + item_count++; + } +*/ + if(item_count == _maxentries) { + // Only insert a "More..." item if there are actually more items. + ++it; + if( it.current() ) { + insertSeparator(); + append(CICON("folder_open"), i18n("More..."), new SQ_CategoryBrowserMenu(path(), this, 0, run_id)); + } + break; + } + } + +#if 0 + // WABA: tear off handles don't work together with dynamically updated + // menus. We can't update the menu while torn off, and we don't know + // when it is torn off. + if(TDEGlobalSettings::insertTearOffHandle() && item_count > 0) + insertTearOffHandle(); +#endif + + adjustSize(); + + TQString dirname = path(); + + int maxlen = contentsRect().width() - 40; + if(item_count == 0) + maxlen = fontMetrics().width(dirname); + + if (fontMetrics().width(dirname) > maxlen) { + while ((!dirname.isEmpty()) && (fontMetrics().width(dirname) > (maxlen - fontMetrics().width("...")))) + dirname = dirname.remove(0, 1); + dirname.prepend("..."); + } + setCaption(dirname); + + // setup and start delayed mimetype check timer + if(_mimemap.count() > 0) { + + if(!_mimecheckTimer) + _mimecheckTimer = new TQTimer(this); + + connect(_mimecheckTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotMimeCheck())); + _mimecheckTimer->start(0); + } +} + +void SQ_CategoryBrowserMenu::append(const TQPixmap &pixmap, const TQString &title, const TQString &file, bool mimecheck) +{ + // avoid &'s being converted to accelerators + TQString newTitle = title; + newTitle.replace("&", "&&"); + newTitle = KStringHandler::cEmSqueeze( newTitle, fontMetrics(), 20 ); + + // insert menu item + int id = insertItem(pixmap, newTitle); + + // insert into file map + _filemap.insert(id, file); + + // insert into mimetype check map + if(mimecheck) + _mimemap.insert(id, true); +} + +void SQ_CategoryBrowserMenu::append(const TQPixmap &pixmap, const TQString &title, SQ_CategoryBrowserMenu *subMenu) +{ + // avoid &'s being converted to accelerators + TQString newTitle = title; + newTitle.replace("&", "&&"); + newTitle = KStringHandler::cEmSqueeze( newTitle, fontMetrics(), 20 ); + + // insert submenu + insertItem(pixmap, newTitle, subMenu); + // remember submenu for later deletion + _subMenus.append(subMenu); +} + +void SQ_CategoryBrowserMenu::mousePressEvent(TQMouseEvent *e) +{ + TQPopupMenu::mousePressEvent(e); + _lastpress = e->pos(); +} + +void SQ_CategoryBrowserMenu::mouseMoveEvent(TQMouseEvent *e) +{ + TQPopupMenu::mouseMoveEvent(e); + + if (!(e->state() & TQt::LeftButton)) return; + if(_lastpress == TQPoint(-1, -1)) return; + + // DND delay + if((_lastpress - e->pos()).manhattanLength() < 12) return; + + // get id + int id = idAt(_lastpress); + if(!_filemap.contains(id)) return; + + // reset _lastpress + _lastpress = TQPoint(-1, -1); + + // start drag + KURL url; + url.setPath(path() + '/' + _filemap[id]); + KURL::List files(url); + KURLDrag *d = new KURLDrag(files, this); + d->setPixmap(iconSet(id)->pixmap()); + d->drag(); +} + +void SQ_CategoryBrowserMenu::dragEnterEvent( TQDragEnterEvent *ev ) +{ + if (KURLDrag::canDecode(ev)) + ev->accept(rect()); + KPanelMenu::dragEnterEvent(ev); +} + +void SQ_CategoryBrowserMenu::dropEvent( TQDropEvent *ev ) +{ + KFileItem item( path(), TQString::fromLatin1( "inode/directory" ), KFileItem::Unknown ); + KonqOperations::doDrop( &item, path(), ev, this ); + KPanelMenu::dropEvent(ev); + // ### TODO: Update list +} + +void SQ_CategoryBrowserMenu::slotExec(int id) +{ + kapp->propagateSessionManager(); + + if(!_filemap.contains(id)) return; + + KURL url; + url.setPath(path() + '/' + _filemap[id]); + new KRun(url, 0, true); // will delete itself + _lastpress = TQPoint(-1, -1); +} + +void SQ_CategoryBrowserMenu::slotAddToCategory() +{ + SQ_CategoriesBox::instance()->addToCategory(path()); +} + +void SQ_CategoryBrowserMenu::slotMimeCheck() +{ + // get the first map entry + TQMap<int, bool>::Iterator it = _mimemap.begin(); + + // no mime types left to check -> stop timer + if(it == _mimemap.end()) { + _mimecheckTimer->stop(); + return; + } + + int id = it.key(); + TQString file = _filemap[id]; + + _mimemap.remove(it); + + KURL url; + url.setPath( path() + '/' + file ); + +// KMimeType::Ptr mt = KMimeType::findByURL(url, 0, true, false); +// TQString icon(mt->icon(url, true)); + TQString icon = KMimeType::iconForURL( url ); +// kdDebug() << url.url() << ": " << icon << endl; + + file = KStringHandler::cEmSqueeze( file, fontMetrics(), 20 ); + + file.replace("&", "&&"); + if(!_icons->contains(icon)) { + TQPixmap pm = SmallIcon(icon); + if( pm.height() > 16 ) + { + TQPixmap cropped( 16, 16 ); + copyBlt( &cropped, 0, 0, &pm, 0, 0, 16, 16 ); + pm = cropped; + } + _icons->insert(icon, pm); + changeItem(id, pm, file); + } + else + changeItem(id, CICON(icon), file); +} + +void SQ_CategoryBrowserMenu::slotClear() +{ + // no need to watch any further + if (_dirWatch.contains(path())) + _dirWatch.removeDir( path() ); + + // don't change menu if already visible + if (isVisible()) { + _dirty = true; + return; + } + KPanelMenu::slotClear(); + _subMenus.clear(); // deletes submenus +} + +void SQ_CategoryBrowserMenu::initIconMap() +{ + if(_icons) return; + +// kdDebug() << "SQ_CategoryBrowserMenu::initIconMap" << endl; + + _icons = new TQMap<TQString, TQPixmap>; + + _icons->insert("folder", SmallIcon("folder")); + _icons->insert("unknown", SmallIcon("unknown")); + _icons->insert("folder_open", SmallIcon("folder_open")); + _icons->insert("kdisknav", SmallIcon("kdisknav")); + _icons->insert("kfm", SmallIcon("kfm")); + _icons->insert("terminal", SmallIcon("terminal")); + _icons->insert("txt", SmallIcon("text-plain")); + _icons->insert("exec", SmallIcon("application-x-executable")); + _icons->insert("chardevice", SmallIcon("chardevice")); +} + +#include "sq_categorybrowsermenu.moc" |