diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 4aed2c8219774f5d797760606b8489a92ddc5163 (patch) | |
tree | 3f8c130f7d269626bf6a9447407ef6c35954426a /kicker/menuext/tom | |
download | tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kicker/menuext/tom')
-rw-r--r-- | kicker/menuext/tom/Makefile.am | 19 | ||||
-rw-r--r-- | kicker/menuext/tom/README | 65 | ||||
-rw-r--r-- | kicker/menuext/tom/TASKGROUPS | 49 | ||||
-rw-r--r-- | kicker/menuext/tom/destinations | 18 | ||||
-rw-r--r-- | kicker/menuext/tom/tom.cc | 855 | ||||
-rw-r--r-- | kicker/menuext/tom/tom.desktop | 75 | ||||
-rw-r--r-- | kicker/menuext/tom/tom.h | 110 |
7 files changed, 1191 insertions, 0 deletions
diff --git a/kicker/menuext/tom/Makefile.am b/kicker/menuext/tom/Makefile.am new file mode 100644 index 000000000..4947ef77b --- /dev/null +++ b/kicker/menuext/tom/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = -I$(srcdir)/../../libkicker -I$(srcdir)/../../ui -I$(srcdir)/../../core $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_tom.la + +kickermenu_tom_la_SOURCES = tom.cc +kickermenu_tom_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_tom_la_LIBADD = $(LIB_KDEUI) +#$(top_builddir)/kicker/ui/libkicker_ui.la + +kickermenu_tom_la_METASOURCES = AUTO + +desktopmenu_DATA = tom.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +tomdata_DATA = destinations +tomdatadir = $(kde_datadir)/kicker/tom + +messages: + $(XGETTEXT) *.cc -o $(podir)/libkickermenu_tom.pot diff --git a/kicker/menuext/tom/README b/kicker/menuext/tom/README new file mode 100644 index 000000000..2616c76c5 --- /dev/null +++ b/kicker/menuext/tom/README @@ -0,0 +1,65 @@ +What is TOM? +============ +TOM stands for Task Oriented Menu and is a work in progress that will become a +viable alternative to the current KMenu. Its goals include: + + o Be task oriented + o Be simple and clear to use + o Create a smaller but usable menu + o Limited configurability through sensible defaults + o Have all configuration needs built right into the menu, including: + o Editor dialogs that can be called up from entries in the menu + o Context menus accessed by RMB clicking on a task for powerusers + o Allow locking down of menus through immutable settings + o Obeys Kicker and KDE Kiosk settings + o By making the TOM group of kickerrc immutable all config is removed + o By making a task group's rc file immutable, config options are removed + o Not require any modifications to the KDE menu system (applnk, etc) + + +What is a "Task Oriented Menu"? +================================ +A task oriented menu displays it's entries as "things to do" (or tasks) rather +than simply listing all items that are available. Each of these tasks has an +application or command associated with it, and this associated command can be +changed without changing the task name or placement within the menu. The tasks +are grouped by function and may map to programs, documents or actions. + + +Todo list +========= +Editor dialogs +Make the Destination entries work (only Run A Command is done) +Populate and track Recent Applications menu entries + o Application launching should be caught somewhere in the KDE libs, ala + Recent Documents +Writing out of config files to reflect runtime changes (deleted entries, etc) + o This requires keeping track of the config files used in creating the menu +KDEDIR merging + o KDEDIRS are already consulted for taskgroups, but groups of the same name + should be merged +Sane merging of menuext entries + o "Recent" items should go into the recent section + o Replace TOM's builin recent docs with the menuext version? + o Create a Recent Applications menuext? + o Add a way to quickly add/remove menuext items from TOM + (ala "Modify These Tasks") +Check for updates on launch and bring them down/install them if they exist + o this includes new apps installed on the local box showing up in the menu + o "Get cool stuff" integration? +Further refinement of wording / ordering in main menu (a perpetual TODO ;) +Creation of real-world task groups +Support plugins which can add arbitrary functionality to the menu + + +Debate list +=========== +What should be the default task entry format be: + a) Task Name + b) Task Name (App Name) + c) App Name (Task Name) <-- silly option =) +Should "Run A Command..." be replaced by an inline combobox? + Pros: It's more obvious and will work even if kdesktop is gone. The widget + is already written (in tom.cc) + Cons: It makes it stand out too much over other entries, takes up more room + and isn't as powerful as the full minicli diff --git a/kicker/menuext/tom/TASKGROUPS b/kicker/menuext/tom/TASKGROUPS new file mode 100644 index 000000000..c1aa1ed98 --- /dev/null +++ b/kicker/menuext/tom/TASKGROUPS @@ -0,0 +1,49 @@ +Task Groups +=========== +Tasks are grouped into common families of functionality. These groups are then +stored in a standard KDE configuration file. The General category in the +config file defines the icon (Icon), user visible name (Name), the number +of tasks in the group (NumTasks) and optionally whether or not it is hidden +(Hidden). + +For each task there is a numbered section in the file in the form TaskN. Each +section contains the user visible name for the task (Name), the associated +.desktop file and optionally whether or not it is hidden (Hidden). + +An example file can be found below. + +Alternatives +============ +Alternative formats are possible, including making it more like the servicemenu +.desktop format or the new virtual menu freedesktop.org draft standard. Here are +the pros and cons of each of these options: + +servicemenu style: + o CONS: no extra flexibility, still have to do most checking manually + o PROS: familiar format + +virtual menu style: + o CONS: it's XML and that's way more trouble that we need to go through, and it + isn't really designed with this sort of menu in mind + o PROS: it's becoming a standard for desktop menus + + +Example +======= +[General] +Icon=konqueror +Name=Internet +NumTasks=3 +Hidden=true + +[Task0] +Name=Browse the web +DesktopFile=applications/konqbrowser.desktop + +[Task1] +Name=EMail +DesktopFile=Internet/KMail.desktop + +[Task2] +Name=VNC +DesktopFile=Internet/keystone.desktop diff --git a/kicker/menuext/tom/destinations b/kicker/menuext/tom/destinations new file mode 100644 index 000000000..6e075237f --- /dev/null +++ b/kicker/menuext/tom/destinations @@ -0,0 +1,18 @@ +[General] +NumTasks=4 + +[Task0] +Name=Consult Manuals +DesktopFile=Help.desktop + +[Task1] +Name=Find Files +DesktopFile=Kfind.desktop + +[Task2] +Name=Adjust Settings +DesktopFile=KControl.desktop + +[Task3] +Name=Browse My Files +DesktopFile=Home.desktop diff --git a/kicker/menuext/tom/tom.cc b/kicker/menuext/tom/tom.cc new file mode 100644 index 000000000..80ea3e71d --- /dev/null +++ b/kicker/menuext/tom/tom.cc @@ -0,0 +1,855 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Aaron J. Seigo <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <iostream> +using namespace std; + +#include <unistd.h> +#include <pwd.h> +#include <sys/types.h> + +#include <qdir.h> +#include <qimage.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qregexp.h> +#include <qsettings.h> +#include <qstyle.h> +#include <qfile.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kcombobox.h> +#include <kdialog.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kiconeffect.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kmimetype.h> +#include <kpixmap.h> +#include <krecentdocument.h> +#include <kservice.h> +#include <kservicegroup.h> +#include <kstandarddirs.h> +#include <kstdaction.h> +#include <ksycocaentry.h> + +#include "menuinfo.h" +#include "service_mnu.h" +#include "kicker.h" +#include "tom.h" + +const int configureMenuID = 1000; +const int contextMenuTitleID = 10000; +const int destMenuTitleID = 10001; + +extern "C" +{ + KDE_EXPORT void* init_kickermenu_tom() + { + KGlobal::locale()->insertCatalogue("libkickermenu_tom"); + return new TOMFactory; + } +}; + +TOMFactory::TOMFactory(QObject *parent, const char *name) +: KLibFactory(parent, name) +{ +} + +QObject* TOMFactory::createObject(QObject *parent, const char *name, const char*, const QStringList&) +{ + return new TOM((QWidget*)parent, name); +} + +#include <qmenudata.h> +/* + * TODO: switch the backgroundmode when translucency turns on/off + * TODO: catch font changes too? + */ +class runMenuWidget : public QWidget, public QMenuItem +{ + public: + runMenuWidget(KPopupMenu* parent, int index) + : QWidget (parent), + m_menu(parent), + m_index(index) + { + setFocusPolicy(StrongFocus); + + QHBoxLayout* runLayout = new QHBoxLayout(this); + textRect = fontMetrics().boundingRect(i18n("Run:")); + runLayout->setSpacing(KDialog::spacingHint()); + runLayout->addSpacing((KDialog::spacingHint() * 3) + KIcon::SizeMedium + textRect.width()); + icon = DesktopIcon("run", KIcon::SizeMedium); + /*QLabel* l1 = new QLabel(this); + QPixmap foo = DesktopIcon("run", KIcon::SizeMedium); + cout << "foo is: " << foo.width() << " by " << foo.height() << endl; + l1->setPixmap(foo); + runLayout->addWidget(l1);*/ + /*QLabel* l2 = new QLabel(i18n("&Run: "), this); + l2->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + l2->setBuddy(this); + runLayout->addWidget(l2);*/ + m_runEdit = new KHistoryCombo(this); + m_runEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + runLayout->addWidget(m_runEdit, 10); + runLayout->addSpacing(KDialog::spacingHint()); + + QSettings settings; + if (settings.readEntry("/KStyle/Settings/MenuTransparencyEngine", "Disabled") != "Disabled") + { + setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + //l1->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + //l2->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + m_runEdit->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + } + else + { + /*setBackgroundMode(Qt::NoBackground, Qt::NoBackground); + l1->setBackgroundMode(Qt::NoBackground, Qt::NoBackground); + l2->setBackgroundMode(Qt::NoBackground, Qt::NoBackground); + m_runEdit->setBackgroundMode(Qt::NoBackground, Qt::NoBackground);*/ + //l1->setAutoMask(true); + //l1->setBackgroundMode(Qt::NoBackground, Qt::NoBackground); + //l2->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + //m_runEdit->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + } + + setMinimumHeight(KIcon::SizeMedium + 2); + } + ~runMenuWidget() {} + + + void paintEvent(QPaintEvent * /*e*/) + { + QPainter p(this); + QRect r(rect()); + // ew, nasty hack. may result in coredumps due to horrid C-style cast??? + kapp->style().drawControl(QStyle::CE_PopupMenuItem, &p, m_menu, r, palette().active(), QStyle::Style_Enabled, + QStyleOption(static_cast<QMenuItem*>(this), 0, KIcon::SizeMedium )); + p.drawPixmap(KDialog::spacingHint(), 1, icon); + p.drawText((KDialog::spacingHint() * 2) + KIcon::SizeMedium, textRect.height() + ((height() - textRect.height()) / 2), i18n("Run:")); + } + + void focusInEvent (QFocusEvent* e) + { + if (!e || e->gotFocus()) + { + m_menu->setActiveItem(m_index); + m_runEdit->setFocus(); + } + } + + void enterEvent(QEvent*) + { + focusInEvent(0); + } + + private: + KPopupMenu* m_menu; + KHistoryCombo* m_runEdit; + QPixmap icon; + QRect textRect; + int m_index; +}; + +TOM::TOM(QWidget *parent, const char *name) + : KPanelMenu(parent, name), + m_maxIndex(0) +{ + disableAutoClear(); + m_submenus.setAutoDelete(true); + setCaption(i18n("Task-Oriented Menu")); + + // KMenu legacy: support some menu config options + KConfig* config = KGlobal::config(); + config->setGroup("menus"); + m_detailedTaskEntries = config->readBoolEntry("DetailedMenuEntries", false); + if (m_detailedTaskEntries) + { + m_detailedNamesFirst = config->readBoolEntry("DetailedEntriesNamesFirst", false); + } + + m_isImmutable = Kicker::kicker()->isImmutable() || config->groupIsImmutable("TOM"); + config->setGroup("TOM"); + m_largerFont = font(); + m_largerFont = config->readFontEntry("Font", &m_largerFont); +} + +TOM::~TOM() +{ + slotClear(); +} + +void TOM::initializeRecentApps(QPopupMenu* menu) +{ + /* + * TODO: make this real + * add a KDE-wide "commands run" registry + */ + + if (!m_isImmutable) + { + menu->insertSeparator(); + menu->insertItem(i18n("Configure This Menu"), configureMenuID); + } +} + +void TOM::initializeRecentDocs() +{ + m_recentDocsMenu->clear(); + m_recentDocsMenu->insertItem(SmallIconSet("history_clear"), i18n("Clear History"), + this, SLOT(clearRecentDocHistory())); + m_recentDocsMenu->insertSeparator(); + + m_recentDocURLs = KRecentDocument::recentDocuments(); + + if (m_recentDocURLs.isEmpty()) + { + setItemEnabled(m_recentDocsMenu->insertItem(i18n("No Entries")), false); + return; + } + + int id = 0; + for (QStringList::ConstIterator it = m_recentDocURLs.begin(); + it != m_recentDocURLs.end(); + ++it) + { + /* + * TODO: make the number of visible items configurable? + */ + + KDesktopFile f(*it, true /* read only */); + m_recentDocsMenu->insertItem(DesktopIcon(f.readIcon(), KIcon::SizeMedium), + f.readName().replace('&', "&&"), id); + ++id; + } +} + +int TOM::appendTaskGroup(KConfig& config, bool inSubMenu) +{ + if (!config.hasGroup("General")) + { + return 0; + } + + config.setGroup("General"); + + if (config.readBoolEntry("Hidden", false)) + { + return 0; + } + + QString name = config.readEntry("Name", i18n("Unknown")); + QString icon = config.readEntry("Icon"); + int numTasks = config.readNumEntry("NumTasks", 0); + + if (numTasks < 1) + { + return 0; + } + + KPopupMenu* taskGroup; + if( inSubMenu ) + { + taskGroup = new KPopupMenu(this); + + if (icon != QString::null) + { + insertItem(DesktopIcon(icon, KIcon::SizeMedium), name, taskGroup); + } + else + { + insertItem(name, taskGroup); + } + } + else + { + taskGroup = this; + } + + int foundTasks = 0; + for (int i = 0; i < numTasks; ++i) + { + QString groupName = QString("Task%1").arg(i); + + if (config.hasGroup(groupName)) + { + config.setGroup(groupName); + + if (config.readBoolEntry("Hidden", false)) + { + continue; + } + + QString name = config.readEntry("Name"); + // in case the name contains an ampersand, double 'em up + name.replace("&", "&&"); + QString desktopfile = config.readPathEntry("DesktopFile"); + KService::Ptr pService = KService::serviceByDesktopPath(desktopfile); + + if (!pService) + { + pService = KService::serviceByDesktopName(desktopfile); + + if (!pService) + { + continue; + } + } + + QString execName = pService->name(); + QString icon = pService->icon(); + + if (m_detailedTaskEntries && !execName.isEmpty()) + { + QString tmp = i18n("%1 (%2)"); + + if (m_detailedNamesFirst) + { + name = tmp.arg(execName).arg(name); + } + else + { + name = tmp.arg(name).arg(execName); + } + } + + ++m_maxIndex; + if (icon.isEmpty()) + { + taskGroup->insertItem(name, m_maxIndex); + } + else + { + + QIconSet iconset = BarIconSet(icon, 22); + if (iconset.isNull()) + taskGroup->insertItem(name, m_maxIndex); + else + taskGroup->insertItem(iconset, name, m_maxIndex); + + } + + m_tasks.insert(m_maxIndex, pService); + ++foundTasks; + } + } + + // if we end up with an empty task group, get rid of the menu + if (foundTasks == 0) + { + if (inSubMenu) + { + delete taskGroup; + } + + return 0; + } + + connect(taskGroup, SIGNAL(activated(int)), this, SLOT(runTask(int))); + // so we have an actual task group menu with tasks, let's add it + + if (inSubMenu) + { + QObject::connect(taskGroup, SIGNAL(aboutToShowContextMenu(KPopupMenu*, int, QPopupMenu*)), + this, SLOT(contextualizeRMBmenu(KPopupMenu*, int, QPopupMenu*))); + + m_submenus.append(taskGroup); + + taskGroup->setFont(m_largerFont); + taskGroup->setKeyboardShortcutsEnabled(true); + + if (!m_isImmutable && !config.isImmutable()) + { + taskGroup->insertSeparator(); + taskGroup->insertItem("Modify These Tasks", configureMenuID); + QPopupMenu* rmbMenu = taskGroup->contextMenu(); + rmbMenu->setFont(m_largerFont); + KPopupTitle* title = new KPopupTitle(); + title->setText(i18n("%1 Menu Editor").arg(name)); + rmbMenu->insertItem(title, contextMenuTitleID); + rmbMenu->insertItem(i18n("Add This Task to Panel")); + rmbMenu->insertItem(i18n("Modify This Task...")); + rmbMenu->insertItem(i18n("Remove This Task..."), this, SLOT(removeTask())); + rmbMenu->insertItem(i18n("Insert New Task...")); + } + } + + return foundTasks; +} +/* + * TODO: track configuration file changes. +void TOM::configChanged() +{ + KPanelMenu::configChanged(); + setInitialized(false); + initialize(); +} +*/ +void TOM::initialize() +{ + if (initialized()) + { + return; + } + + setInitialized(true); + m_submenus.clear(); + m_tasks.clear(); + clear(); + + /* hack to make items larger. should use something better? + m_largerFont = font(); + if (m_largerFont.pointSize() < 18) + { + m_largerFont.setPointSize(18); + } + setFont(m_largerFont);*/ + + + /*if (!loadSidePixmap()) + { + m_sidePixmap = m_sideTilePixmap = QPixmap(); + } + else + { + connect(kapp, SIGNAL(kdisplayPaletteChanged()), SLOT(paletteChanged())); + }*/ + + // TASKS + insertTitle(i18n("Tasks"), contextMenuTitleID); + + QStringList dirs = KGlobal::dirs()->findDirs("data", "kicker/tom/"); + QStringList::ConstIterator dIt = dirs.begin(); + QStringList::ConstIterator dEnd = dirs.end(); + + for (; dIt != dEnd; ++dIt ) + { + QDir dir(*dIt); + + QStringList entries = dir.entryList("*rc", QDir::Files); + QStringList::ConstIterator eIt = entries.begin(); + QStringList::ConstIterator eEnd = entries.end(); + + for (; eIt != eEnd; ++eIt ) + { + KConfig config(*dIt + *eIt); + appendTaskGroup(config); + } + } + + PanelServiceMenu* moreApps = new PanelServiceMenu(QString::null, QString::null, this, "More Applications"); + moreApps->setFont(m_largerFont); + insertItem(DesktopIcon("misc", KIcon::SizeMedium), i18n("More Applications"), moreApps); + m_submenus.append(moreApps); + + if (!m_isImmutable) + { + insertSeparator(); + // TODO: connect to taskgroup edits + insertItem("Modify The Above Tasks"); + } + + // DESTINATIONS + insertTitle(i18n("Destinations"), destMenuTitleID); + int numDests = 0; + QString destinationsConfig = locate("appdata", "tom/destinations"); + + if (!destinationsConfig.isEmpty() && QFile::exists(destinationsConfig)) + { + KConfig config(destinationsConfig); + numDests = appendTaskGroup(config, false); + } + + if (numDests == 0) + { + removeItem(destMenuTitleID); + } + else if (kapp->authorize("run_command")) + { + insertItem(DesktopIcon("run", KIcon::SizeMedium), i18n("Run Command..."), this, SLOT(runCommand())); + } + + // RECENTLY USED ITEMS + insertTitle(i18n("Recently Used Items"), contextMenuTitleID); + + m_recentDocsMenu = new KPopupMenu(this, "recentDocs"); + m_recentDocsMenu->setFont(m_largerFont); + connect(m_recentDocsMenu, SIGNAL(aboutToShow()), this, SLOT(initializeRecentDocs())); + connect(m_recentDocsMenu, SIGNAL(activated(int)), this, SLOT(openRecentDocument(int))); + insertItem(DesktopIcon("document", KIcon::SizeMedium), i18n("Recent Documents"), m_recentDocsMenu); + m_submenus.append(m_recentDocsMenu); + + KPopupMenu* recentApps = new KPopupMenu(this, "recentApps"); + recentApps->setFont(m_largerFont); + recentApps->setKeyboardShortcutsEnabled(true); + initializeRecentApps(recentApps); + insertItem(i18n("Recent Applications"), recentApps); + m_submenus.append(recentApps); + + // SPECIAL ITEMS + insertTitle(i18n("Special Items"), contextMenuTitleID); + + // if we have no destinations, put the run command here + if (numDests == 0 && kapp->authorize("run_command")) + { + insertItem(DesktopIcon("run", KIcon::SizeMedium), i18n("Run Command..."), this, SLOT(runCommand())); + } + + + KConfig* config = KGlobal::config(); + QStringList menu_ext = config->readListEntry("Extensions"); + if (!menu_ext.isEmpty()) + { + bool needSeparator = false; + for (QStringList::ConstIterator it = menu_ext.begin(); it != menu_ext.end(); ++it) + { + MenuInfo info(*it); + if (!info.isValid()) + { + continue; + } + + KPanelMenu *menu = info.load(); + if (menu) + { + ++m_maxIndex; + insertItem(DesktopIcon(info.icon(), KIcon::SizeMedium), info.name(), menu, m_maxIndex); + m_submenus.append(menu); + needSeparator = true; + } + } + + if (needSeparator) + { + insertSeparator(); + } + } + + + QString username; + struct passwd *userInfo = getpwuid(getuid()); + if (userInfo) + { + username = QString::fromLocal8Bit(userInfo->pw_gecos); + if (username.find(',') != -1) + { + // Remove everything from and including first comma + username.truncate(username.find(',')); + } + + if (username.isEmpty()) + { + username = QString::fromLocal8Bit(userInfo->pw_name); + } + } + + insertItem(DesktopIcon("exit", KIcon::SizeMedium), + i18n("Logout %1").arg(username), this, SLOT(logout())); +} + +void TOM::reload() +{ + setInitialized(false); + initialize(); +} + +void TOM::contextualizeRMBmenu(KPopupMenu* menu, int menuItem, QPopupMenu* ctxMenu) +{ + if (menuItem == configureMenuID) + { + menu->hideContextMenu(); + return; + } + + ctxMenu->removeItem(contextMenuTitleID); + QString text = menu->text(menuItem); + int parens = text.find('(') - 1; + if (parens > 0) + { + text = text.left(parens); + } + KPopupTitle* title = new KPopupTitle(); + title->setText(i18n("The \"%2\" Task").arg(text)); + ctxMenu->insertItem(title, contextMenuTitleID, 0); +} + +void TOM::slotClear() +{ + KPanelMenu::slotClear(); + m_submenus.clear(); + m_tasks.clear(); +} + +void TOM::slotExec(int /* id */) +{ + // Reimplemented because we have to +} + +void TOM::removeTask() +{ + // TODO: write this change out to the appropriate config file + QString task = KPopupMenu::contextMenuFocus()->text(KPopupMenu::contextMenuFocusItem()); + if (KMessageBox::warningContinueCancel(this, + i18n("<qt>Are you sure you want to remove the <strong>%1</strong> task?<p>" + "<em>Tip: You can restore the task after it has been removed by selecting the "Modify These Tasks" entry</em></qt>").arg(task), + i18n("Remove Task?"),KStdGuiItem::del()) == KMessageBox::Continue) + { + m_tasks.remove(KPopupMenu::contextMenuFocusItem()); + KPopupMenu::contextMenuFocus()->removeItem(KPopupMenu::contextMenuFocusItem()); + } +} + +// TODO: should we have a side graphic like the K Menu? personally, i don't +// think it helps usability. it's nice for branding, but that's it. perhaps a +// top image, or something blended with the actual menu background? deffinitely +// a job for a graphic artist. +/* + * if this goes in, it should be shared w/the kmenu + * +bool TOM::loadSidePixmap() +{ + KConfig *config = KGlobal::config(); + QColor color = palette().active().highlight(); + QImage image; + + config->setGroup("WM"); + QColor activeTitle = config->readColorEntry("activeBackground", &color); + QColor inactiveTitle = config->readColorEntry("inactiveBackground", &color); + + config->setGroup("KMenu"); + if (!config->readBoolEntry("Usem_sidePixmap", true)) + return false; + + // figure out which color is most suitable for recoloring to + int h1, s1, v1, h2, s2, v2, h3, s3, v3; + activeTitle.hsv(&h1, &s1, &v1); + inactiveTitle.hsv(&h2, &s2, &v2); + palette().active().background().hsv(&h3, &s3, &v3); + + if ( (abs(h1-h3)+abs(s1-s3)+abs(v1-v3) < abs(h2-h3)+abs(s2-s3)+abs(v2-v3)) && + ((abs(h1-h3)+abs(s1-s3)+abs(v1-v3) < 32) || (s1 < 32)) && (s2 > s1)) + color = inactiveTitle; + else + color = activeTitle; + + // limit max/min brightness + int r, g, b; + color.rgb(&r, &g, &b); + int gray = qGray(r, g, b); + if (gray > 180) { + r = (r - (gray - 180) < 0 ? 0 : r - (gray - 180)); + g = (g - (gray - 180) < 0 ? 0 : g - (gray - 180)); + b = (b - (gray - 180) < 0 ? 0 : b - (gray - 180)); + } else if (gray < 76) { + r = (r + (76 - gray) > 255 ? 255 : r + (76 - gray)); + g = (g + (76 - gray) > 255 ? 255 : g + (76 - gray)); + b = (b + (76 - gray) > 255 ? 255 : b + (76 - gray)); + } + color.setRgb(r, g, b); + + QString sideName = config->readEntry("SideName", "kside.png"); + QString sideTileName = config->readEntry("SideTileName", "kside_tile.png"); + + image.load(locate("data", "kicker/pics/" + sideName)); + + if (image.isNull()) + { + return false; + } + + KIconEffect::colorize(image, color, 1.0); + m_sidePixmap.convertFromImage(image); + + image.load(locate("data", "kicker/pics/" + sideTileName)); + + if (image.isNull()) + { + return false; + } + + KIconEffect::colorize(image, color, 1.0); + m_sideTilePixmap.convertFromImage(image); + + if (m_sidePixmap.width() != m_sideTilePixmap.width()) + { + return false; + } + + // pretile the pixmap to a height of at least 100 pixels + if (m_sideTilePixmap.height() < 100) + { + int tiles = (int)(100 / m_sideTilePixmap.height()) + 1; + QPixmap preTiledPixmap(m_sideTilePixmap.width(), m_sideTilePixmap.height() * tiles); + QPainter p(&preTiledPixmap); + p.drawTiledPixmap(preTiledPixmap.rect(), m_sideTilePixmap); + m_sideTilePixmap = preTiledPixmap; + } + + return true; +} + +void TOM::paletteChanged() +{ + if (!loadSidePixmap()) + m_sidePixmap = m_sideTilePixmap = QPixmap(); +} + +void TOM::setMinimumSize(const QSize & s) +{ + KPanelMenu::setMinimumSize(s.width() + m_sidePixmap.width(), s.height()); +} + +void TOM::setMaximumSize(const QSize & s) +{ + KPanelMenu::setMaximumSize(s.width() + m_sidePixmap.width(), s.height()); +} + +void TOM::setMinimumSize(int w, int h) +{ + KPanelMenu::setMinimumSize(w + m_sidePixmap.width(), h); +} + +void TOM::setMaximumSize(int w, int h) +{ + KPanelMenu::setMaximumSize(w + m_sidePixmap.width(), h); +} + +QRect TOM::sideImageRect() +{ + return QStyle::visualRect( QRect( frameWidth(), frameWidth(), m_sidePixmap.width(), + height() - 2*frameWidth() ), this ); +} + +void TOM::resizeEvent(QResizeEvent * e) +{ + setFrameRect( QStyle::visualRect( QRect( m_sidePixmap.width(), 0, + width() - m_sidePixmap.width(), height() ), this ) ); +} + +void TOM::paintEvent(QPaintEvent * e) +{ + if (m_sidePixmap.isNull()) { + KPanelMenu::paintEvent(e); + return; + } + + QPainter p(this); + + style().drawPrimitive( QStyle::PE_PanelPopup, &p, + QRect( 0, 0, width(), height() ), + colorGroup(), QStyle::Style_Default, + QStyleOption( frameWidth(), 0 ) ); + + QRect r = sideImageRect(); + r.setBottom( r.bottom() - m_sidePixmap.height() ); + p.drawTiledPixmap( r, m_sideTilePixmap ); + + r = sideImageRect(); + r.setTop( r.bottom() - m_sidePixmap.height() ); + p.drawPixmap( r, m_sidePixmap ); + + drawContents( &p ); +} + +QMouseEvent TOM::translateMouseEvent( QMouseEvent* e ) +{ + QRect side = sideImageRect(); + + if ( !side.contains( e->pos() ) ) + return *e; + + QPoint newpos( e->pos() ); + QApplication::reverseLayout() ? + newpos.setX( newpos.x() - side.width() ) : + newpos.setX( newpos.x() + side.width() ); + QPoint newglobal( e->globalPos() ); + QApplication::reverseLayout() ? + newglobal.setX( newpos.x() - side.width() ) : + newglobal.setX( newpos.x() + side.width() ); + + return QMouseEvent( e->type(), newpos, newglobal, e->button(), e->state() ); +} + +void TOM::mousePressEvent(QMouseEvent * e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + KPanelMenu::mousePressEvent( &newEvent ); +} + +void TOM::mouseReleaseEvent(QMouseEvent *e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + KPanelMenu::mouseReleaseEvent( &newEvent ); +} + +void TOM::mouseMoveEvent(QMouseEvent *e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + KPanelMenu::mouseMoveEvent( &newEvent ); +}*/ + +extern int kicker_screen_number; + +void TOM::runCommand() +{ + QByteArray data; + QCString appname( "kdesktop" ); + if ( kicker_screen_number ) + appname.sprintf("kdesktop-screen-%d", kicker_screen_number); + + kapp->updateRemoteUserTimestamp( appname ); + kapp->dcopClient()->send( appname, "KDesktopIface", + "popupExecuteCommand()", data ); +} + +void TOM::runTask(int id) +{ + if (!m_tasks.contains(id)) return; + + kapp->propagateSessionManager(); + KApplication::startServiceByDesktopPath(m_tasks[id]->desktopEntryPath(), + QStringList(), 0, 0, 0, "", true); +} + +void TOM::clearRecentDocHistory() +{ + KRecentDocument::clear(); +} + +void TOM::openRecentDocument(int id) +{ + if (id >= 0) + { + kapp->propagateSessionManager(); + KURL u; + u.setPath(m_recentDocURLs[id]); + KDEDesktopMimeType::run(u, true); + } +} + +void TOM::logout() +{ + kapp->requestShutDown(); +} + +#include "tom.moc" diff --git a/kicker/menuext/tom/tom.desktop b/kicker/menuext/tom/tom.desktop new file mode 100644 index 000000000..f59a4beab --- /dev/null +++ b/kicker/menuext/tom/tom.desktop @@ -0,0 +1,75 @@ +[Desktop Entry] +Name=TOM +Name[bg]=Задачно меню +Name[eo]=PTMS +Name[hi]=टीओएम +Name[te]=టామ్ +Name[zh_CN]=任务菜单 +Comment=A task oriented menu system +Comment[af]='n Taak geörienteerde kieslys stelsel +Comment[ar]=نظام قوائم وظيفيّ المنحى +Comment[be]=Сістэма меню, арыентаваная на выкананне шматлікіх задачаў +Comment[bg]=Меню, ориентирано към изпълнение на задачи +Comment[bn]=টাস্ক ওরিয়েন্টেড মেনু সিস্টেম +Comment[bs]=Sistem menija orjentisan na zadatke +Comment[ca]=Una tasca orientada al menú del sistema +Comment[cs]=Úkolově orientovaný systém nabídek +Comment[csb]=Systema menu skòncentrowónô na dzejaniô +Comment[cy]=Cysawd dewislenni a gyfeirir at dasgau +Comment[da]=Et opgaveorienteret menusystem +Comment[de]=Aufgabenorientiertes Menüsystem +Comment[el]=Ένα σύστημα μενού προσανατολισμένο στην εργασία +Comment[eo]=Pertaska menusistemo +Comment[es]=Sistema de menú orientado a tareas +Comment[et]=Ülesandele orienteeritud menüüsüsteem +Comment[eu]=Atazetara zuzendutako menu sistema +Comment[fa]=یک سیستم گزینگان جهتدار تکلیف +Comment[fi]=Tehtäväpohjainen valikkojärjestelmä +Comment[fr]=Un menu système par tâches +Comment[fy]=In taakoriïntearre menusysteem +Comment[ga]=Córas roghchláir dírithe ar thascanna +Comment[gl]=Un menu do sistema orientado a tarefas +Comment[he]=מערכת תפריטים מונחת משימות +Comment[hi]=कार्य अनुकूल मेन्यू तंत्र +Comment[hr]=Sustav izbornika orijentiran zadacima +Comment[hu]=Feladatorientált menürendszer +Comment[is]=Verkefnabyggt valmyndakerfi +Comment[it]=Un sistema di menu organizzato per funzione +Comment[ja]=作業タスクベースのメニューシステム +Comment[ka]=ამოცანაზე ორიენტირებული მენიუს სისტემა +Comment[kk]=Тапсырмаларға арналған мәзір жүйесі +Comment[km]=ប្រព័ន្ធម៉ឺនុយដែលសម្របតាមភារកិច្ច +Comment[lt]=Į užduotis orientuota meniu sistema +Comment[lv]=Uz darbībām orientēta izvēlņu sistēma +Comment[mk]=Систем од менија ориентиран кон задачи +Comment[mn]=Үйлдэлд чиглэсэн цэсийн систем +Comment[ms]=Sistem menu berorientasikan tugas +Comment[mt]=Menu imqassam skond ix-xogħol li trid tagħmel +Comment[nb]=Et oppgaveorientert menysystem +Comment[nds]=Menüsysteem, dat an Opgaven utricht is +Comment[ne]=कार्य उन्मुख मेनु प्रणाली +Comment[nl]=Een taakgeörienteerd menusysteem +Comment[nn]=Eit oppgåveorientert menysystem +Comment[pa]=ਇੱਕ ਕੰਮ ਆਧਾਰਿਤ ਮੇਨੂ ਸਿਸਟਮ +Comment[pl]=System menu zorientowany na zadania +Comment[pt]=Um sistema de menus orientado por tarefas +Comment[pt_BR]=Um sistema de menu orientado a tarefa +Comment[ro]=Un meniu orientat pe probleme de rezolvat +Comment[ru]=Система меню, ориентированная на задачи +Comment[rw]=Ibikubiyemo Sisitemu bijyanye n'Igikorwa +Comment[sk]=Systém menu podľa činnosti +Comment[sl]=Opravilno narejen menijski sistem +Comment[sr]=Систем менија оријентисан према задацима +Comment[sr@Latn]=Sistem menija orijentisan prema zadacima +Comment[sv]=Uppgiftsrelaterat menysystem +Comment[ta]=பணி சார்ந்த பட்டியல் அமைப்பு +Comment[th]=ระบบเมนูที่ใช้แนวทางของงาน +Comment[tr]=Görev yönelimli bir menü sistemi +Comment[tt]=Yökkä yünälgän saylaq sisteme +Comment[uk]=Система меню орієнтована на завдання +Comment[vi]=Hệ thực đơn hướng tác vụ +Comment[wa]=Ene dressêye sistinme fwaite po les bouyes +Comment[zh_CN]=面向任务的菜单系统 +Comment[zh_TW]=一個工作導向的選單系統 +Icon=kmenu +X-KDE-Library=kickermenu_tom diff --git a/kicker/menuext/tom/tom.h b/kicker/menuext/tom/tom.h new file mode 100644 index 000000000..663cb05d6 --- /dev/null +++ b/kicker/menuext/tom/tom.h @@ -0,0 +1,110 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Aaron J. Seigo <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __tom_h_ +#define __tom_h_ + +#include <qpixmap.h> + +#include <kpanelmenu.h> +#include <klibloader.h> + +class KPopupMenu; +class QPopupMenu; + +typedef QPtrList<QPopupMenu> PopupMenuList; +typedef QMap<int, KService::Ptr> TaskMap; + +class TOM : public KPanelMenu +{ + Q_OBJECT + + public: + TOM(QWidget *parent = 0, const char *name = 0); + ~TOM(); + + // for the side image + /*void setMinimumSize(const QSize &); + void setMaximumSize(const QSize &); + void setMinimumSize(int, int); + void setMaximumSize(int, int); */ + + protected slots: + void slotClear(); + void slotExec(int); + //void configChanged(); + void initialize(); + void contextualizeRMBmenu(KPopupMenu* menu, int menuItem, QPopupMenu* ctxMenu); + //void paletteChanged(); + void clearRecentDocHistory(); + void runCommand(); + void runTask(int id); + void initializeRecentDocs(); + void openRecentDocument(int id); + void logout(); + + /* + * slots for the RMB menu on task group + */ + void removeTask(); + + protected: + void reload(); + + int appendTaskGroup(KConfig& config, bool inSubMenu = true ); + void initializeRecentApps(QPopupMenu* menu); + //int insertTOMTitle(QPopupMenu* menu, const QString &text, int id = -1, int index = -1); + + /* + * this stuff should be shared w/the kmenu + + QRect sideImageRect(); + QMouseEvent translateMouseEvent( QMouseEvent* e ); + void resizeEvent(QResizeEvent *); + void paintEvent(QPaintEvent *); + void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + bool loadSidePixmap(); + + QPixmap m_sidePixmap; + QPixmap m_sideTilePixmap;*/ + PopupMenuList m_submenus; + QFont m_largerFont; + int m_maxIndex; + bool m_isImmutable; + bool m_detailedTaskEntries; + bool m_detailedNamesFirst; + TaskMap m_tasks; + KPopupMenu* m_recentDocsMenu; + QStringList m_recentDocURLs; +}; + +class TOMFactory : public KLibFactory +{ + public: + TOMFactory(QObject *parent = 0, const char *name = 0); + + protected: + QObject* createObject(QObject *parent = 0, const char *name = 0, + const char *classname = "QObject", + const QStringList& args = QStringList()); +}; + + +#endif |