summaryrefslogtreecommitdiffstats
path: root/src/sidebar/sq_categorybrowsermenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sidebar/sq_categorybrowsermenu.cpp')
-rw-r--r--src/sidebar/sq_categorybrowsermenu.cpp521
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"