You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
522 lines
15 KiB
522 lines
15 KiB
/*
|
|
* 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, TQT_SIGNAL(dirty(const TQString&)),
|
|
this, TQT_SLOT(slotClearIfNeeded(const TQString&)) );
|
|
connect( &_dirWatch, TQT_SIGNAL(created(const TQString&)),
|
|
this, TQT_SLOT(slotClear()) );
|
|
connect( &_dirWatch, TQT_SIGNAL(deleted(const TQString&)),
|
|
this, TQT_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, TQT_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, TQT_SIGNAL(timeout()), TQT_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"
|