mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-23 10:22:49 +00:00
plasma: reimplement launcher applet
very much WIP but functional Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
4f448f84ec
commit
97f73b2608
60 changed files with 1025 additions and 11070 deletions
|
@ -11,7 +11,7 @@ add_subdirectory(system-monitor)
|
|||
add_subdirectory(notifications)
|
||||
add_subdirectory(systemtray)
|
||||
add_subdirectory(keyboard)
|
||||
add_subdirectory(kickoff)
|
||||
add_subdirectory(launcher)
|
||||
add_subdirectory(trash)
|
||||
add_subdirectory(folderview)
|
||||
add_subdirectory(weather)
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
#######################################################################################
|
||||
# Kickoff Library
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
set(libkickoff_SRCS
|
||||
core/kickoffmodel.cpp
|
||||
core/kickoffabstractmodel.cpp
|
||||
core/kickoffproxymodel.cpp
|
||||
core/applicationmodel.cpp
|
||||
core/favoritesmodel.cpp
|
||||
core/leavemodel.cpp
|
||||
core/models.cpp
|
||||
core/recentapplications.cpp
|
||||
core/recentlyusedmodel.cpp
|
||||
core/krunnermodel.cpp
|
||||
core/systemmodel.cpp
|
||||
core/urlitemlauncher.cpp
|
||||
core/itemhandlers.cpp
|
||||
)
|
||||
|
||||
qt4_add_dbus_adaptor(libkickoff_SRCS core/org.kde.kickoff.xml core/applicationmodel.h Kickoff::ApplicationModel)
|
||||
qt4_add_dbus_adaptor(libkickoff_SRCS core/org.kde.kickoff.recent.xml core/recentlyusedmodel.h Kickoff::RecentlyUsedModel)
|
||||
|
||||
set(screensaver_xml ${CMAKE_SOURCE_DIR}/kscreensaver/org.freedesktop.ScreenSaver.xml)
|
||||
QT4_ADD_DBUS_INTERFACE(libkickoff_SRCS ${screensaver_xml} screensaver_interface)
|
||||
set(ksmserver_xml ${CMAKE_SOURCE_DIR}/ksmserver/org.kde.KSMServerInterface.xml)
|
||||
QT4_ADD_DBUS_INTERFACE(libkickoff_SRCS ${ksmserver_xml} ksmserver_interface)
|
||||
|
||||
set(Kickoff_LIBS KDE4::kio KDE4::solid kworkspace)
|
||||
|
||||
add_library(kickoff SHARED ${libkickoff_SRCS})
|
||||
target_link_libraries(kickoff KDE4::plasma ${Kickoff_LIBS})
|
||||
|
||||
generate_export_header(kickoff)
|
||||
|
||||
install(
|
||||
TARGETS kickoff
|
||||
DESTINATION ${KDE4_LIB_INSTALL_DIR}
|
||||
)
|
||||
|
||||
#######################################################################################
|
||||
# Kickoff Plasma Applet
|
||||
|
||||
set(Applet_SRCS
|
||||
ui/contextmenufactory.cpp
|
||||
ui/flipscrollview.cpp
|
||||
ui/itemdelegate.cpp
|
||||
ui/contentareacap.cpp
|
||||
ui/launcher.cpp
|
||||
ui/searchbar.cpp
|
||||
ui/tabbar.cpp
|
||||
ui/urlitemview.cpp
|
||||
applet/applet.cpp
|
||||
applet/kickoffConfig.ui
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/contextmenufactory.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/launcher.cpp
|
||||
PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE
|
||||
)
|
||||
|
||||
kde4_add_plugin(plasma_applet_launcher ${Applet_SRCS})
|
||||
|
||||
target_link_libraries(plasma_applet_launcher
|
||||
KDE4::kcmutils
|
||||
KDE4::plasma
|
||||
${QT_QTNETWORK_LIBRARY}
|
||||
${Kickoff_LIBS}
|
||||
kickoff
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS plasma_applet_launcher
|
||||
DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}
|
||||
)
|
||||
|
||||
install(
|
||||
FILES applet/plasma-applet-launcher.desktop
|
||||
DESTINATION ${KDE4_SERVICES_INSTALL_DIR}
|
||||
)
|
||||
|
||||
#######################################################################################
|
||||
# Kickoff Simple KMenu Plasma Applet
|
||||
|
||||
set(SimpleApplet_SRCS
|
||||
ui/contextmenufactory.cpp
|
||||
simpleapplet/menuview.cpp
|
||||
simpleapplet/simpleapplet.cpp
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/contextmenufactory.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/simpleapplet/menuview.cpp
|
||||
PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE
|
||||
)
|
||||
|
||||
kde4_add_plugin(plasma_applet_simplelauncher ${SimpleApplet_SRCS})
|
||||
target_link_libraries(plasma_applet_simplelauncher
|
||||
KDE4::kcmutils
|
||||
KDE4::plasma
|
||||
${Kickoff_LIBS}
|
||||
kickoff
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS plasma_applet_simplelauncher
|
||||
DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}
|
||||
)
|
||||
|
||||
install(
|
||||
FILES simpleapplet/plasma-applet-simplelauncher.desktop
|
||||
DESTINATION ${KDE4_SERVICES_INSTALL_DIR}
|
||||
)
|
||||
|
||||
# Kickoff Standalone Test Application
|
||||
#IF (CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
# set(Application_SRCS ${Kickoff_SRCS} main.cpp)
|
||||
# add_executable(kickoff ${Application_SRCS})
|
||||
# target_link_libraries(kickoff KDE4::plasma ${Kickoff_LIBS})
|
||||
# install(TARGETS kickoff DESTINATION ${KDE4_BIN_INSTALL_DIR})
|
||||
#ENDIF (CMAKE_BUILD_TYPE MATCHES Debug)
|
|
@ -1,69 +0,0 @@
|
|||
|
||||
Project Proposal: Kickoff KDE 4 Rewrite
|
||||
|
||||
This is a re-implementation of the Kickoff menu for KDE 3 originally created
|
||||
by the OpenSuSE team.
|
||||
|
||||
Overall goals:
|
||||
|
||||
1. Implement the Kickoff user interface using Qt/KDE 4 technology
|
||||
|
||||
2. Make it easy for distributions to modify the menu contents
|
||||
|
||||
3. Make it easy for distributions to add their own branding
|
||||
|
||||
Detailed goals:
|
||||
|
||||
1. Implement the Kickoff user interface using Qt/KDE 4 technology
|
||||
|
||||
-> Clean separation of core and user interface
|
||||
-> eg. Make good use of Qt 4's model/view classes
|
||||
-> Use Strigi for search and analysis (or possibly just Xesam interface?)
|
||||
-> Use Solid for getting data for removable device list
|
||||
-> Attractive, original, but not overbearing graphical effects
|
||||
using Qt 4's new painting and animation features.
|
||||
|
||||
To decide on:
|
||||
|
||||
-> Consult the Kickoff/KDE 3 developers and OpenSuSE users about
|
||||
any desired changes to the user interface.
|
||||
-> Whether to use Plasma applets and widgets or Qt's widgets and
|
||||
QAbstractItemView as the base for the view classes.
|
||||
-> Provision of Plasma data engines for applets to use to query
|
||||
applications, recent documents, favorites etc.
|
||||
-> Should facilities be provided for distributions to replace
|
||||
Strigi with their choice of search engine?
|
||||
|
||||
Ideas to explore in future:
|
||||
|
||||
-> Use Sonnet for spell-checking the user's search query
|
||||
-> Light KWin integration for interesting effects for revealing,
|
||||
hiding or rendering the Kickoff launcher on composited '3D'
|
||||
desktops.
|
||||
|
||||
Goals 2 and 3 are derived from looking at the KDE 3 implementation
|
||||
of Kickoff and also the way in which distributions customise KDE.
|
||||
Consulting distribution representatives is important to clarify
|
||||
these particular goals.
|
||||
|
||||
2. Make it easy for distributions to modify the menu contents
|
||||
|
||||
-> Different distributions may have different tools for system
|
||||
configuration ( eg. System Settings , YaST , Mandriva's tools )
|
||||
-> The available options on the leave page and the way in which
|
||||
those tools work varies depending on the distribution
|
||||
|
||||
3. Make it easy for distributions to add their own branding
|
||||
|
||||
-> The launcher menu is a highly visible part of the desktop,
|
||||
distributions are therefore likely to want to brand it with
|
||||
their own logos, colors, icons etc.
|
||||
This does not mean infinite theme-ability, but rather a good
|
||||
out-of-the-box look which distros can easily tweak so that
|
||||
it is obvious which distribution is being used from looking
|
||||
at a screenshot, and also to allow distros to make some
|
||||
obvious cosmetic changes between versions.
|
||||
|
||||
(See the Ubuntu art specs for example which state that each
|
||||
new version is supposed to have a visual look which is
|
||||
distinct from the previous version)
|
|
@ -1,334 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "applet/applet.h"
|
||||
|
||||
// Katie
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QGraphicsView>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QGraphicsLinearLayout>
|
||||
|
||||
// KDE
|
||||
#include <KIcon>
|
||||
#include <KDebug>
|
||||
#include <KConfigDialog>
|
||||
#include <KPluginSelector>
|
||||
#include <KToolInvocation>
|
||||
#include <KCategorizedView>
|
||||
#include <Plasma/IconWidget>
|
||||
#include <Plasma/Containment>
|
||||
#include <Plasma/View>
|
||||
#include <Plasma/ToolTipManager>
|
||||
#include <Plasma/RunnerManager>
|
||||
|
||||
// Local
|
||||
#include "ui_kickoffConfig.h"
|
||||
#include "ui/launcher.h"
|
||||
#include "core/recentapplications.h"
|
||||
#include "core/models.h"
|
||||
#include "core/krunnermodel.h"
|
||||
|
||||
// NOTE: keep in sync with:
|
||||
// kdelibs/kutils/kpluginselector_p.h
|
||||
static const int s_pluginnamerole = 0x0CBBBB00;
|
||||
|
||||
static QString kMakeToolTip(const QString &pluginname)
|
||||
{
|
||||
QString result;
|
||||
Plasma::AbstractRunner* runner = Kickoff::KRunnerModel::runnerManager()->runner(pluginname);
|
||||
if (!runner) {
|
||||
return result;
|
||||
}
|
||||
const QList<Plasma::RunnerSyntax> syntaxes = runner->syntaxes();
|
||||
if (syntaxes.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
QStringList uniqueexamples;
|
||||
foreach (const Plasma::RunnerSyntax &syntax, syntaxes) {
|
||||
foreach (const QString &example, syntax.exampleQueriesWithTermDescription()) {
|
||||
uniqueexamples.append(example);
|
||||
}
|
||||
}
|
||||
uniqueexamples.removeDuplicates();
|
||||
if (uniqueexamples.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
result.append(i18n("<b>Examples:</b><br/>"));
|
||||
foreach (const QString &example, uniqueexamples) {
|
||||
result.append(QString::fromLatin1("<i>%1</i><br/>").arg(Qt::escape(example)));
|
||||
}
|
||||
// qDebug() << Q_FUNC_INFO << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
class LauncherApplet::Private
|
||||
{
|
||||
public:
|
||||
Private(LauncherApplet *lApplet) : launcher(0), switcher(0), q(lApplet) { }
|
||||
~Private() {
|
||||
delete launcher;
|
||||
}
|
||||
void createLauncher();
|
||||
void initToolTip();
|
||||
|
||||
Kickoff::Launcher *launcher;
|
||||
|
||||
QList<QAction*> actions;
|
||||
QAction* switcher;
|
||||
LauncherApplet *q;
|
||||
Ui::kickoffConfig ui;
|
||||
KPluginSelector* selector;
|
||||
};
|
||||
|
||||
void LauncherApplet::Private::createLauncher()
|
||||
{
|
||||
if (launcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
launcher = new Kickoff::Launcher(q);
|
||||
launcher->setAttribute(Qt::WA_NoSystemBackground);
|
||||
launcher->setAutoHide(true);
|
||||
QObject::connect(launcher, SIGNAL(aboutToHide()), q, SLOT(hidePopup()));
|
||||
QObject::connect(launcher, SIGNAL(configNeedsSaving()), q, SIGNAL(configNeedsSaving()));
|
||||
//launcher->resize(launcher->sizeHint());
|
||||
//QObject::connect(launcher, SIGNAL(aboutToHide()), icon, SLOT(setUnpressed()));
|
||||
}
|
||||
|
||||
void LauncherApplet::Private::initToolTip()
|
||||
{
|
||||
Plasma::ToolTipContent data(i18n("Kickoff Application Launcher"),
|
||||
i18n("Favorites, applications, computer places, "
|
||||
"recently used items and desktop sessions"),
|
||||
q->popupIcon().pixmap(IconSize(KIconLoader::Desktop)));
|
||||
Plasma::ToolTipManager::self()->setContent(q, data);
|
||||
}
|
||||
|
||||
LauncherApplet::LauncherApplet(QObject *parent, const QVariantList &args)
|
||||
: Plasma::PopupApplet(parent, args),
|
||||
d(new Private(this))
|
||||
{
|
||||
KGlobal::locale()->insertCatalog("plasma_applet_launcher");
|
||||
setAspectRatioMode(Plasma::IgnoreAspectRatio);
|
||||
setHasConfigurationInterface(true);
|
||||
}
|
||||
|
||||
LauncherApplet::~LauncherApplet()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void LauncherApplet::init()
|
||||
{
|
||||
if (KService::serviceByStorageId("kmenuedit.desktop")) {
|
||||
QAction* menueditor = new QAction(i18n("Edit Applications..."), this);
|
||||
d->actions.append(menueditor);
|
||||
connect(menueditor, SIGNAL(triggered(bool)), this, SLOT(startMenuEditor()));
|
||||
}
|
||||
|
||||
Q_ASSERT(! d->switcher);
|
||||
d->switcher = new QAction(i18n("Switch to Classic Menu Style"), this);
|
||||
d->actions.append(d->switcher);
|
||||
connect(d->switcher, SIGNAL(triggered(bool)), this, SLOT(switchMenuStyle()));
|
||||
|
||||
setGlobalShortcut(KShortcut(Qt::ALT+Qt::Key_F2));
|
||||
|
||||
configChanged();
|
||||
Plasma::ToolTipManager::self()->registerWidget(this);
|
||||
}
|
||||
|
||||
void LauncherApplet::constraintsEvent(Plasma::Constraints constraints)
|
||||
{
|
||||
if ((constraints & Plasma::ImmutableConstraint) && d->switcher) {
|
||||
d->switcher->setVisible(immutability() == Plasma::Mutable);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherApplet::switchMenuStyle()
|
||||
{
|
||||
if (containment()) {
|
||||
Plasma::Applet * simpleLauncher =
|
||||
containment()->addApplet("simplelauncher", QVariantList() << true, geometry());
|
||||
|
||||
//Copy all the config items to the simple launcher
|
||||
QMetaObject::invokeMethod(simpleLauncher, "saveConfigurationFromKickoff",
|
||||
Qt::DirectConnection, Q_ARG(KConfigGroup, config()),
|
||||
Q_ARG(KConfigGroup, globalConfig()));
|
||||
|
||||
//Switch shortcuts with the new launcher to avoid losing it
|
||||
KShortcut currentShortcut = globalShortcut();
|
||||
setGlobalShortcut(KShortcut());
|
||||
simpleLauncher->setGlobalShortcut(currentShortcut);
|
||||
|
||||
//Destroy this widget
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherApplet::startMenuEditor()
|
||||
{
|
||||
KToolInvocation::kdeinitExec("kmenuedit");
|
||||
}
|
||||
|
||||
void LauncherApplet::createConfigurationInterface(KConfigDialog *parent)
|
||||
{
|
||||
QWidget *widget = new QWidget();
|
||||
d->ui.setupUi(widget);
|
||||
parent->addPage(widget, i18nc("General configuration page", "General"), icon());
|
||||
|
||||
const QList<KPluginInfo> plugins = Plasma::RunnerManager::listRunnerInfo();
|
||||
d->selector = new KPluginSelector(widget);
|
||||
d->selector->addPlugins(
|
||||
plugins,
|
||||
KPluginSelector::ReadConfigFile,
|
||||
i18n("Available Plugins"), QString(),
|
||||
Kickoff::componentData().config()
|
||||
);
|
||||
connect(d->selector, SIGNAL(changed(bool)), parent, SLOT(settingsModified()));
|
||||
parent->addPage(d->selector, i18n("Runners"), "preferences-plugin");
|
||||
|
||||
foreach (const KPluginInfo& plugin, plugins) {
|
||||
Kickoff::KRunnerModel::runnerManager()->loadRunner(plugin.service());
|
||||
}
|
||||
// HACK: setup tooltips for the plugins
|
||||
KCategorizedView* selectorview = d->selector->findChild<KCategorizedView*>();
|
||||
if (selectorview) {
|
||||
QAbstractItemModel* selectormodel = selectorview->model();
|
||||
if (selectormodel) {
|
||||
for (int i = 0; i < selectormodel->rowCount(); i++) {
|
||||
QModelIndex selectorindex = selectormodel->index(i, 0);
|
||||
const QString pluginname = selectormodel->data(selectorindex, s_pluginnamerole).toString();
|
||||
selectormodel->setData(selectorindex, kMakeToolTip(pluginname), Qt::ToolTipRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
// forces unload of the disabled plugins that have been loaded for the tooltip
|
||||
Kickoff::KRunnerModel::runnerManager()->reloadConfiguration();
|
||||
|
||||
connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
|
||||
connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
|
||||
|
||||
d->createLauncher();
|
||||
d->ui.iconButton->setIcon(popupIcon());
|
||||
d->ui.switchOnHoverCheckBox->setChecked(d->launcher->switchTabsOnHover());
|
||||
d->ui.appsByNameCheckBox->setChecked(d->launcher->showAppsByName());
|
||||
d->ui.showRecentlyInstalledCheckBox->setChecked(d->launcher->showRecentlyInstalled());
|
||||
connect(d->ui.iconButton, SIGNAL(iconChanged(QString)), parent, SLOT(settingsModified()));
|
||||
connect(d->ui.switchOnHoverCheckBox, SIGNAL(toggled(bool)), parent, SLOT(settingsModified()));
|
||||
connect(d->ui.appsByNameCheckBox, SIGNAL(toggled(bool)), parent, SLOT(settingsModified()));
|
||||
connect(d->ui.showRecentlyInstalledCheckBox, SIGNAL(toggled(bool)), parent, SLOT(settingsModified()));
|
||||
}
|
||||
|
||||
void LauncherApplet::popupEvent(bool show)
|
||||
{
|
||||
if (show) {
|
||||
Plasma::ToolTipManager::self()->clearContent(this);
|
||||
d->createLauncher();
|
||||
d->launcher->setLauncherOrigin(popupPlacement(), location());
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherApplet::toolTipAboutToShow()
|
||||
{
|
||||
if (d->launcher->isVisible()) {
|
||||
Plasma::ToolTipManager::self()->clearContent(this);
|
||||
} else {
|
||||
d->initToolTip();
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherApplet::configChanged()
|
||||
{
|
||||
KConfigGroup cg = config();
|
||||
setPopupIcon(cg.readEntry("icon", "start-here-kde"));
|
||||
constraintsEvent(Plasma::ImmutableConstraint);
|
||||
|
||||
if (d->launcher) {
|
||||
d->launcher->setApplet(this);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherApplet::configAccepted()
|
||||
{
|
||||
d->selector->save();
|
||||
KConfigGroup pcg = Kickoff::componentData().config()->group("Plugins");
|
||||
QStringList allowed;
|
||||
foreach (KPluginInfo plugin, Plasma::RunnerManager::listRunnerInfo()) {
|
||||
plugin.load(pcg);
|
||||
if (plugin.isPluginEnabled()) {
|
||||
allowed.append(plugin.pluginName());
|
||||
}
|
||||
}
|
||||
Kickoff::KRunnerModel::runnerManager()->setAllowedRunners(allowed);
|
||||
|
||||
bool switchTabsOnHover = d->ui.switchOnHoverCheckBox->isChecked();
|
||||
bool showAppsByName = d->ui.appsByNameCheckBox->isChecked();
|
||||
bool showRecentlyInstalled = d->ui.showRecentlyInstalledCheckBox->isChecked();
|
||||
|
||||
const QString iconname = d->ui.iconButton->icon();
|
||||
|
||||
// TODO: should this be moved into Launcher as well? perhaps even the config itself?
|
||||
d->createLauncher();
|
||||
|
||||
KConfigGroup cg = config();
|
||||
const QString oldIcon = cg.readEntry("icon", "start-here-kde");
|
||||
if (!iconname.isEmpty() && iconname != oldIcon) {
|
||||
cg.writeEntry("icon", iconname);
|
||||
|
||||
if (!iconname.isEmpty()) {
|
||||
setPopupIcon(iconname);
|
||||
}
|
||||
|
||||
emit configNeedsSaving();
|
||||
}
|
||||
|
||||
d->launcher->setSwitchTabsOnHover(switchTabsOnHover);
|
||||
d->launcher->setShowAppsByName(showAppsByName);
|
||||
d->launcher->setShowRecentlyInstalled(showRecentlyInstalled);
|
||||
}
|
||||
|
||||
QList<QAction*> LauncherApplet::contextualActions()
|
||||
{
|
||||
return d->actions;
|
||||
}
|
||||
|
||||
QWidget *LauncherApplet::widget()
|
||||
{
|
||||
d->createLauncher();
|
||||
return d->launcher;
|
||||
}
|
||||
|
||||
void LauncherApplet::saveConfigurationFromSimpleLauncher(const KConfigGroup & configGroup, const KConfigGroup & globalConfigGroup)
|
||||
{
|
||||
//Copy configuration values
|
||||
KConfigGroup cg = config();
|
||||
configGroup.copyTo(&cg);
|
||||
|
||||
KConfigGroup gcg = globalConfig();
|
||||
globalConfigGroup.copyTo(&gcg);
|
||||
|
||||
configChanged();
|
||||
emit configNeedsSaving();
|
||||
}
|
||||
|
||||
#include "moc_applet.cpp"
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef APPLET_H
|
||||
#define APPLET_H
|
||||
|
||||
// KDE
|
||||
|
||||
// Plasma
|
||||
#include <Plasma/PopupApplet>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
class Launcher;
|
||||
}
|
||||
namespace Plasma
|
||||
{
|
||||
}
|
||||
|
||||
class LauncherApplet : public Plasma::PopupApplet
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LauncherApplet(QObject *parent, const QVariantList &args);
|
||||
virtual ~LauncherApplet();
|
||||
|
||||
void init();
|
||||
|
||||
void constraintsEvent(Plasma::Constraints constraints);
|
||||
|
||||
virtual QList<QAction*> contextualActions();
|
||||
|
||||
QWidget *widget();
|
||||
|
||||
public slots:
|
||||
void switchMenuStyle();
|
||||
void startMenuEditor();
|
||||
void toolTipAboutToShow();
|
||||
void configChanged();
|
||||
|
||||
/**
|
||||
* Save config values stored on SimpleLauncher after a menu switch
|
||||
*/
|
||||
void saveConfigurationFromSimpleLauncher(const KConfigGroup & configGroup,
|
||||
const KConfigGroup & globalConfigGroup);
|
||||
|
||||
protected slots:
|
||||
void configAccepted();
|
||||
//void toggleMenu();
|
||||
//void toggleMenu(bool pressed);
|
||||
|
||||
protected:
|
||||
|
||||
void createConfigurationInterface(KConfigDialog *parent);
|
||||
void popupEvent(bool show);
|
||||
|
||||
private:
|
||||
friend class Kickoff::Launcher;
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
K_EXPORT_PLASMA_APPLET(launcher, LauncherApplet)
|
||||
|
||||
#endif
|
|
@ -1,126 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>kickoffConfig</class>
|
||||
<widget class="QWidget" name="kickoffConfig">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="2">
|
||||
<widget class="KIconButton" name="iconButton"/>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QCheckBox" name="switchOnHoverCheckBox">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Show applications by &name:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>appsByNameCheckBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="appsByNameCheckBox">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>131</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>204</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="iconLabel">
|
||||
<property name="text">
|
||||
<string>&Icon:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>iconButton</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Switch &tabs on hover:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>switchOnHoverCheckBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QCheckBox" name="showRecentlyInstalledCheckBox">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Show 'Recently Installed':</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>showRecentlyInstalledCheckBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KIconButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kicondialog.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -1,708 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Pino Toscano <pino@kde.org>
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "applicationmodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QtCore/qalgorithms.h>
|
||||
#include <QtCore/QList>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QLayout>
|
||||
#include <QtGui/QCheckBox>
|
||||
|
||||
// KDE
|
||||
#include <khistorycombobox.h>
|
||||
#include <kdesktopfile.h>
|
||||
#include <klineedit.h>
|
||||
#include <klocale.h>
|
||||
#include <kiconloader.h>
|
||||
#include <krun.h>
|
||||
#include <kstandarddirs.h>
|
||||
#include <kstringhandler.h>
|
||||
#include <kmimetypetrader.h>
|
||||
#include <kurlcompletion.h>
|
||||
#include <kurlrequester.h>
|
||||
#include <kmimetype.h>
|
||||
#include <kservicegroup.h>
|
||||
#include <ksycoca.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <kconfiggroup.h>
|
||||
#include "kickoffadaptor.h"
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
|
||||
#include <Plasma/Applet>
|
||||
|
||||
template <> inline
|
||||
void KConfigGroup::writeEntry(const char *pKey,
|
||||
const KGlobalSettings::Completion& aValue,
|
||||
KConfigBase::WriteConfigFlags flags)
|
||||
{
|
||||
writeEntry(pKey, int(aValue), flags);
|
||||
}
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class AppNode
|
||||
{
|
||||
public:
|
||||
AppNode()
|
||||
: parent(0),
|
||||
fetched(false),
|
||||
isDir(false),
|
||||
isSeparator(false),
|
||||
subTitleMandatory(false)
|
||||
{
|
||||
}
|
||||
|
||||
~AppNode()
|
||||
{
|
||||
qDeleteAll(children);
|
||||
}
|
||||
|
||||
QList<AppNode*> children;
|
||||
|
||||
QIcon icon;
|
||||
QString iconName;
|
||||
QString genericName;
|
||||
QString appName;
|
||||
QString relPath;
|
||||
QString desktopEntry;
|
||||
|
||||
AppNode *parent;
|
||||
DisplayOrder displayOrder;
|
||||
bool fetched : 1;
|
||||
bool isDir : 1;
|
||||
bool isSeparator : 1;
|
||||
bool subTitleMandatory : 1;
|
||||
};
|
||||
|
||||
class ApplicationModelPrivate
|
||||
{
|
||||
public:
|
||||
ApplicationModelPrivate(ApplicationModel *qq, bool _allowSeparators)
|
||||
: q(qq),
|
||||
root(new AppNode()),
|
||||
duplicatePolicy(ApplicationModel::ShowDuplicatesPolicy),
|
||||
systemApplicationPolicy(ApplicationModel::ShowApplicationAndSystemPolicy),
|
||||
primaryNamePolicy(ApplicationModel::GenericNamePrimary),
|
||||
displayOrder(NameAfterDescription),
|
||||
allowSeparators(_allowSeparators),
|
||||
showRecentlyInstalled(true)
|
||||
{
|
||||
systemApplications = Kickoff::systemApplicationList();
|
||||
reloadTimer = new QTimer(qq);
|
||||
reloadTimer->setSingleShot(true);
|
||||
QObject::connect(reloadTimer, SIGNAL(timeout()), qq, SLOT(delayedReloadMenu()));
|
||||
}
|
||||
|
||||
~ApplicationModelPrivate()
|
||||
{
|
||||
delete root;
|
||||
}
|
||||
|
||||
void fillNode(const QString &relPath, AppNode *node);
|
||||
static QHash<QString, QString> iconNameMap();
|
||||
|
||||
ApplicationModel *q;
|
||||
QWeakPointer<Plasma::Applet> applet;
|
||||
AppNode *root;
|
||||
ApplicationModel::DuplicatePolicy duplicatePolicy;
|
||||
ApplicationModel::SystemApplicationPolicy systemApplicationPolicy;
|
||||
ApplicationModel::PrimaryNamePolicy primaryNamePolicy;
|
||||
QStringList systemApplications;
|
||||
DisplayOrder displayOrder;
|
||||
bool allowSeparators;
|
||||
bool showRecentlyInstalled;
|
||||
QTimer *reloadTimer;
|
||||
|
||||
QStringList newInstalledPrograms;
|
||||
QHash<QString, QDate> seenPrograms;
|
||||
};
|
||||
|
||||
void ApplicationModelPrivate::fillNode(const QString &_relPath, AppNode *node)
|
||||
{
|
||||
if (_relPath=="new/") {
|
||||
Q_FOREACH (const QString &it, newInstalledPrograms) {
|
||||
KService::Ptr p = KService::serviceByStorageId(it);
|
||||
|
||||
if (p->noDisplay()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AppNode *newnode = new AppNode();
|
||||
newnode->icon = KIcon(p->icon());
|
||||
newnode->appName = p->name();
|
||||
newnode->genericName = p->genericName();
|
||||
newnode->desktopEntry = p->entryPath();
|
||||
newnode->parent = node;
|
||||
node->children.append(newnode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
KServiceGroup::Ptr root = KServiceGroup::group(_relPath);
|
||||
|
||||
if (!root || !root->isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const KServiceGroup::List list = root->entries(true /* sorted */,
|
||||
true /* exclude no display entries */,
|
||||
allowSeparators /* allow separators */,
|
||||
primaryNamePolicy == ApplicationModel::GenericNamePrimary /* sort by generic name */);
|
||||
|
||||
// application name <-> service map for detecting duplicate entries
|
||||
QHash<QString, KService::Ptr> existingServices;
|
||||
|
||||
// generic name <-> node mapping to determinate duplicate generic names
|
||||
QHash<QString,QList<AppNode*> > genericNames;
|
||||
|
||||
for (KServiceGroup::List::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) {
|
||||
QString icon;
|
||||
QString appName;
|
||||
QString genericName;
|
||||
QString relPath = _relPath;
|
||||
QString desktopEntry;
|
||||
bool isDir = false;
|
||||
bool isSeparator = false;
|
||||
const KSycocaEntry::Ptr p = (*it);
|
||||
|
||||
if (p->isType(KST_KService)) {
|
||||
const KService::Ptr service = KService::Ptr::staticCast(p);
|
||||
|
||||
if (service->noDisplay()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
icon = service->icon();
|
||||
appName = service->name();
|
||||
genericName = service->genericName();
|
||||
desktopEntry = service->entryPath();
|
||||
|
||||
// check for duplicates (eg. KDE 3 and KDE 4 versions of application
|
||||
// both present)
|
||||
if (duplicatePolicy == ApplicationModel::ShowLatestOnlyPolicy &&
|
||||
existingServices.contains(appName)) {
|
||||
if (Kickoff::isLaterVersion(existingServices[appName], service)) {
|
||||
continue;
|
||||
} else {
|
||||
// find and remove the existing entry with the same name
|
||||
for (int i = node->children.count() - 1; i >= 0; --i) {
|
||||
AppNode *app = node->children.at(i);
|
||||
if (app->appName == appName &&
|
||||
app->genericName == genericName &&
|
||||
app->iconName == icon) {
|
||||
app = node->children.takeAt(i);
|
||||
const QString s = app->genericName.toLower();
|
||||
if (genericNames.contains(s)) {
|
||||
QList<AppNode*> list = genericNames[s];
|
||||
for (int j = list.count() - 1; j >= 0; --j) {
|
||||
if(list.at(j) == app) {
|
||||
list.takeAt(j);
|
||||
}
|
||||
}
|
||||
genericNames[s] = list;
|
||||
}
|
||||
delete app;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (systemApplicationPolicy == ApplicationModel::ShowSystemOnlyPolicy &&
|
||||
systemApplications.contains(service->desktopEntryName())) {
|
||||
// don't duplicate applications that are configured to appear in the System tab
|
||||
// in the Applications tab
|
||||
continue;
|
||||
}
|
||||
|
||||
existingServices[appName] = service;
|
||||
} else if (p->isType(KST_KServiceGroup)) {
|
||||
const KServiceGroup::Ptr serviceGroup = KServiceGroup::Ptr::staticCast(p);
|
||||
|
||||
if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
kDebug() << "Service group" << serviceGroup->entryPath() << serviceGroup->icon()
|
||||
<< serviceGroup->relPath() << serviceGroup->directoryEntryPath();
|
||||
|
||||
icon = serviceGroup->icon();
|
||||
if (iconNameMap().contains(icon)) {
|
||||
icon = iconNameMap().value(icon);
|
||||
}
|
||||
|
||||
desktopEntry = serviceGroup->entryPath();
|
||||
genericName = serviceGroup->caption();
|
||||
relPath = serviceGroup->relPath();
|
||||
appName = serviceGroup->comment();
|
||||
isDir = true;
|
||||
} else if (p->isType(KST_KServiceSeparator)) {
|
||||
isSeparator = true;
|
||||
} else {
|
||||
kWarning() << "KServiceGroup: Unexpected object in list!";
|
||||
continue;
|
||||
}
|
||||
|
||||
AppNode *newnode = new AppNode();
|
||||
newnode->iconName = icon;
|
||||
newnode->icon = KIcon(icon);
|
||||
newnode->appName = appName;
|
||||
newnode->genericName = genericName;
|
||||
newnode->relPath = relPath;
|
||||
newnode->desktopEntry = desktopEntry;
|
||||
newnode->isDir = isDir;
|
||||
newnode->isSeparator = isSeparator;
|
||||
newnode->parent = node;
|
||||
node->children.append(newnode);
|
||||
|
||||
if (p->isType(KST_KService)) {
|
||||
const QString s = genericName.toLower();
|
||||
QList<AppNode*> list = genericNames.value(s);
|
||||
list.append(newnode);
|
||||
genericNames[s] = list;
|
||||
}
|
||||
}
|
||||
|
||||
if (showRecentlyInstalled && _relPath.isEmpty() && !newInstalledPrograms.isEmpty()) {
|
||||
AppNode *newnode = new AppNode();
|
||||
newnode->icon = KIcon("chronometer");
|
||||
newnode->appName = i18n("Recently Installed");
|
||||
newnode->relPath = "new/";
|
||||
newnode->isDir = true;
|
||||
newnode->parent = node;
|
||||
node->children.prepend(newnode);
|
||||
}
|
||||
|
||||
// set the subTitleMandatory field for nodes that do not provide a unique generic
|
||||
// name what may help us on display to show in such cases also the subtitle to
|
||||
// provide a hint to the user what the duplicate entries are about.
|
||||
foreach (const QList<AppNode*> &list, genericNames) {
|
||||
if (list.count() > 1) {
|
||||
foreach (AppNode* n, list) {
|
||||
n->subTitleMandatory = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationModel::ApplicationModel(QObject *parent, bool allowSeparators)
|
||||
: KickoffAbstractModel(parent),
|
||||
d(new ApplicationModelPrivate(this, allowSeparators))
|
||||
{
|
||||
QDBusConnection dbus = QDBusConnection::sessionBus();
|
||||
(void)new KickoffAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject("/kickoff", this);
|
||||
dbus.connect(QString(), "/kickoff", "org.kde.plasma", "reloadMenu", this, SLOT(reloadMenu()));
|
||||
connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), this, SLOT(checkSycocaChange(QStringList)));
|
||||
}
|
||||
|
||||
ApplicationModel::~ApplicationModel()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool ApplicationModel::canFetchMore(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid())
|
||||
return false;
|
||||
|
||||
AppNode *node = static_cast<AppNode*>(parent.internalPointer());
|
||||
return node->isDir && !node->fetched;
|
||||
}
|
||||
|
||||
void ApplicationModel::setNameDisplayOrder(DisplayOrder displayOrder)
|
||||
{
|
||||
d->displayOrder = displayOrder;
|
||||
}
|
||||
|
||||
DisplayOrder ApplicationModel::nameDisplayOrder() const
|
||||
{
|
||||
return d->displayOrder;
|
||||
}
|
||||
|
||||
void ApplicationModel::setShowRecentlyInstalled(bool showRecentlyInstalled)
|
||||
{
|
||||
if (d->showRecentlyInstalled != showRecentlyInstalled) {
|
||||
d->showRecentlyInstalled = showRecentlyInstalled;
|
||||
reloadMenu();
|
||||
}
|
||||
}
|
||||
|
||||
bool ApplicationModel::showRecentlyInstalled() const
|
||||
{
|
||||
return d->showRecentlyInstalled;
|
||||
}
|
||||
|
||||
int ApplicationModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ApplicationModel::nameAfterDescription(const QModelIndex &index) const
|
||||
{
|
||||
AppNode *node = static_cast<AppNode*>(index.internalPointer());
|
||||
if (node->isDir) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QModelIndex parent = index.parent();
|
||||
while (parent.parent().isValid()) {
|
||||
parent = parent.parent();
|
||||
}
|
||||
|
||||
if (parent.isValid()) {
|
||||
// nasty little hack to always makes games show their unique name
|
||||
// there is no such thing as a "generic name" for a game in practice
|
||||
// though this is apparently quite true for all other kinds of apps
|
||||
AppNode *node = static_cast<AppNode*>(parent.internalPointer());
|
||||
if (node->isDir && node->genericName == i18n("Games")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return d->displayOrder == NameAfterDescription;
|
||||
}
|
||||
|
||||
QVariant ApplicationModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
AppNode *node = static_cast<AppNode*>(index.internalPointer());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (nameAfterDescription(index) && !node->genericName.isEmpty()) {
|
||||
return node->genericName;
|
||||
}
|
||||
return node->appName;
|
||||
case Kickoff::SubTitleRole:
|
||||
if (!nameAfterDescription(index) && !node->genericName.isEmpty()) {
|
||||
return node->genericName;
|
||||
}
|
||||
return node->appName;
|
||||
case Kickoff::UrlRole:
|
||||
if (node->isDir) {
|
||||
return QString();
|
||||
}
|
||||
return node->desktopEntry;
|
||||
case Kickoff::SubTitleMandatoryRole:
|
||||
return nameAfterDescription(index) && node->subTitleMandatory;
|
||||
case Kickoff::SeparatorRole:
|
||||
return node->isSeparator;
|
||||
case Qt::DecorationRole:
|
||||
return node->icon;
|
||||
case Kickoff::RelPathRole:
|
||||
return node->relPath;
|
||||
case Kickoff::IconNameRole:
|
||||
return node->iconName;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ApplicationModel::fetchMore(const QModelIndex &parent)
|
||||
{
|
||||
if (!parent.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AppNode *node = static_cast<AppNode*>(parent.internalPointer());
|
||||
if (!node->isDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit layoutAboutToBeChanged();
|
||||
d->fillNode(node->relPath, node);
|
||||
node->fetched = true;
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
bool ApplicationModel::hasChildren(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AppNode *node = static_cast<AppNode*>(parent.internalPointer());
|
||||
return node->isDir;
|
||||
}
|
||||
|
||||
QVariant ApplicationModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal || section != 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return i18n("All Applications");
|
||||
break;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex ApplicationModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (row < 0 || column != 0)
|
||||
return QModelIndex();
|
||||
|
||||
AppNode *node = d->root;
|
||||
if (parent.isValid())
|
||||
node = static_cast<AppNode*>(parent.internalPointer());
|
||||
|
||||
if (row >= node->children.count())
|
||||
return QModelIndex();
|
||||
else
|
||||
return createIndex(row, 0, node->children.at(row));
|
||||
}
|
||||
|
||||
QModelIndex ApplicationModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
AppNode *node = static_cast<AppNode*>(index.internalPointer());
|
||||
if (node->parent->parent) {
|
||||
int id = node->parent->parent->children.indexOf(node->parent);
|
||||
|
||||
if (id >= 0 && id < node->parent->parent->children.count()) {
|
||||
return createIndex(id, 0, node->parent);
|
||||
}
|
||||
}
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int ApplicationModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid()) {
|
||||
return d->root->children.count();
|
||||
}
|
||||
|
||||
AppNode *node = static_cast<AppNode*>(parent.internalPointer());
|
||||
return node->children.count();
|
||||
}
|
||||
|
||||
void ApplicationModel::setDuplicatePolicy(DuplicatePolicy policy)
|
||||
{
|
||||
if (d->duplicatePolicy != policy) {
|
||||
d->duplicatePolicy = policy;
|
||||
reloadMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::setSystemApplicationPolicy(SystemApplicationPolicy policy)
|
||||
{
|
||||
if (d->systemApplicationPolicy != policy) {
|
||||
d->systemApplicationPolicy = policy;
|
||||
reloadMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::setPrimaryNamePolicy(PrimaryNamePolicy policy)
|
||||
{
|
||||
if (policy != d->primaryNamePolicy) {
|
||||
d->primaryNamePolicy = policy;
|
||||
reloadMenu();
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationModel::PrimaryNamePolicy ApplicationModel::primaryNamePolicy() const
|
||||
{
|
||||
return d->primaryNamePolicy;
|
||||
}
|
||||
|
||||
void ApplicationModel::delayedReloadMenu()
|
||||
{
|
||||
if (!d->reloadTimer->isActive()) {
|
||||
d->reloadTimer->start(200);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::reloadMenu()
|
||||
{
|
||||
delete d->root;
|
||||
d->root = new AppNode();
|
||||
createNewProgramList();
|
||||
d->fillNode(QString(), d->root);
|
||||
reset();
|
||||
}
|
||||
|
||||
void ApplicationModel::checkSycocaChange(const QStringList &changes)
|
||||
{
|
||||
if (changes.contains("services") || changes.contains("apps") || changes.contains("xdgdata-apps")) {
|
||||
reloadMenu();
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationModel::DuplicatePolicy ApplicationModel::duplicatePolicy() const
|
||||
{
|
||||
return d->duplicatePolicy;
|
||||
}
|
||||
|
||||
ApplicationModel::SystemApplicationPolicy ApplicationModel::systemApplicationPolicy() const
|
||||
{
|
||||
return d->systemApplicationPolicy;
|
||||
}
|
||||
|
||||
void ApplicationModel::setApplet(Plasma::Applet *applet)
|
||||
{
|
||||
if (d->applet.data() != applet) {
|
||||
d->applet = applet;
|
||||
createNewProgramList();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::createNewProgramList()
|
||||
{
|
||||
if (!d->applet) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->newInstalledPrograms.clear();
|
||||
if (!d->showRecentlyInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
KConfigGroup kickoffrc = d->applet.data()->globalConfig();
|
||||
foreach (const QString &it, kickoffrc.keyList()) {
|
||||
d->seenPrograms.insert(it, QDate::fromString(kickoffrc.readEntry(it), Qt::ISODate));
|
||||
}
|
||||
|
||||
bool initialize = (d->seenPrograms.isEmpty());
|
||||
|
||||
bool seenProgramsChanged = createNewProgramListForPath(QString());
|
||||
|
||||
if (initialize) {
|
||||
// on first start, set all entries' dates to empty (means: they are not new)
|
||||
for (QHash<QString, QDate>::Iterator it = d->seenPrograms.begin(); it != d->seenPrograms.end(); ++it)
|
||||
*it = QDate();
|
||||
|
||||
d->newInstalledPrograms.clear();
|
||||
}
|
||||
|
||||
if (seenProgramsChanged) {
|
||||
for (QHash<QString, QDate>::Iterator it = d->seenPrograms.begin(); it != d->seenPrograms.end(); ++it) {
|
||||
kickoffrc.writeEntry(it.key(), it.value().toString(Qt::ISODate));
|
||||
}
|
||||
kickoffrc.sync();
|
||||
}
|
||||
}
|
||||
|
||||
bool ApplicationModel::createNewProgramListForPath(const QString &relPath)
|
||||
{
|
||||
bool seenProgramsChanged = false;
|
||||
|
||||
KServiceGroup::Ptr group = KServiceGroup::group(relPath);
|
||||
if (!group || !group->isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const KServiceGroup::List list = group->entries();
|
||||
|
||||
KServiceGroup::List::ConstIterator it = list.begin();
|
||||
for (; it != list.end(); ++it) {
|
||||
KSycocaEntry::Ptr e = (*it);
|
||||
|
||||
if (e->isType(KST_KServiceGroup)) {
|
||||
KServiceGroup::Ptr g(KServiceGroup::Ptr::staticCast(e));
|
||||
if (!g->noDisplay()) {
|
||||
if (createNewProgramListForPath(g->relPath()))
|
||||
seenProgramsChanged = true;
|
||||
}
|
||||
} else if (e->isType(KST_KService)) {
|
||||
KService::Ptr s(KService::Ptr::staticCast(e));
|
||||
if (s->isApplication() && !s->noDisplay()) {
|
||||
QString shortStorageId = s->storageId().remove(".desktop");
|
||||
QHash<QString, QDate>::Iterator it_find = d->seenPrograms.find(shortStorageId);
|
||||
if (it_find == d->seenPrograms.end()) {
|
||||
seenProgramsChanged = true;
|
||||
d->seenPrograms.insert(shortStorageId, QDate::currentDate());
|
||||
if (!d->newInstalledPrograms.contains(s->storageId())) {
|
||||
d->newInstalledPrograms += s->storageId();
|
||||
}
|
||||
}
|
||||
else {
|
||||
QDate date = it_find.value();
|
||||
if (date.isValid()) {
|
||||
if (date.daysTo(QDate::currentDate()) < 3) {
|
||||
if (!d->newInstalledPrograms.contains(s->storageId())) {
|
||||
d->newInstalledPrograms += s->storageId();
|
||||
}
|
||||
}
|
||||
else {
|
||||
seenProgramsChanged = true;
|
||||
(*it_find) = QDate(); // this entry is not new anymore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return seenProgramsChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME This is a temporary workaround to map the icon names found
|
||||
* in the desktop directory files (from /usr/share/desktop-directories)
|
||||
* into the Oxygen icon names. (Only applies if the Gnome menu files
|
||||
* are also installed)
|
||||
*
|
||||
* This list was compiled from Kubuntu 7.04 with the gnome-menus
|
||||
* package present.
|
||||
*
|
||||
* This needs to be discussed on kde-core-devel and fixed
|
||||
*/
|
||||
QHash<QString, QString> ApplicationModelPrivate::iconNameMap()
|
||||
{
|
||||
static QHash<QString, QString> map;
|
||||
if (map.isEmpty()) {
|
||||
map.insert("gnome-util", "applications-accessories");
|
||||
// accessibility Oxygen icon was missing when this list was compiled
|
||||
map.insert("accessibility-directory", "applications-other");
|
||||
map.insert("gnome-devel", "applications-development");
|
||||
map.insert("package_edutainment", "applications-education");
|
||||
map.insert("gnome-joystick", "applications-games");
|
||||
map.insert("gnome-graphics", "applications-graphics");
|
||||
map.insert("gnome-globe", "applications-internet");
|
||||
map.insert("gnome-multimedia", "applications-multimedia");
|
||||
map.insert("gnome-applications", "applications-office");
|
||||
map.insert("gnome-system", "applications-system");
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
} // namespace Kickoff
|
||||
|
||||
|
||||
#include "moc_applicationmodel.cpp"
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Pino Toscano <pino@kde.org>
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef APPLICATIONMODEL_H
|
||||
#define APPLICATIONMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
#include "core/kickoffabstractmodel.h"
|
||||
#include "core/models.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
class Applet;
|
||||
} // namespace Plasma
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class ApplicationModelPrivate;
|
||||
|
||||
/**
|
||||
* ApplicationModel provides a tree model containing all of the user's installed graphical programs.
|
||||
* The applications are arranged into categories, based on the information in their .desktop files.
|
||||
*/
|
||||
class KICKOFF_EXPORT ApplicationModel : public KickoffAbstractModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ApplicationModel(QObject *parent = 0, bool allowSeparators = false);
|
||||
virtual ~ApplicationModel();
|
||||
|
||||
/**
|
||||
* This enum describes the policy for
|
||||
* handling duplicate applications (that is,
|
||||
* two applications with the same name in the same group)
|
||||
*/
|
||||
enum DuplicatePolicy {
|
||||
/** Display duplicate entries. */
|
||||
ShowDuplicatesPolicy,
|
||||
/**
|
||||
* Show only the entry for the most recent
|
||||
* version of the application.
|
||||
*
|
||||
* Currently only a crude heuristic to determine whether the
|
||||
* application is from KDE 3 or KDE 4 is used to determine
|
||||
* recent-ness.
|
||||
*
|
||||
* eg. If MyGame/KDE 3 and MyGame/KDE 4 are found
|
||||
* show only MyGame/KDE 4
|
||||
*/
|
||||
ShowLatestOnlyPolicy
|
||||
};
|
||||
|
||||
/**
|
||||
* This enum describes the policy for
|
||||
* handling applications that are configured to appear
|
||||
* in the System tab.
|
||||
*/
|
||||
enum SystemApplicationPolicy {
|
||||
/** Display entries in Applications tab and System tab. */
|
||||
ShowApplicationAndSystemPolicy,
|
||||
/** Display entry only in System tab. */
|
||||
ShowSystemOnlyPolicy
|
||||
};
|
||||
|
||||
enum PrimaryNamePolicy {
|
||||
AppNamePrimary,
|
||||
GenericNamePrimary
|
||||
};
|
||||
|
||||
void setNameDisplayOrder(DisplayOrder displayOrder);
|
||||
DisplayOrder nameDisplayOrder() const;
|
||||
//DisplayOrder m_displayOrder;
|
||||
/**
|
||||
* Sets the policy for handling duplicate applications.
|
||||
* See DuplicatePolicy
|
||||
*/
|
||||
void setDuplicatePolicy(DuplicatePolicy policy);
|
||||
/** See setDuplicatePolicy() */
|
||||
DuplicatePolicy duplicatePolicy() const;
|
||||
|
||||
/**
|
||||
* Sets the policy for handling System applications.
|
||||
* See SystemApplicationPolicy
|
||||
*/
|
||||
void setSystemApplicationPolicy(SystemApplicationPolicy policy);
|
||||
/** See setSystemApplicationPolicy() */
|
||||
SystemApplicationPolicy systemApplicationPolicy() const;
|
||||
|
||||
void setPrimaryNamePolicy(PrimaryNamePolicy policy);
|
||||
PrimaryNamePolicy primaryNamePolicy() const;
|
||||
|
||||
// reimplemented from QAbstractItemModel
|
||||
virtual bool canFetchMore(const QModelIndex &parent) const;
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
virtual void fetchMore(const QModelIndex &parent);
|
||||
virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QModelIndex parent(const QModelIndex &index) const;
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
void setApplet(Plasma::Applet *applet);
|
||||
void setShowRecentlyInstalled(bool showRecentlyInstalled);
|
||||
bool showRecentlyInstalled() const;
|
||||
|
||||
public slots:
|
||||
void reloadMenu();
|
||||
void delayedReloadMenu();
|
||||
void checkSycocaChange(const QStringList &changes);
|
||||
|
||||
private:
|
||||
bool nameAfterDescription(const QModelIndex &index) const;
|
||||
|
||||
friend class ApplicationModelPrivate;
|
||||
ApplicationModelPrivate *const d;
|
||||
|
||||
void createNewProgramList();
|
||||
bool createNewProgramListForPath(const QString &relPath);
|
||||
|
||||
Q_DISABLE_COPY(ApplicationModel)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,351 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
//Own
|
||||
#include "core/favoritesmodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QMimeData>
|
||||
#include <QFileInfo>
|
||||
#include <QUrl>
|
||||
|
||||
// KDE
|
||||
#include <KConfigGroup>
|
||||
#include <KService>
|
||||
#include <KDesktopFile>
|
||||
#include <kdebug.h>
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
class FavoritesModel::Private
|
||||
{
|
||||
public:
|
||||
Private(FavoritesModel *parent)
|
||||
: q(parent),
|
||||
displayOrder(NameAfterDescription)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
headerItem = new QStandardItem(i18n("Favorites"));
|
||||
q->appendRow(headerItem);
|
||||
}
|
||||
|
||||
void addFavoriteItem(const QString& url)
|
||||
{
|
||||
QStandardItem *item = StandardItemFactory::createItemForUrl(url, displayOrder);
|
||||
headerItem->appendRow(item);
|
||||
}
|
||||
|
||||
void moveFavoriteItem(int startRow, int destRow)
|
||||
{
|
||||
if (destRow == startRow) {
|
||||
return;
|
||||
}
|
||||
|
||||
QStandardItem *item = headerItem->takeChild(startRow);
|
||||
|
||||
headerItem->removeRow(startRow);
|
||||
headerItem->insertRow(destRow, item);
|
||||
}
|
||||
|
||||
void removeFavoriteItem(const QString& url)
|
||||
{
|
||||
QModelIndexList matches = q->match(q->index(0, 0), UrlRole,
|
||||
url, -1,
|
||||
Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap | Qt::MatchRecursive));
|
||||
|
||||
kDebug() << "Removing item matches" << matches;
|
||||
|
||||
foreach (const QModelIndex& index, matches) {
|
||||
QStandardItem *item = q->itemFromIndex(index);
|
||||
if (item->parent()) {
|
||||
item->parent()->removeRow(item->row());
|
||||
} else {
|
||||
qDeleteAll(q->takeRow(item->row()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void loadFavorites()
|
||||
{
|
||||
globalFavoriteList.clear();
|
||||
globalFavoriteSet.clear();
|
||||
|
||||
KConfigGroup favoritesGroup = componentData().config()->group("Favorites");
|
||||
QList<QString> favoriteList = favoritesGroup.readEntry("FavoriteURLs", QList<QString>());
|
||||
if (favoriteList.isEmpty()) {
|
||||
favoriteList = defaultFavorites();
|
||||
}
|
||||
|
||||
foreach (const QString &favorite, favoriteList) {
|
||||
FavoritesModel::add(favorite);
|
||||
}
|
||||
}
|
||||
|
||||
static QList<QString> defaultFavorites()
|
||||
{
|
||||
QList<QString> applications;
|
||||
applications << "konsole" << "dolphin" << "systemsettings";
|
||||
|
||||
QList<QString> desktopFiles;
|
||||
|
||||
foreach (const QString& application, applications) {
|
||||
KService::Ptr service = KService::serviceByStorageId(application + ".desktop");
|
||||
if (service) {
|
||||
desktopFiles << service->entryPath();
|
||||
}
|
||||
}
|
||||
|
||||
return desktopFiles;
|
||||
}
|
||||
|
||||
static void saveFavorites()
|
||||
{
|
||||
KConfigGroup favoritesGroup = componentData().config()->group("Favorites");
|
||||
favoritesGroup.writeEntry("FavoriteURLs", globalFavoriteList);
|
||||
favoritesGroup.config()->sync();
|
||||
}
|
||||
|
||||
static QList<QString> globalFavoriteList;
|
||||
static QSet<QString> globalFavoriteSet;
|
||||
static QSet<FavoritesModel*> models;
|
||||
|
||||
FavoritesModel * const q;
|
||||
QStandardItem *headerItem;
|
||||
DisplayOrder displayOrder;
|
||||
};
|
||||
|
||||
QList<QString> FavoritesModel::Private::globalFavoriteList;
|
||||
QSet<QString> FavoritesModel::Private::globalFavoriteSet;
|
||||
QSet<FavoritesModel*> FavoritesModel::Private::models;
|
||||
|
||||
FavoritesModel::FavoritesModel(QObject *parent)
|
||||
: KickoffModel(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
Private::models << this;
|
||||
if (Private::models.count() == 1 && Private::globalFavoriteList.isEmpty()) {
|
||||
Private::loadFavorites();
|
||||
} else {
|
||||
foreach (const QString &url, Private::globalFavoriteList) {
|
||||
d->addFavoriteItem(url);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FavoritesModel::~FavoritesModel()
|
||||
{
|
||||
Private::models.remove(this);
|
||||
|
||||
if (Private::models.isEmpty()) {
|
||||
Private::saveFavorites();
|
||||
}
|
||||
|
||||
delete d;
|
||||
}
|
||||
|
||||
void FavoritesModel::add(const QString& url)
|
||||
{
|
||||
Private::globalFavoriteList << url;
|
||||
Private::globalFavoriteSet << url;
|
||||
|
||||
foreach (FavoritesModel* model, Private::models) {
|
||||
model->d->addFavoriteItem(url);
|
||||
}
|
||||
|
||||
// save after each add in case we crash
|
||||
Private::saveFavorites();
|
||||
}
|
||||
|
||||
void FavoritesModel::move(int startRow, int destRow)
|
||||
{
|
||||
// just move the item
|
||||
Private::globalFavoriteList.move(startRow, destRow);
|
||||
|
||||
foreach (FavoritesModel* model, Private::models) {
|
||||
model->d->moveFavoriteItem(startRow, destRow);
|
||||
}
|
||||
|
||||
// save after each add in case we crash
|
||||
Private::saveFavorites();
|
||||
}
|
||||
|
||||
void FavoritesModel::remove(const QString& url)
|
||||
{
|
||||
Private::globalFavoriteList.removeAll(url);
|
||||
Private::globalFavoriteSet.remove(url);
|
||||
|
||||
foreach (FavoritesModel* model, Private::models) {
|
||||
model->d->removeFavoriteItem(url);
|
||||
}
|
||||
|
||||
// save after each remove in case of crash or other mishaps
|
||||
Private::saveFavorites();
|
||||
}
|
||||
|
||||
bool FavoritesModel::isFavorite(const QString& url)
|
||||
{
|
||||
return Private::globalFavoriteSet.contains(url);
|
||||
}
|
||||
|
||||
int FavoritesModel::numberOfFavorites()
|
||||
{
|
||||
foreach (FavoritesModel* model, Private::models) {
|
||||
return model->d->headerItem->rowCount() - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FavoritesModel::sortFavorites(Qt::SortOrder order)
|
||||
{
|
||||
if(Private::models.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (FavoritesModel *model, Private::models) {
|
||||
model->d->headerItem->sortChildren(0, order);
|
||||
}
|
||||
|
||||
Private::globalFavoriteList.clear();
|
||||
|
||||
FavoritesModel *model = *Private::models.begin();
|
||||
QStandardItem *childData;
|
||||
for (int i = 0; i <= numberOfFavorites(); i++) {
|
||||
childData = model->d->headerItem->child(i, 0);
|
||||
Private::globalFavoriteList.append(childData->data(Kickoff::UrlRole).toString());
|
||||
}
|
||||
|
||||
Private::saveFavorites();
|
||||
}
|
||||
|
||||
void FavoritesModel::sortFavoritesAscending()
|
||||
{
|
||||
sortFavorites(Qt::AscendingOrder);
|
||||
}
|
||||
|
||||
void FavoritesModel::sortFavoritesDescending()
|
||||
{
|
||||
sortFavorites(Qt::DescendingOrder);
|
||||
}
|
||||
|
||||
bool FavoritesModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex & parent)
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
if (action == Qt::IgnoreAction) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (column > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (action == Qt::MoveAction) {
|
||||
QModelIndex modelIndex;
|
||||
QStandardItem *startItem;
|
||||
int startRow = -1;
|
||||
|
||||
int destRow = row;
|
||||
|
||||
// look for the favorite that was dragged
|
||||
for (int i = 0; i < d->headerItem->rowCount(); i++) {
|
||||
startItem = d->headerItem->child(i, 0);
|
||||
if (QFileInfo(startItem->data(Kickoff::UrlRole).toString()).completeBaseName()
|
||||
== QFileInfo(data->text()).completeBaseName()) {
|
||||
startRow = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (startRow < 0) {
|
||||
bool dropped = false;
|
||||
foreach (const QUrl &url, data->urls()) {
|
||||
if (!url.isValid()) {
|
||||
continue;
|
||||
}
|
||||
const QString path = url.toLocalFile();
|
||||
if (!KDesktopFile::isDesktopFile(path)) {
|
||||
continue;
|
||||
}
|
||||
KDesktopFile dFile(path);
|
||||
if (dFile.hasApplicationType() && !dFile.noDisplay()) {
|
||||
FavoritesModel::add(path);
|
||||
dropped = true;
|
||||
}
|
||||
}
|
||||
return dropped;
|
||||
}
|
||||
|
||||
if (destRow < 0)
|
||||
return false;
|
||||
|
||||
// now move the item to it's new location
|
||||
FavoritesModel::move(startRow, destRow);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariant FavoritesModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal || section != 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return i18nc("@title:column", "Favorites");
|
||||
break;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void FavoritesModel::setNameDisplayOrder(DisplayOrder displayOrder)
|
||||
{
|
||||
if (d->displayOrder == displayOrder) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->displayOrder = displayOrder;
|
||||
|
||||
foreach (FavoritesModel* model, Private::models) {
|
||||
model->clear();
|
||||
model->d->init();
|
||||
}
|
||||
|
||||
Private::loadFavorites();
|
||||
}
|
||||
|
||||
DisplayOrder FavoritesModel::nameDisplayOrder() const
|
||||
{
|
||||
return d->displayOrder;
|
||||
}
|
||||
|
||||
#include "moc_favoritesmodel.cpp"
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef FAVORITESMODEL_H
|
||||
#define FAVORITESMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
#include "core/kickoffmodel.h"
|
||||
#include "core/models.h"
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* A model which provides an ordered list of 'favorite' items chosen by the user.
|
||||
* The items may represent documents, folders, applications, devices or anything else
|
||||
* identified by a URL.
|
||||
*
|
||||
* The information persists between sessions.
|
||||
*/
|
||||
class KICKOFF_EXPORT FavoritesModel : public KickoffModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FavoritesModel(QObject *parent);
|
||||
virtual ~FavoritesModel();
|
||||
|
||||
/** Add a new item for @p url to the user's favorites list. */
|
||||
static void add(const QString& url);
|
||||
/** Remove the item associated with @p url from the user's favorites list. */
|
||||
static void remove(const QString& url);
|
||||
/** Returns true if @p url is in the list of the user's favorite URLs. */
|
||||
static void move(int startRow, int destRow);
|
||||
static int numberOfFavorites();
|
||||
static void sortFavorites(Qt::SortOrder order);
|
||||
static bool isFavorite(const QString& url);
|
||||
|
||||
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex & parent);
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
void setNameDisplayOrder(DisplayOrder displayOrder);
|
||||
DisplayOrder nameDisplayOrder() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void sortFavoritesAscending();
|
||||
void sortFavoritesDescending();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FAVORITESMODEL_H
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/itemhandlers.h"
|
||||
|
||||
// Qt
|
||||
#include <QTimer>
|
||||
|
||||
// KDE
|
||||
#include <KDebug>
|
||||
#include <KJob>
|
||||
#include <KService>
|
||||
#include <KRun>
|
||||
#include <KUrl>
|
||||
#include <Solid/PowerManagement>
|
||||
|
||||
// KDE Base
|
||||
#include "kworkspace/kworkspace.h"
|
||||
#include "kworkspace/kdisplaymanager.h"
|
||||
|
||||
// Local
|
||||
#include "core/recentapplications.h"
|
||||
|
||||
// DBus
|
||||
#include "screensaver_interface.h"
|
||||
#include "ksmserver_interface.h"
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusConnectionInterface>
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
bool ServiceItemHandler::openUrl(const KUrl& url)
|
||||
{
|
||||
KService::Ptr service = KService::serviceByDesktopPath(url.pathOrUrl());
|
||||
|
||||
if (!service.isNull()) {
|
||||
RecentApplications::self()->add(service);
|
||||
} else {
|
||||
qWarning() << "Failed to find service for" << url;
|
||||
return false;
|
||||
}
|
||||
|
||||
new KRun(url, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LeaveItemHandler::openUrl(const KUrl& url)
|
||||
{
|
||||
m_logoutAction = url.path().remove('/');
|
||||
|
||||
if (m_logoutAction == "sleep") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(suspendRAM()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "hibernate") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(suspendDisk()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "hybrid") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(suspendHybrid()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "lock") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(lock()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "switch") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(switchUser()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "logout" || m_logoutAction == "logoutonly" ||
|
||||
m_logoutAction == "restart" || m_logoutAction == "shutdown") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(logout()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "savesession") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(saveSession()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "suspendram") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(suspendRAM()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "suspenddisk") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(suspendDisk()));
|
||||
return true;
|
||||
} else if (m_logoutAction == "suspendhybrid") {
|
||||
// decouple dbus call, otherwise we'll run into a dead-lock
|
||||
QTimer::singleShot(0, this, SLOT(suspendHybrid()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LeaveItemHandler::logout()
|
||||
{
|
||||
KWorkSpace::ShutdownConfirm confirm = KWorkSpace::ShutdownConfirmDefault;
|
||||
KWorkSpace::ShutdownType type = KWorkSpace::ShutdownTypeNone;
|
||||
|
||||
if (m_logoutAction == "logout" || m_logoutAction == "logoutonly") {
|
||||
type = KWorkSpace::ShutdownTypeNone;
|
||||
} else if (m_logoutAction == "lock") {
|
||||
kDebug() << "Locking screen";
|
||||
} else if (m_logoutAction == "switch") {
|
||||
kDebug() << "Switching user";
|
||||
} else if (m_logoutAction == "restart") {
|
||||
type = KWorkSpace::ShutdownTypeReboot;
|
||||
} else if (m_logoutAction == "shutdown") {
|
||||
type = KWorkSpace::ShutdownTypeHalt;
|
||||
}
|
||||
|
||||
KWorkSpace::requestShutDown(confirm, type);
|
||||
}
|
||||
|
||||
void LeaveItemHandler::lock()
|
||||
{
|
||||
QString interface("org.freedesktop.ScreenSaver");
|
||||
org::freedesktop::ScreenSaver screensaver(interface, "/ScreenSaver", QDBusConnection::sessionBus());
|
||||
screensaver.Lock();
|
||||
}
|
||||
|
||||
void LeaveItemHandler::switchUser()
|
||||
{
|
||||
QDBusInterface saveriface(
|
||||
"org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver"
|
||||
);
|
||||
saveriface.call("Lock");
|
||||
KDisplayManager dm;
|
||||
dm.newSession();
|
||||
}
|
||||
|
||||
void LeaveItemHandler::saveSession()
|
||||
{
|
||||
QString interface("org.kde.ksmserver");
|
||||
|
||||
org::kde::KSMServerInterface ksmserver(interface, "/KSMServer", QDBusConnection::sessionBus());
|
||||
if (ksmserver.isValid()) {
|
||||
ksmserver.saveCurrentSession();
|
||||
}
|
||||
}
|
||||
|
||||
void LeaveItemHandler::suspendRAM()
|
||||
{
|
||||
Solid::PowerManagement::requestSleep(Solid::PowerManagement::SuspendState);
|
||||
}
|
||||
|
||||
void LeaveItemHandler::suspendDisk()
|
||||
{
|
||||
Solid::PowerManagement::requestSleep(Solid::PowerManagement::HibernateState);
|
||||
}
|
||||
|
||||
void LeaveItemHandler::suspendHybrid()
|
||||
{
|
||||
Solid::PowerManagement::requestSleep(Solid::PowerManagement::HybridSuspendState);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef ITEMHANDLERS_H
|
||||
#define ITEMHANDLERS_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "kickoff_export.h"
|
||||
#include "core/urlitemlauncher.h"
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class KICKOFF_EXPORT ServiceItemHandler : public UrlItemHandler
|
||||
{
|
||||
public:
|
||||
virtual bool openUrl(const KUrl& url);
|
||||
};
|
||||
class KICKOFF_EXPORT LeaveItemHandler : public QObject, public UrlItemHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual bool openUrl(const KUrl& url);
|
||||
|
||||
private Q_SLOTS:
|
||||
void logout();
|
||||
void lock();
|
||||
void switchUser();
|
||||
void saveSession();
|
||||
void suspendRAM();
|
||||
void suspendDisk();
|
||||
void suspendHybrid();
|
||||
|
||||
private:
|
||||
QString m_logoutAction;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ITEMHANDLERS_H
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/kickoffabstractmodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QMimeData>
|
||||
|
||||
// KDE
|
||||
#include <KUrl>
|
||||
#include <KDebug>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
KickoffAbstractModel::KickoffAbstractModel(QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{}
|
||||
|
||||
KickoffAbstractModel::~KickoffAbstractModel()
|
||||
{}
|
||||
|
||||
Qt::ItemFlags KickoffAbstractModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
|
||||
|
||||
if (index.isValid()) {
|
||||
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData *KickoffAbstractModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
KUrl::List urls;
|
||||
QByteArray itemData;
|
||||
|
||||
foreach(const QModelIndex &index, indexes) {
|
||||
KUrl itemUrl = KUrl(data(index, UrlRole).toString());
|
||||
if (itemUrl.isValid()) {
|
||||
urls << itemUrl;
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
|
||||
if (!urls.isEmpty()) {
|
||||
urls.populateMimeData(mimeData);
|
||||
}
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
QStringList KickoffAbstractModel::mimeTypes() const
|
||||
{
|
||||
QStringList types;
|
||||
types << QLatin1String("text/uri-list");
|
||||
return types;
|
||||
}
|
||||
|
||||
Qt::DropActions KickoffAbstractModel::supportedDropActions() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Qt::DropActions KickoffAbstractModel::supportedDragActions() const
|
||||
{
|
||||
return Qt::CopyAction;
|
||||
}
|
||||
|
||||
#include "moc_kickoffabstractmodel.cpp"
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KICKOFFABSTRACTMODEL_H
|
||||
#define KICKOFFABSTRACTMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
|
||||
// Qt
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
// KDE
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* Base model for Kickoff models based on QAbstractItemModel, enables drag and drop support
|
||||
*/
|
||||
class KICKOFF_EXPORT KickoffAbstractModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Construct a new KickoffModel with the specified parent. */
|
||||
KickoffAbstractModel(QObject *parent = 0);
|
||||
virtual ~KickoffAbstractModel();
|
||||
|
||||
//Reimplementations
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
|
||||
virtual QStringList mimeTypes() const;
|
||||
virtual Qt::DropActions supportedDropActions() const;
|
||||
virtual Qt::DropActions supportedDragActions() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // KICKOFFABSTRACTMODEL_H
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/kickoffmodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QMimeData>
|
||||
|
||||
// KDE
|
||||
#include <KUrl>
|
||||
#include <KDebug>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
KickoffModel::KickoffModel(QObject *parent)
|
||||
: QStandardItemModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
KickoffModel::~KickoffModel()
|
||||
{}
|
||||
|
||||
Qt::ItemFlags KickoffModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags defaultFlags = QStandardItemModel::flags(index);
|
||||
|
||||
if (index.isValid()) {
|
||||
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData *KickoffModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
KUrl::List urls;
|
||||
|
||||
foreach (const QModelIndex &index, indexes) {
|
||||
KUrl itemUrl = KUrl(data(index, UrlRole).toString());
|
||||
if (itemUrl.isValid()) {
|
||||
urls << itemUrl;
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
|
||||
if (!urls.isEmpty()) {
|
||||
urls.populateMimeData(mimeData);
|
||||
}
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
QStringList KickoffModel::mimeTypes() const
|
||||
{
|
||||
QStringList types;
|
||||
types << QLatin1String("text/uri-list");
|
||||
return types;
|
||||
}
|
||||
|
||||
Qt::DropActions KickoffModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::MoveAction;
|
||||
}
|
||||
|
||||
Qt::DropActions KickoffModel::supportedDragActions() const
|
||||
{
|
||||
return Qt::CopyAction;
|
||||
}
|
||||
|
||||
#include "moc_kickoffmodel.cpp"
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KICKOFFMODEL_H
|
||||
#define KICKOFFMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
|
||||
// Qt
|
||||
#include <QStandardItemModel>
|
||||
|
||||
// KDE
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* Base model for Kickoff models based on QStandardItemModel, enables drag and drop support
|
||||
*/
|
||||
class KICKOFF_EXPORT KickoffModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Construct a new KickoffModel with the specified parent. */
|
||||
KickoffModel(QObject *parent = 0);
|
||||
virtual ~KickoffModel();
|
||||
|
||||
//Reimplementations
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
|
||||
virtual QStringList mimeTypes() const;
|
||||
virtual Qt::DropActions supportedDropActions() const;
|
||||
virtual Qt::DropActions supportedDragActions() const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // KICKOFFMODEL_H
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/kickoffproxymodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QMimeData>
|
||||
|
||||
// KDE
|
||||
#include <KUrl>
|
||||
#include <KDebug>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
KickoffProxyModel::KickoffProxyModel(QObject *parent)
|
||||
: QAbstractProxyModel(parent)
|
||||
{}
|
||||
|
||||
KickoffProxyModel::~KickoffProxyModel()
|
||||
{}
|
||||
|
||||
Qt::ItemFlags KickoffProxyModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags defaultFlags = QAbstractProxyModel::flags(index);
|
||||
|
||||
if (index.isValid()) {
|
||||
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData *KickoffProxyModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
KUrl::List urls;
|
||||
QByteArray itemData;
|
||||
|
||||
foreach(const QModelIndex &index, indexes) {
|
||||
KUrl itemUrl = KUrl(data(index, UrlRole).toString());
|
||||
if (itemUrl.isValid()) {
|
||||
urls << itemUrl;
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
|
||||
if (!urls.isEmpty()) {
|
||||
urls.populateMimeData(mimeData);
|
||||
}
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
QStringList KickoffProxyModel::mimeTypes() const
|
||||
{
|
||||
QStringList types;
|
||||
types << QLatin1String("text/uri-list");
|
||||
return types;
|
||||
}
|
||||
|
||||
Qt::DropActions KickoffProxyModel::supportedDropActions() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Qt::DropActions KickoffProxyModel::supportedDragActions() const
|
||||
{
|
||||
return Qt::CopyAction;
|
||||
}
|
||||
|
||||
#include "moc_kickoffproxymodel.cpp"
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KICKOFFPROXYMODEL_H
|
||||
#define KICKOFFPROXYMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
|
||||
// Qt
|
||||
#include <QAbstractProxyModel>
|
||||
|
||||
// KDE
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* Base model for Kickoff models based on QAbstractProxyModel, enables drag and drop support
|
||||
*/
|
||||
class KICKOFF_EXPORT KickoffProxyModel : public QAbstractProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Construct a new KickoffModel with the specified parent. */
|
||||
KickoffProxyModel(QObject *parent = 0);
|
||||
virtual ~KickoffProxyModel();
|
||||
|
||||
//Reimplementations
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
|
||||
virtual QStringList mimeTypes() const;
|
||||
virtual Qt::DropActions supportedDropActions() const;
|
||||
virtual Qt::DropActions supportedDragActions() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // KICKOFFPROXYMODEL_H
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
Copyright 2009 Ivan Cukic <ivan.cukic+kde@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/krunnermodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QBasicTimer>
|
||||
#include <QDebug>
|
||||
#include <QList>
|
||||
#include <QMimeData>
|
||||
#include <QString>
|
||||
#include <QtCore/qcoreevent.h>
|
||||
|
||||
// KDE
|
||||
#include <KUrl>
|
||||
#include <KService>
|
||||
#include <KStandardDirs>
|
||||
#include <Plasma/AbstractRunner>
|
||||
|
||||
// Local
|
||||
#include "core/recentapplications.h"
|
||||
|
||||
#define DELAY_TIME 50
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
Plasma::RunnerManager* _runnerManager = nullptr;
|
||||
|
||||
static KService::Ptr serviceForUrl(const KUrl &url)
|
||||
{
|
||||
QString runner = url.host();
|
||||
QString id = url.path();
|
||||
|
||||
if (id.startsWith(QLatin1Char('/'))) {
|
||||
id = id.remove(0, 1);
|
||||
}
|
||||
|
||||
if (runner != QLatin1String("services")) {
|
||||
return KService::Ptr(nullptr);
|
||||
}
|
||||
|
||||
// URL path example: services_kde4-kate.desktop
|
||||
// or: services_firefox.desktop
|
||||
id.remove("services_");
|
||||
|
||||
return KService::serviceByStorageId(id);
|
||||
}
|
||||
|
||||
bool KRunnerItemHandler::openUrl(const KUrl& url)
|
||||
{
|
||||
QString runner = url.host();
|
||||
QString id = url.path();
|
||||
if (id.startsWith(QLatin1Char('/'))) {
|
||||
id = id.remove(0, 1);
|
||||
}
|
||||
|
||||
// Since krunner:// urls can't be added to recent applications,
|
||||
// we find the local .desktop entry.
|
||||
|
||||
KService::Ptr service = serviceForUrl(url);
|
||||
if (service) {
|
||||
RecentApplications::self()->add(service);
|
||||
} else {
|
||||
qWarning() << "Failed to find service for" << url;
|
||||
}
|
||||
|
||||
KRunnerModel::runnerManager()->run(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
class KRunnerModel::Private {
|
||||
public:
|
||||
QBasicTimer searchDelay;
|
||||
QString searchQuery;
|
||||
DisplayOrder displayOrder;
|
||||
};
|
||||
|
||||
KRunnerModel::KRunnerModel(QObject *parent)
|
||||
: KickoffModel(parent)
|
||||
, d(new Private())
|
||||
{
|
||||
connect(
|
||||
runnerManager(), SIGNAL(matchesChanged(QList<Plasma::QueryMatch>)),
|
||||
this, SLOT(matchesChanged(QList<Plasma::QueryMatch>))
|
||||
);
|
||||
}
|
||||
|
||||
KRunnerModel::~KRunnerModel()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void KRunnerModel::setQuery(const QString& query)
|
||||
{
|
||||
runnerManager()->reset();
|
||||
clear();
|
||||
|
||||
d->searchQuery = query.trimmed();
|
||||
|
||||
if (d->searchQuery.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->searchDelay.start(DELAY_TIME, this);
|
||||
}
|
||||
|
||||
void KRunnerModel::timerEvent(QTimerEvent * event)
|
||||
{
|
||||
KickoffModel::timerEvent(event);
|
||||
|
||||
if (event->timerId() == d->searchDelay.timerId()) {
|
||||
d->searchDelay.stop();
|
||||
runnerManager()->launchQuery(d->searchQuery);
|
||||
};
|
||||
}
|
||||
|
||||
void KRunnerModel::setNameDisplayOrder(DisplayOrder displayOrder)
|
||||
{
|
||||
d->displayOrder = displayOrder;
|
||||
}
|
||||
|
||||
DisplayOrder KRunnerModel::nameDisplayOrder() const
|
||||
{
|
||||
return d->displayOrder;
|
||||
}
|
||||
|
||||
void KRunnerModel::matchesChanged(const QList< Plasma::QueryMatch > & m)
|
||||
{
|
||||
QList< Plasma::QueryMatch > matches = m;
|
||||
|
||||
qSort(matches.begin(), matches.end());
|
||||
|
||||
clear();
|
||||
|
||||
while (matches.size()) {
|
||||
Plasma::QueryMatch match = matches.takeLast();
|
||||
|
||||
appendRow(
|
||||
StandardItemFactory::createItem(
|
||||
match.icon(),
|
||||
match.text(),
|
||||
match.subtext(),
|
||||
QString("krunner://") + match.runner()->id() + "/" + match.id()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Qt::ItemFlags KRunnerModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags flags = KickoffModel::flags(index);
|
||||
|
||||
if (index.isValid()) {
|
||||
KUrl url = data(index, UrlRole).toString();
|
||||
QString host = url.host();
|
||||
if (host != "services") {
|
||||
flags &= ~ (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
}
|
||||
} else {
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
QMimeData * KRunnerModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
KUrl::List urls;
|
||||
|
||||
foreach (const QModelIndex &index, indexes) {
|
||||
KUrl url = data(index, UrlRole).toString();
|
||||
|
||||
KService::Ptr service = serviceForUrl(url);
|
||||
|
||||
if (service) {
|
||||
urls << KUrl(service->entryPath());
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
|
||||
if (!urls.isEmpty()) {
|
||||
urls.populateMimeData(mimeData);
|
||||
}
|
||||
|
||||
return mimeData;
|
||||
|
||||
}
|
||||
|
||||
Plasma::RunnerManager* KRunnerModel::runnerManager()
|
||||
{
|
||||
if (!_runnerManager) {
|
||||
KConfigGroup conf = componentData().config()->group("Plugins");
|
||||
QStringList allowed;
|
||||
foreach (KPluginInfo plugin, Plasma::RunnerManager::listRunnerInfo()) {
|
||||
plugin.load(conf);
|
||||
if (plugin.isPluginEnabled()) {
|
||||
allowed.append(plugin.pluginName());
|
||||
}
|
||||
}
|
||||
// NOTE: Plasma::RunnerManager uses sub-group named PlasmaRunnerManager
|
||||
conf = componentData().config()->group("KRunner");
|
||||
conf.writeEntry("loadAll", false);
|
||||
conf.sync();
|
||||
_runnerManager = new Plasma::RunnerManager(conf);
|
||||
_runnerManager->setAllowedRunners(allowed);
|
||||
}
|
||||
return _runnerManager;
|
||||
}
|
||||
|
||||
|
||||
#include "moc_krunnermodel.cpp"
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
Copyright 2009 Ivan Cukic <ivan.cukic+kde@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KRUNNERMODEL_H
|
||||
#define KRUNNERMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
#include "core/models.h"
|
||||
#include "core/kickoffmodel.h"
|
||||
#include "core/urlitemlauncher.h"
|
||||
|
||||
#include <Plasma/QueryMatch>
|
||||
#include <Plasma/RunnerManager>
|
||||
|
||||
namespace Kickoff {
|
||||
|
||||
class KICKOFF_EXPORT KRunnerItemHandler : public UrlItemHandler {
|
||||
public:
|
||||
virtual bool openUrl(const KUrl& url);
|
||||
};
|
||||
|
||||
class KICKOFF_EXPORT KRunnerModel : public KickoffModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KRunnerModel(QObject *parent);
|
||||
virtual ~KRunnerModel();
|
||||
void setNameDisplayOrder(DisplayOrder displayOrder);
|
||||
DisplayOrder nameDisplayOrder() const;
|
||||
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
|
||||
// virtual QStringList mimeTypes() const;
|
||||
// virtual Qt::DropActions supportedDropActions() const;
|
||||
// virtual Qt::DropActions supportedDragActions() const;
|
||||
|
||||
static Plasma::RunnerManager* runnerManager();
|
||||
private:
|
||||
void timerEvent(QTimerEvent * event);
|
||||
|
||||
public Q_SLOTS:
|
||||
void setQuery(const QString& query);
|
||||
|
||||
private Q_SLOTS:
|
||||
void matchesChanged(const QList< Plasma::QueryMatch > & matches);
|
||||
|
||||
Q_SIGNALS:
|
||||
void resultsAvailable();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // KRUNNERMODEL_H
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/leavemodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QFileInfo>
|
||||
|
||||
// KDE
|
||||
#include <KConfigGroup>
|
||||
#include <KDebug>
|
||||
#include <KIcon>
|
||||
#include <Solid/PowerManagement>
|
||||
#include <kworkspace/kworkspace.h>
|
||||
#include <kworkspace/kdisplaymanager.h>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
QStandardItem* LeaveModel::createStandardItem(const QString& url)
|
||||
{
|
||||
//Q_ASSERT(KUrl(url).scheme() == "leave");
|
||||
QStandardItem *item = new QStandardItem();
|
||||
const QString basename = QFileInfo(url).baseName();
|
||||
if (basename == "logoutonly") {
|
||||
item->setText(i18n("Log out"));
|
||||
item->setIcon(KIcon("system-log-out"));
|
||||
item->setData(i18n("End session"), Kickoff::SubTitleRole);
|
||||
} else if (basename == "lock") {
|
||||
item->setText(i18n("Lock"));
|
||||
item->setIcon(KIcon("system-lock-screen"));
|
||||
item->setData(i18n("Lock screen"), Kickoff::SubTitleRole);
|
||||
} else if (basename == "switch") {
|
||||
item->setText(i18n("Switch user"));
|
||||
item->setIcon(KIcon("system-switch-user"));
|
||||
item->setData(i18n("Start a parallel session as a different user"), Kickoff::SubTitleRole);
|
||||
} else if (basename == "shutdown") {
|
||||
item->setText(i18n("Shut down"));
|
||||
item->setIcon(KIcon("system-shutdown"));
|
||||
item->setData(i18n("Turn off computer"), Kickoff::SubTitleRole);
|
||||
} else if (basename == "restart") {
|
||||
item->setText(i18nc("Restart computer", "Restart"));
|
||||
item->setIcon(KIcon("system-reboot"));
|
||||
item->setData(i18n("Restart computer"), Kickoff::SubTitleRole);
|
||||
} else if (basename == "savesession") {
|
||||
item->setText(i18n("Save Session"));
|
||||
item->setIcon(KIcon("document-save"));
|
||||
item->setData(i18n("Save current session for next login"), Kickoff::SubTitleRole);
|
||||
} else if (basename == "suspenddisk") {
|
||||
item->setText(i18n("Hibernate"));
|
||||
item->setIcon(KIcon("system-suspend-hibernate"));
|
||||
item->setData(i18n("Suspend to disk"), Kickoff::SubTitleRole);
|
||||
} else if (basename == "suspendram") {
|
||||
item->setText(i18n("Sleep"));
|
||||
item->setIcon(KIcon("system-suspend"));
|
||||
item->setData(i18n("Suspend to RAM"), Kickoff::SubTitleRole);
|
||||
} else if (basename == "suspendhybrid") {
|
||||
item->setText(i18n("Hybrid Suspend"));
|
||||
item->setIcon(KIcon("system-suspend"));
|
||||
item->setData(i18n("Hybrid Suspend"), Kickoff::SubTitleRole);
|
||||
} else {
|
||||
item->setText(basename);
|
||||
item->setData(url, Kickoff::SubTitleRole);
|
||||
}
|
||||
item->setData(url, Kickoff::UrlRole);
|
||||
return item;
|
||||
}
|
||||
|
||||
LeaveModel::LeaveModel(QObject *parent)
|
||||
: QStandardItemModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LeaveModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal || section != 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return i18n("Leave");
|
||||
break;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void LeaveModel::updateModel()
|
||||
{
|
||||
clear();
|
||||
|
||||
// Session Options
|
||||
QStandardItem *sessionOptions = new QStandardItem(i18n("Session"));
|
||||
|
||||
// Logout
|
||||
QStandardItem *logoutOption = createStandardItem("leave:/logoutonly");
|
||||
sessionOptions->appendRow(logoutOption);
|
||||
|
||||
// Lock
|
||||
QStandardItem *lockOption = createStandardItem("leave:/lock");
|
||||
sessionOptions->appendRow(lockOption);
|
||||
|
||||
// Save Session
|
||||
KConfigGroup c(KSharedConfig::openConfig("ksmserverrc", KConfig::NoGlobals), "General");
|
||||
if (c.readEntry("loginMode") == "restoreSavedSession") {
|
||||
QStandardItem *saveSessionOption = createStandardItem("leave:/savesession");
|
||||
sessionOptions->appendRow(saveSessionOption);
|
||||
}
|
||||
|
||||
// Switch User
|
||||
if (KDisplayManager().isSwitchable()) {
|
||||
QStandardItem *switchUserOption = createStandardItem("leave:/switch");
|
||||
sessionOptions->appendRow(switchUserOption);
|
||||
}
|
||||
|
||||
// System Options
|
||||
QStandardItem *systemOptions = new QStandardItem(i18n("System"));
|
||||
bool addSystemSession = false;
|
||||
|
||||
QSet< Solid::PowerManagement::SleepState > spdMethods = Solid::PowerManagement::supportedSleepStates();
|
||||
if (spdMethods.contains(Solid::PowerManagement::SuspendState)) {
|
||||
QStandardItem *suspendramOption = createStandardItem("leave:/suspendram");
|
||||
systemOptions->appendRow(suspendramOption);
|
||||
addSystemSession = true;
|
||||
}
|
||||
|
||||
if (spdMethods.contains(Solid::PowerManagement::HibernateState)) {
|
||||
QStandardItem *suspenddiskOption = createStandardItem("leave:/suspenddisk");
|
||||
systemOptions->appendRow(suspenddiskOption);
|
||||
addSystemSession = true;
|
||||
}
|
||||
|
||||
if (spdMethods.contains(Solid::PowerManagement::HybridSuspendState)) {
|
||||
QStandardItem *suspendhybridOption = createStandardItem("leave:/suspendhybrid");
|
||||
systemOptions->appendRow(suspendhybridOption);
|
||||
addSystemSession = true;
|
||||
}
|
||||
|
||||
if (KWorkSpace::canShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeReboot)) {
|
||||
// Restart
|
||||
QStandardItem *restartOption = createStandardItem("leave:/restart");
|
||||
systemOptions->appendRow(restartOption);
|
||||
addSystemSession = true;
|
||||
}
|
||||
|
||||
if (KWorkSpace::canShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeHalt)) {
|
||||
// Shutdown
|
||||
QStandardItem *shutDownOption = createStandardItem("leave:/shutdown");
|
||||
systemOptions->appendRow(shutDownOption);
|
||||
addSystemSession = true;
|
||||
}
|
||||
|
||||
appendRow(sessionOptions);
|
||||
if (addSystemSession) {
|
||||
appendRow(systemOptions);
|
||||
} else {
|
||||
delete systemOptions;
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_leavemodel.cpp"
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef LEAVEMODEL_H
|
||||
#define LEAVEMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class KICKOFF_EXPORT LeaveModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LeaveModel(QObject *parent);
|
||||
|
||||
static QStandardItem* createStandardItem(const QString& url);
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
void updateModel();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LEAVEMODEL_H
|
|
@ -1,216 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/models.h"
|
||||
#include "core/leavemodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QFileInfo>
|
||||
#include <QtGui/qstandarditemmodel.h>
|
||||
#include <QDir>
|
||||
|
||||
// KDE
|
||||
#include <KDebug>
|
||||
#include <KConfigGroup>
|
||||
#include <KDesktopFile>
|
||||
#include <KIcon>
|
||||
#include <KMimeType>
|
||||
#include <KUrl>
|
||||
#include <Solid/Device>
|
||||
#include <Solid/StorageAccess>
|
||||
#include <Solid/StorageDrive>
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(KUrl, homeUrl, (QDir::homePath()))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(KUrl, remoteUrl, ("remote:/"))
|
||||
K_GLOBAL_STATIC(StandardItemFactoryData, factoryData)
|
||||
|
||||
StandardItemFactoryData* deviceFactoryData()
|
||||
{
|
||||
return factoryData;
|
||||
}
|
||||
} // namespace Kickoff
|
||||
|
||||
QStandardItem *StandardItemFactory::createItemForUrl(const QString& urlString, DisplayOrder displayOrder)
|
||||
{
|
||||
KUrl url(urlString);
|
||||
|
||||
QStandardItem *item = 0;
|
||||
|
||||
// Match files ending with ".desktop" and being local or having a relative
|
||||
// path. For instance applications that still installs .desktop files at
|
||||
// /usr/share/applnk, like KVirc 3
|
||||
const bool isDesktopFile = urlString.endsWith(QLatin1String(".desktop"));
|
||||
if (isDesktopFile && (url.isLocalFile() || url.isRelative())) {
|
||||
// .desktop files may be services (type field == 'Application' or 'Service')
|
||||
// or they may be other types such as links.
|
||||
//
|
||||
// first look in the KDE service database to see if this file is a service,
|
||||
// otherwise represent it as a generic .desktop file
|
||||
KService::Ptr service = KService::serviceByDesktopPath(url.toLocalFile());
|
||||
if (service) {
|
||||
return createItemForService(service, displayOrder);
|
||||
}
|
||||
|
||||
item = new QStandardItem();
|
||||
KDesktopFile desktopFile(url.toLocalFile());
|
||||
QString urlFileName = QFileInfo(urlString).fileName();
|
||||
if (isDesktopFile) {
|
||||
urlFileName = urlFileName.mid(0, urlFileName.size() - 8);
|
||||
}
|
||||
item->setText(urlFileName);
|
||||
item->setIcon(KIcon(desktopFile.readIcon()));
|
||||
|
||||
//FIXME: desktopUrl is a hack around borkage in KRecentDocuments which
|
||||
// stores a path in the URL field!
|
||||
KUrl desktopUrl(desktopFile.desktopGroup().readPathEntry("URL", QString()));
|
||||
if (!desktopUrl.url().isEmpty()) {
|
||||
item->setData(desktopUrl.url(), Kickoff::UrlRole);
|
||||
} else {
|
||||
// desktopUrl.url() is empty if the file doesn't exist so set the
|
||||
// url role to that which was passed so that the item can still be
|
||||
// manually removed
|
||||
item->setData(urlString, Kickoff::UrlRole);
|
||||
}
|
||||
|
||||
QString subTitle = desktopUrl.isLocalFile() ? desktopUrl.toLocalFile() : desktopUrl.prettyUrl();
|
||||
item->setData(subTitle, Kickoff::SubTitleRole);
|
||||
|
||||
setSpecialUrlProperties(desktopUrl, item);
|
||||
} else if (url.scheme() == "leave") {
|
||||
item = LeaveModel::createStandardItem(urlString);
|
||||
} else {
|
||||
item = new QStandardItem();
|
||||
const QString subTitle = url.isLocalFile() ? url.toLocalFile() : url.prettyUrl();
|
||||
QString basename = QFileInfo(url.prettyUrl()).fileName();
|
||||
if (basename.isNull()) {
|
||||
basename = subTitle;
|
||||
}
|
||||
|
||||
item->setText(basename);
|
||||
item->setIcon(KIcon(KMimeType::iconNameForUrl(url)));
|
||||
item->setData(url.url(), Kickoff::UrlRole);
|
||||
item->setData(subTitle, Kickoff::SubTitleRole);
|
||||
|
||||
setSpecialUrlProperties(url, item);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void StandardItemFactory::setSpecialUrlProperties(const KUrl& url, QStandardItem *item)
|
||||
{
|
||||
// specially handled URLs
|
||||
if (homeUrl() && url == *homeUrl()) {
|
||||
item->setText(i18n("Home Folder"));
|
||||
item->setIcon(KIcon("user-home"));
|
||||
} else if (remoteUrl() && url == *remoteUrl()) {
|
||||
item->setText(i18n("Network Folders"));
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItem *StandardItemFactory::createItem(const QIcon & icon, const QString & title,
|
||||
const QString & description, const QString & url)
|
||||
{
|
||||
QStandardItem *appItem = new QStandardItem;
|
||||
|
||||
appItem->setText(title);
|
||||
appItem->setIcon(icon);
|
||||
appItem->setData(description, Kickoff::SubTitleRole);
|
||||
appItem->setData(url, Kickoff::UrlRole);
|
||||
|
||||
return appItem;
|
||||
}
|
||||
|
||||
QStandardItem *StandardItemFactory::createItemForService(KService::Ptr service, DisplayOrder displayOrder)
|
||||
{
|
||||
QStandardItem *appItem = new QStandardItem;
|
||||
|
||||
QString genericName = service->genericName();
|
||||
QString appName = service->name();
|
||||
bool nameFirst = displayOrder == NameBeforeDescription;
|
||||
appItem->setText(nameFirst || genericName.isEmpty() ? appName : genericName);
|
||||
appItem->setIcon(KIcon(service->icon()));
|
||||
appItem->setData(service->entryPath(), Kickoff::UrlRole);
|
||||
|
||||
if (nameFirst) {
|
||||
if (!genericName.isEmpty()) {
|
||||
appItem->setData(genericName, Kickoff::SubTitleRole);
|
||||
}
|
||||
} else if (!genericName.isEmpty()) {
|
||||
// we only set the subtitle to appname if the generic name is empty because if
|
||||
// the generic name IS empty, then the app name is used as the title role
|
||||
// and we don't want it repeated twice.
|
||||
appItem->setData(appName, Kickoff::SubTitleRole);
|
||||
}
|
||||
|
||||
return appItem;
|
||||
}
|
||||
|
||||
bool Kickoff::isLaterVersion(KService::Ptr first , KService::Ptr second)
|
||||
{
|
||||
// a very crude heuristic using the .desktop path names
|
||||
// which only understands kde3 vs kde4
|
||||
bool firstIsKde4 = first->entryPath().contains("kde4");
|
||||
bool secondIsKde4 = second->entryPath().contains("kde4");
|
||||
|
||||
return firstIsKde4 && !secondIsKde4;
|
||||
}
|
||||
|
||||
QStringList Kickoff::systemApplicationList()
|
||||
{
|
||||
KConfigGroup appsGroup = componentData().config()->group("SystemApplications");
|
||||
QStringList apps;
|
||||
apps << "systemsettings";
|
||||
apps = appsGroup.readEntry("DesktopFiles", apps);
|
||||
return apps;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void Kickoff::swapModelIndexes(QModelIndex& first, QModelIndex& second)
|
||||
{
|
||||
Q_ASSERT(first.isValid());
|
||||
Q_ASSERT(second.isValid());
|
||||
|
||||
QAbstractItemModel *firstModel = const_cast<QAbstractItemModel*>(first.model());
|
||||
QAbstractItemModel *secondModel = const_cast<QAbstractItemModel*>(second.model());
|
||||
|
||||
Q_ASSERT(firstModel && secondModel);
|
||||
|
||||
QMap<int, QVariant> firstIndexData = firstModel->itemData(first);
|
||||
QMap<int, QVariant> secondIndexData = secondModel->itemData(second);
|
||||
|
||||
firstModel->setItemData(first, secondIndexData);
|
||||
secondModel->setItemData(second, firstIndexData);
|
||||
}
|
||||
#endif
|
||||
|
||||
K_GLOBAL_STATIC_WITH_ARGS(KComponentData, kickoffComponent, ("kickoff", QByteArray(), KComponentData::SkipMainComponentRegistration))
|
||||
KComponentData Kickoff::componentData()
|
||||
{
|
||||
return *kickoffComponent;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef MODELS_H
|
||||
#define MODELS_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
|
||||
// Katie
|
||||
#include <QStandardItem>
|
||||
#include <QModelIndex>
|
||||
|
||||
// KDE
|
||||
#include <KService>
|
||||
#include <KUrl>
|
||||
|
||||
namespace Solid
|
||||
{
|
||||
class Device;
|
||||
}
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
class StandardItemFactoryData
|
||||
{
|
||||
public:
|
||||
QHash<QString, Solid::Device> deviceByUrl;
|
||||
};
|
||||
|
||||
StandardItemFactoryData* deviceFactoryData();
|
||||
|
||||
/**
|
||||
* List of applications contained in the DesktopFiles key in the
|
||||
* SystemApplications group, used to populate the System model
|
||||
* @return list of desktop entry names
|
||||
*/
|
||||
QStringList systemApplicationList();
|
||||
|
||||
/**
|
||||
* Additional data roles for data which the Kickoff models supply with their items
|
||||
* for use when rendering the items and launching them.
|
||||
*/
|
||||
enum DataRole {
|
||||
/** A sub title to be displayed below the text from the item's Qt::DisplayRole data */
|
||||
SubTitleRole = Qt::UserRole + 1,
|
||||
FirstDataRole = SubTitleRole,
|
||||
/** The URL to be opened when executing the item. */
|
||||
UrlRole = Qt::UserRole + 2,
|
||||
/** The Solid device identifier for items which represent devices. */
|
||||
DeviceUdiRole = Qt::UserRole + 3,
|
||||
/** The amount of space (in Kilobytes) used for items which represent storage. */
|
||||
DiskUsedSpaceRole = Qt::UserRole + 4,
|
||||
/** The amount of free space (in Kilobytes) for items which represent storage. */
|
||||
DiskFreeSpaceRole = Qt::UserRole + 5,
|
||||
SubTitleMandatoryRole = Qt::UserRole + 6,
|
||||
/** Is item a separator. **/
|
||||
SeparatorRole = Qt::UserRole + 7,
|
||||
/** relative path of the item */
|
||||
RelPathRole = Qt::UserRole + 8,
|
||||
IconNameRole = Qt::UserRole + 9,
|
||||
LastDataRole = IconNameRole
|
||||
};
|
||||
|
||||
/**
|
||||
* This enum describes the policy for displaying
|
||||
* Name of Application - Description
|
||||
* Description - Name of Application
|
||||
*/
|
||||
enum DisplayOrder {
|
||||
NameAfterDescription,
|
||||
NameBeforeDescription
|
||||
};
|
||||
|
||||
/**
|
||||
* Factory for creating QStandardItems with appropriate text, icons, URL
|
||||
* and other Kickoff-specific information for a given URL or Service.
|
||||
*/
|
||||
class StandardItemFactory
|
||||
{
|
||||
public:
|
||||
static QStandardItem *createItemForUrl(const QString& url, DisplayOrder displayOrder);
|
||||
static QStandardItem *createItemForService(KService::Ptr service,
|
||||
DisplayOrder displayOrder);
|
||||
static QStandardItem *createItem(const QIcon & icon, const QString & title,
|
||||
const QString & description, const QString & url);
|
||||
|
||||
private:
|
||||
static void setSpecialUrlProperties(const KUrl& url, QStandardItem *item);
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract base class for delegates which provide information about a model
|
||||
* item's state in a particular view.
|
||||
*/
|
||||
class ItemStateProvider
|
||||
{
|
||||
public:
|
||||
virtual ~ItemStateProvider() {}
|
||||
|
||||
/**
|
||||
* Returns true if a @p index should be drawn in the view or
|
||||
* false if it should be hidden.
|
||||
*/
|
||||
virtual bool isVisible(const QModelIndex& index) const = 0;
|
||||
};
|
||||
|
||||
// returns true if 'first' represents a more recent version of
|
||||
// an application than 'second'
|
||||
//
|
||||
// eg. isLaterVersion(myapp_kde4,myapp_kde3) returns true
|
||||
bool isLaterVersion(KService::Ptr first , KService::Ptr second);
|
||||
|
||||
#if 0
|
||||
/** Swaps the data for two indexes in a QAbstractItemModel */
|
||||
void swapModelIndexes(QModelIndex& first, QModelIndex& second);
|
||||
#endif
|
||||
|
||||
// returns the Kickoff component data, this is mainly used
|
||||
// to access the Kickoff shared config data
|
||||
KICKOFF_EXPORT KComponentData componentData();
|
||||
}
|
||||
|
||||
#endif //MODELS_H
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.kde.kickoff.recent">
|
||||
<signal name="clearRecentDocumentsAndApplications"/>
|
||||
</interface>
|
||||
</node>
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.kde.kickoff">
|
||||
<signal name="reloadMenu"/>
|
||||
</interface>
|
||||
</node>
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/recentapplications.h"
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QList>
|
||||
|
||||
// KDE
|
||||
#include <KConfigGroup>
|
||||
#include <KDebug>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
class RecentApplications::Private
|
||||
{
|
||||
public:
|
||||
class ServiceInfo;
|
||||
|
||||
Private() : defaultMaxServices(DEFAULT_MAX_SERVICES) {
|
||||
KConfigGroup recentGroup = componentData().config()->group("RecentlyUsed");
|
||||
QList<QString> recentApplications = recentGroup.readEntry("Applications", QList<QString>());
|
||||
defaultMaxServices = maxServices = qMax(0, recentGroup.readEntry("MaxApplications", defaultMaxServices));
|
||||
|
||||
// TESTING
|
||||
// the actual last date/time is not currently recorded, instead we just use
|
||||
// the current date/time and adjust it by one second after each item is added
|
||||
// to preserve the order of the applications in the list loaded from the KConfig
|
||||
// source
|
||||
QDateTime dateTime = QDateTime::currentDateTime();
|
||||
foreach(const QString& application, recentApplications) {
|
||||
ServiceInfo info;
|
||||
info.storageId = application;
|
||||
info.startCount = 1;
|
||||
info.lastStartedTime = dateTime;
|
||||
addEntry(info.storageId, info);
|
||||
dateTime = dateTime.addSecs(1);
|
||||
}
|
||||
};
|
||||
~Private() {
|
||||
KConfigGroup recentGroup = componentData().config()->group("RecentlyUsed");
|
||||
|
||||
QList<ServiceInfo> services = serviceInfo.values();
|
||||
qSort(services.begin(), services.end());
|
||||
|
||||
// TESTING
|
||||
// only the desktop file used is currently recorded, information such
|
||||
// as start count and date/time of last used is lost
|
||||
QList<QString> recentApplications;
|
||||
foreach(const ServiceInfo& info, services) {
|
||||
recentApplications << info.storageId;
|
||||
}
|
||||
|
||||
recentGroup.writeEntry("Applications", recentApplications);
|
||||
recentGroup.config()->sync();
|
||||
}
|
||||
void addEntry(const QString& id, ServiceInfo& info) {
|
||||
// if this service is already in the list then remove the existing
|
||||
// queue entry (so that there are no duplicates in the queue)
|
||||
if (serviceInfo.contains(id)) {
|
||||
kDebug() << "Duplicate entry added. Removing existing entry from queue.";
|
||||
serviceQueue.removeAll(id);
|
||||
}
|
||||
|
||||
serviceQueue.append(id);
|
||||
serviceInfo.insert(id, info);
|
||||
}
|
||||
|
||||
void removeExpiredEntries() {
|
||||
// if more than the maximum number of services have been added
|
||||
// remove the least recently used service
|
||||
while (serviceQueue.count() > maxServices) {
|
||||
QString removeId = serviceQueue.takeFirst();
|
||||
kDebug() << "More than the maximal " << maxServices << " services added. Removing" << removeId << "from queue.";
|
||||
serviceInfo.remove(removeId);
|
||||
emit instance.applicationRemoved(KService::serviceByStorageId(removeId));
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceInfo
|
||||
{
|
||||
public:
|
||||
ServiceInfo() : startCount(0) {}
|
||||
|
||||
QString storageId;
|
||||
int startCount;
|
||||
QDateTime lastStartedTime;
|
||||
|
||||
bool operator<(const ServiceInfo& rhs) const {
|
||||
return this->lastStartedTime < rhs.lastStartedTime;
|
||||
}
|
||||
};
|
||||
|
||||
static const int DEFAULT_MAX_SERVICES = 5;
|
||||
int defaultMaxServices, maxServices;
|
||||
// queue to keep track of the order in which services have been used
|
||||
// (most recently used at the back)
|
||||
QList<QString> serviceQueue;
|
||||
QHash<QString, ServiceInfo> serviceInfo;
|
||||
RecentApplications instance;
|
||||
};
|
||||
K_GLOBAL_STATIC(RecentApplications::Private, privateSelf)
|
||||
|
||||
RecentApplications *RecentApplications::self()
|
||||
{
|
||||
return &privateSelf->instance;
|
||||
}
|
||||
|
||||
RecentApplications::RecentApplications()
|
||||
{
|
||||
}
|
||||
|
||||
QList<KService::Ptr> RecentApplications::recentApplications() const
|
||||
{
|
||||
QList<Private::ServiceInfo> services = privateSelf->serviceInfo.values();
|
||||
qSort(services.begin(), services.end(), qGreater<Private::ServiceInfo>());
|
||||
|
||||
QList<KService::Ptr> servicePtrs;
|
||||
foreach(const Private::ServiceInfo& info, services) {
|
||||
KService::Ptr s = KService::serviceByStorageId(info.storageId);
|
||||
|
||||
if (s) {
|
||||
servicePtrs << s;
|
||||
}
|
||||
}
|
||||
return servicePtrs;
|
||||
}
|
||||
int RecentApplications::startCount(KService::Ptr service) const
|
||||
{
|
||||
return privateSelf->serviceInfo[service->storageId()].startCount;
|
||||
}
|
||||
QDateTime RecentApplications::lastStartedTime(KService::Ptr service) const
|
||||
{
|
||||
return privateSelf->serviceInfo[service->storageId()].lastStartedTime;
|
||||
}
|
||||
void RecentApplications::setMaximum(int maximum)
|
||||
{
|
||||
Q_ASSERT(maximum >= 0);
|
||||
privateSelf->maxServices = maximum;
|
||||
privateSelf->removeExpiredEntries();
|
||||
}
|
||||
int RecentApplications::maximum() const
|
||||
{
|
||||
return privateSelf->maxServices;
|
||||
}
|
||||
int RecentApplications::defaultMaximum() const
|
||||
{
|
||||
return privateSelf->defaultMaxServices;
|
||||
}
|
||||
void RecentApplications::add(KService::Ptr service)
|
||||
{
|
||||
Private::ServiceInfo info = privateSelf->serviceInfo.value(service->storageId());
|
||||
info.storageId = service->storageId();
|
||||
info.startCount++;
|
||||
info.lastStartedTime = QDateTime::currentDateTime();
|
||||
|
||||
privateSelf->addEntry(info.storageId, info);
|
||||
|
||||
kDebug() << "Recent app added" << info.storageId << info.startCount;
|
||||
emit applicationAdded(service, info.startCount);
|
||||
|
||||
privateSelf->removeExpiredEntries();
|
||||
}
|
||||
void RecentApplications::clear()
|
||||
{
|
||||
privateSelf->serviceInfo.clear();
|
||||
emit cleared();
|
||||
}
|
||||
|
||||
#include "moc_recentapplications.cpp"
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef RECENTAPPLICATIONS_H
|
||||
#define RECENTAPPLICATIONS_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QObject>
|
||||
#include <QDateTime>
|
||||
|
||||
// KDE
|
||||
#include <KService>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* Singleton class which can be used to keep track of recently started applications
|
||||
* in the Kickoff launcher.
|
||||
*
|
||||
* RecentApplications information persists between sessions.
|
||||
*/
|
||||
class KICKOFF_EXPORT RecentApplications : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class Private;
|
||||
friend class Private;
|
||||
|
||||
static RecentApplications *self();
|
||||
|
||||
/**
|
||||
* List of service pointers for recently started applications in the order in which
|
||||
* they were started, with the most recently used application first.
|
||||
*/
|
||||
QList<KService::Ptr> recentApplications() const;
|
||||
/** Returns the number of times an application represented by @p service has been started. */
|
||||
int startCount(KService::Ptr service) const;
|
||||
/** Returns the last time and date with the application represented by @p service was started. */
|
||||
QDateTime lastStartedTime(KService::Ptr service) const;
|
||||
|
||||
/** Sets the maximum number of recently used applications to remember. */
|
||||
void setMaximum(int max);
|
||||
/** Returns the maximum number of recently used applications that are remembered. */
|
||||
int maximum() const;
|
||||
/** Returns the default maximum number of recently used applications that are remembered as defined
|
||||
either in the configfile as "MaxApplications" or via the DEFAULT_MAX_SERVICES macro. */
|
||||
int defaultMaximum() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Registers the startup of an application. This should be called whenever a new application
|
||||
* or service is started.
|
||||
*/
|
||||
void add(KService::Ptr service);
|
||||
/** Clear the list of recent applications. */
|
||||
void clear();
|
||||
|
||||
Q_SIGNALS:
|
||||
/** Emitted after add() has been called. */
|
||||
void applicationAdded(KService::Ptr service, int startCount);
|
||||
/** Emitted after remove() has been called. */
|
||||
void applicationRemoved(KService::Ptr service);
|
||||
/** Emitted after clear() has been called. */
|
||||
void cleared();
|
||||
|
||||
private:
|
||||
RecentApplications();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // RECENTAPPLICATIONS_H
|
||||
|
||||
|
|
@ -1,286 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "core/recentlyusedmodel.h"
|
||||
|
||||
// Qt
|
||||
|
||||
// KDE
|
||||
#include <KDesktopFile>
|
||||
#include <KDirWatch>
|
||||
#include <KRecentDocument>
|
||||
#include <KUrl>
|
||||
#include <KDebug>
|
||||
|
||||
// Local
|
||||
#include "core/recentapplications.h"
|
||||
#include "recentadaptor.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
class RecentlyUsedModel::Private
|
||||
{
|
||||
public:
|
||||
Private(RecentlyUsedModel *parent, RecentType recenttype, int maxRecentApps)
|
||||
: q(parent),
|
||||
recenttype(recenttype),
|
||||
maxRecentApps(maxRecentApps >= 0 ? maxRecentApps : Kickoff::RecentApplications::self()->defaultMaximum()),
|
||||
recentDocumentItem(0),
|
||||
recentAppItem(0),
|
||||
displayOrder(NameAfterDescription)
|
||||
{
|
||||
}
|
||||
|
||||
void removeExistingItem(const QString& path) {
|
||||
if (!itemsByPath.contains(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QStandardItem *existingItem = itemsByPath[path];
|
||||
kDebug() << "Removing existing item" << existingItem;
|
||||
Q_ASSERT(existingItem->parent());
|
||||
existingItem->parent()->removeRow(existingItem->row());
|
||||
itemsByPath.remove(path);
|
||||
}
|
||||
|
||||
void addRecentApplication(KService::Ptr service, bool append) {
|
||||
// remove existing item if any
|
||||
removeExistingItem(service->entryPath());
|
||||
|
||||
QStandardItem *appItem = StandardItemFactory::createItemForService(service, displayOrder);
|
||||
itemsByPath.insert(service->entryPath(), appItem);
|
||||
|
||||
if (append) {
|
||||
recentAppItem->appendRow(appItem);
|
||||
} else {
|
||||
recentAppItem->insertRow(0, appItem);
|
||||
}
|
||||
|
||||
while (recentAppItem->rowCount() > maxRecentApps) {
|
||||
QList<QStandardItem*> row = recentAppItem->takeRow(recentAppItem->rowCount() - 1);
|
||||
|
||||
//don't leave pending stuff in itemsByPath
|
||||
if (!row.isEmpty()) {
|
||||
itemsByPath.remove(row.first()->data(UrlRole).toString());
|
||||
qDeleteAll(row.begin(), row.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addRecentDocument(const QString& desktopPath, bool append) {
|
||||
// remove existing item if any
|
||||
KDesktopFile desktopFile(desktopPath);
|
||||
KUrl documentUrl = desktopFile.readUrl();
|
||||
|
||||
removeExistingItem(documentUrl.url());
|
||||
|
||||
QStandardItem *documentItem = StandardItemFactory::createItemForUrl(desktopPath, displayOrder);
|
||||
documentItem->setData(true, Kickoff::SubTitleMandatoryRole);
|
||||
itemsByPath.insert(desktopPath, documentItem);
|
||||
|
||||
//kDebug() << "Document item" << documentItem << "text" << documentItem->text() << "url" << documentUrl.url();
|
||||
if (append) {
|
||||
recentDocumentItem->appendRow(documentItem);
|
||||
} else {
|
||||
recentDocumentItem->insertRow(0, documentItem);
|
||||
}
|
||||
}
|
||||
|
||||
void loadRecentDocuments()
|
||||
{
|
||||
// create branch for documents and add existing items
|
||||
recentDocumentItem = new QStandardItem(i18n("Documents"));
|
||||
const QStringList documents = KRecentDocument::recentDocuments();
|
||||
foreach(const QString& document, documents) {
|
||||
addRecentDocument(document, true);
|
||||
}
|
||||
|
||||
q->appendRow(recentDocumentItem);
|
||||
}
|
||||
|
||||
void loadRecentApplications()
|
||||
{
|
||||
recentAppItem = new QStandardItem(i18n("Applications"));
|
||||
|
||||
const QList<KService::Ptr> services = RecentApplications::self()->recentApplications();
|
||||
for(int i = 0; i < maxRecentApps && i < services.count(); ++i) {
|
||||
addRecentApplication(services[i], true);
|
||||
}
|
||||
|
||||
q->appendRow(recentAppItem);
|
||||
}
|
||||
|
||||
RecentlyUsedModel * const q;
|
||||
RecentType recenttype;
|
||||
int maxRecentApps;
|
||||
|
||||
QStandardItem *recentDocumentItem;
|
||||
QStandardItem *recentAppItem;
|
||||
QHash<QString, QStandardItem*> itemsByPath;
|
||||
DisplayOrder displayOrder;
|
||||
};
|
||||
|
||||
RecentlyUsedModel::RecentlyUsedModel(QObject *parent, RecentType recenttype, int maxRecentApps)
|
||||
: KickoffModel(parent),
|
||||
d(new Private(this, recenttype, maxRecentApps))
|
||||
{
|
||||
QDBusConnection dbus = QDBusConnection::sessionBus();
|
||||
(void)new RecentAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject("/kickoff/RecentAppDoc", this);
|
||||
dbus.connect(QString(), "/kickoff/RecentAppDoc", "org.kde.plasma", "clearRecentDocumentsAndApplications", this, SLOT(clearRecentDocumentsAndApplications()));
|
||||
|
||||
if (recenttype != DocumentsOnly) {
|
||||
d->loadRecentApplications();
|
||||
|
||||
// listen for changes to the list of recent applications
|
||||
connect(RecentApplications::self(), SIGNAL(applicationAdded(KService::Ptr,int)),
|
||||
this, SLOT(recentApplicationAdded(KService::Ptr,int)));
|
||||
connect(RecentApplications::self(), SIGNAL(applicationRemoved(KService::Ptr)),
|
||||
this, SLOT(recentApplicationRemoved(KService::Ptr)));
|
||||
connect(RecentApplications::self(), SIGNAL(cleared()),
|
||||
this, SLOT(recentApplicationsCleared()));
|
||||
}
|
||||
|
||||
if (recenttype != ApplicationsOnly) {
|
||||
d->loadRecentDocuments();
|
||||
|
||||
// listen for changes to the list of recent documents
|
||||
KDirWatch *recentDocWatch = new KDirWatch(this);
|
||||
recentDocWatch->addDir(KRecentDocument::recentDocumentDirectory());
|
||||
connect(recentDocWatch, SIGNAL(dirty(QString)), this, SLOT(recentDocumentDirty(QString)));
|
||||
}
|
||||
}
|
||||
|
||||
RecentlyUsedModel::~RecentlyUsedModel()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QVariant RecentlyUsedModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal || section != 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (d->recenttype == DocumentsAndApplications) {
|
||||
return i18n("Recently Used");
|
||||
} else if (d->recenttype == DocumentsOnly) {
|
||||
return i18n("Recently Used Documents");
|
||||
} else if (d->recenttype == ApplicationsOnly) {
|
||||
return i18n("Recently Used Applications");
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void RecentlyUsedModel::setNameDisplayOrder(DisplayOrder displayOrder)
|
||||
{
|
||||
if (d->displayOrder == displayOrder) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->displayOrder = displayOrder;
|
||||
|
||||
d->itemsByPath.clear();
|
||||
clear();
|
||||
|
||||
if (d->recenttype != DocumentsOnly) {
|
||||
d->loadRecentApplications();
|
||||
}
|
||||
|
||||
if (d->recenttype != ApplicationsOnly) {
|
||||
d->loadRecentDocuments();
|
||||
}
|
||||
}
|
||||
|
||||
DisplayOrder RecentlyUsedModel::nameDisplayOrder() const
|
||||
{
|
||||
return d->displayOrder;
|
||||
}
|
||||
|
||||
void RecentlyUsedModel::recentDocumentDirty(const QString& path)
|
||||
{
|
||||
kDebug() << "Recent document dirty" << path;
|
||||
|
||||
d->itemsByPath.clear();
|
||||
clear();
|
||||
|
||||
if (d->recenttype != DocumentsOnly) {
|
||||
d->loadRecentApplications();
|
||||
}
|
||||
|
||||
if (d->recenttype != ApplicationsOnly) {
|
||||
d->loadRecentDocuments();
|
||||
}
|
||||
}
|
||||
|
||||
void RecentlyUsedModel::recentApplicationAdded(KService::Ptr service, int)
|
||||
{
|
||||
if (service) {
|
||||
d->addRecentApplication(service, false);
|
||||
}
|
||||
}
|
||||
|
||||
void RecentlyUsedModel::recentApplicationRemoved(KService::Ptr service)
|
||||
{
|
||||
if (service) {
|
||||
d->removeExistingItem(service->entryPath());
|
||||
}
|
||||
}
|
||||
|
||||
void RecentlyUsedModel::recentApplicationsCleared()
|
||||
{
|
||||
QSet<QStandardItem*> appItems;
|
||||
const int rows = d->recentAppItem->rowCount();
|
||||
for (int i = 0;i < rows;i++) {
|
||||
appItems << d->recentAppItem->child(i);
|
||||
}
|
||||
QMutableHashIterator<QString, QStandardItem*> iter(d->itemsByPath);
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
if (appItems.contains(iter.value())) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
d->recentAppItem->removeRows(0, d->recentAppItem->rowCount());
|
||||
}
|
||||
|
||||
void RecentlyUsedModel::clearRecentApplications()
|
||||
{
|
||||
RecentApplications::self()->clear();
|
||||
}
|
||||
void RecentlyUsedModel::clearRecentDocuments()
|
||||
{
|
||||
KRecentDocument::clear();
|
||||
}
|
||||
|
||||
void RecentlyUsedModel::clearRecentDocumentsAndApplications()
|
||||
{
|
||||
clearRecentDocuments();
|
||||
clearRecentApplications();
|
||||
}
|
||||
|
||||
|
||||
#include "moc_recentlyusedmodel.cpp"
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef RECENTLYUSEDMODEL_H
|
||||
#define RECENTLYUSEDMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
#include "core/kickoffmodel.h"
|
||||
#include "core/models.h"
|
||||
|
||||
// KDE
|
||||
#include <KService>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* Model for the Recently Used view which provides a tree of recently used
|
||||
* applications and documents.
|
||||
*/
|
||||
class KICKOFF_EXPORT RecentlyUsedModel : public KickoffModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/** Defines what the model should display. */
|
||||
enum RecentType {
|
||||
DocumentsAndApplications, ///< display recently used documents and applications.
|
||||
DocumentsOnly, ///< documents only. recently used applications will not be displayed.
|
||||
ApplicationsOnly ///< applications only, recently used documents will not be displayed.
|
||||
};
|
||||
|
||||
/** Construct a new RecentlyUsedModel with the specified parent. */
|
||||
explicit RecentlyUsedModel(QObject *parent = 0, RecentType recenttype = DocumentsAndApplications, int maxRecentApps = -1);
|
||||
virtual ~RecentlyUsedModel();
|
||||
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
void setNameDisplayOrder(DisplayOrder displayOrder);
|
||||
DisplayOrder nameDisplayOrder() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void clearRecentApplications();
|
||||
void clearRecentDocuments();
|
||||
void clearRecentDocumentsAndApplications();
|
||||
|
||||
private Q_SLOTS:
|
||||
void recentDocumentDirty(const QString& path);
|
||||
void recentApplicationAdded(KService::Ptr, int startCount);
|
||||
void recentApplicationRemoved(KService::Ptr);
|
||||
void recentApplicationsCleared();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // RECENTLYUSEDMODEL_H
|
|
@ -1,464 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2007 Kevin Ottens <ervin@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "systemmodel.h"
|
||||
|
||||
// Qt
|
||||
#include <QHash>
|
||||
#include <QTimer>
|
||||
|
||||
// KDE
|
||||
#include <KDebug>
|
||||
#include <KDiskFreeSpaceInfo>
|
||||
#include <KIcon>
|
||||
#include <KUrl>
|
||||
#include <KSycoca>
|
||||
#include <KFilePlacesModel>
|
||||
#include <Solid/Device>
|
||||
#include <Solid/DeviceInterface>
|
||||
#include <Solid/DeviceNotifier>
|
||||
#include <Solid/StorageAccess>
|
||||
#include <Solid/StorageDrive>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
#include "core/systemmodel.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
static const int APPLICATIONS_ROW = 0;
|
||||
static const int BOOKMARKS_ROW = 1;
|
||||
static const int REMOVABLE_ROW = 2;
|
||||
static const int FIXED_ROW = 3;
|
||||
static const int LAST_ROW = FIXED_ROW;
|
||||
|
||||
class SystemModel::Private
|
||||
{
|
||||
public:
|
||||
Private(SystemModel *parent)
|
||||
: q(parent),
|
||||
placesModel(new KFilePlacesModel(parent)),
|
||||
refreshRequested(false)
|
||||
{
|
||||
q->setSourceModel(placesModel);
|
||||
|
||||
connect(placesModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
|
||||
q, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
|
||||
connect(placesModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
|
||||
q, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
|
||||
connect(placesModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||
q, SLOT(sourceRowsInserted(QModelIndex,int,int)));
|
||||
connect(placesModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
q, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
connect(placesModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||||
q, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
|
||||
|
||||
topLevelSections << i18n("Applications")
|
||||
<< i18n("Places")
|
||||
<< i18n("Removable Storage")
|
||||
<< i18n("Storage");
|
||||
connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), q, SLOT(reloadApplications()));
|
||||
}
|
||||
|
||||
SystemModel * const q;
|
||||
KFilePlacesModel *placesModel;
|
||||
QStringList topLevelSections;
|
||||
KService::List appsList;
|
||||
QMap<QString, UsageInfo> usageByMountpoint;
|
||||
QWeakPointer<UsageFinder> usageFinder;
|
||||
bool refreshRequested;
|
||||
};
|
||||
|
||||
SystemModel::SystemModel(QObject *parent)
|
||||
: KickoffProxyModel(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
qRegisterMetaType<UsageInfo>("UsageInfo");
|
||||
reloadApplications();
|
||||
}
|
||||
|
||||
SystemModel::~SystemModel()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QModelIndex SystemModel::mapFromSource(const QModelIndex &sourceIndex) const
|
||||
{
|
||||
if (!sourceIndex.isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex parent;
|
||||
|
||||
if (!d->placesModel->isDevice(sourceIndex)) {
|
||||
parent = index(BOOKMARKS_ROW, 0);
|
||||
} else {
|
||||
bool isFixedDevice = d->placesModel->data(sourceIndex, KFilePlacesModel::FixedDeviceRole).toBool();
|
||||
|
||||
if (!isFixedDevice) {
|
||||
parent = index(REMOVABLE_ROW, 0);
|
||||
} else {
|
||||
parent = index(FIXED_ROW, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return index(sourceIndex.row(), 0, parent);
|
||||
}
|
||||
|
||||
QModelIndex SystemModel::mapToSource(const QModelIndex &proxyIndex) const
|
||||
{
|
||||
if (!proxyIndex.isValid() || !proxyIndex.parent().isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
return d->placesModel->index(proxyIndex.row(), proxyIndex.column());
|
||||
}
|
||||
|
||||
QModelIndex SystemModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid()) {
|
||||
return createIndex(row, column, 0);
|
||||
}
|
||||
|
||||
// We use the row+1 of the parent as internal Id.
|
||||
return createIndex(row, column, parent.row() + 1);
|
||||
}
|
||||
|
||||
QModelIndex SystemModel::parent(const QModelIndex &item) const
|
||||
{
|
||||
if (item.internalId() > 0) {
|
||||
return index(item.internalId() - 1, 0);
|
||||
} else {
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
int SystemModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid()) {
|
||||
return LAST_ROW + 1;
|
||||
} else if (!parent.parent().isValid()) {
|
||||
switch (parent.row()) {
|
||||
case APPLICATIONS_ROW:
|
||||
return d->appsList.size() + 1;
|
||||
case BOOKMARKS_ROW:
|
||||
return d->placesModel->rowCount();
|
||||
case REMOVABLE_ROW:
|
||||
return d->placesModel->rowCount();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant SystemModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (index.internalId() == 0) {
|
||||
if (role == Qt::DisplayRole) {
|
||||
return d->topLevelSections[index.row()];
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
if (index.internalId() - 1 == APPLICATIONS_ROW) {
|
||||
if (d->appsList.count() < index.row()) {
|
||||
return QVariant();
|
||||
} else if (d->appsList.count() == index.row()) {
|
||||
// used to be "Run Command"
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
KService::Ptr service = d->appsList[index.row()];
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return service->name();
|
||||
case Qt::DecorationRole:
|
||||
return KIcon(service->icon());
|
||||
case SubTitleRole:
|
||||
return service->genericName();
|
||||
case UrlRole:
|
||||
return service->entryPath();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
if (role == UrlRole && !d->placesModel->isHidden(mapToSource(index))) {
|
||||
QModelIndex parent = index.parent();
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
|
||||
bool isDevice = d->placesModel->isDevice(sourceIndex);
|
||||
bool wellPlaced = false;
|
||||
|
||||
if (!isDevice && parent.row() == BOOKMARKS_ROW) {
|
||||
wellPlaced = true;
|
||||
} else if (isDevice) {
|
||||
bool fixed = d->placesModel->data(sourceIndex, KFilePlacesModel::FixedDeviceRole).toBool();
|
||||
|
||||
if (!fixed && parent.row() == REMOVABLE_ROW) {
|
||||
wellPlaced = true;
|
||||
} else if (fixed && parent.row() == FIXED_ROW) {
|
||||
wellPlaced = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wellPlaced) {
|
||||
return d->placesModel->url(sourceIndex).url();
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
} else if (role == DeviceUdiRole) {
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
|
||||
if (d->placesModel->isDevice(sourceIndex)) {
|
||||
Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
|
||||
return dev.udi();
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
} else if (role == SubTitleRole) {
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
|
||||
if (d->placesModel->isDevice(sourceIndex)) {
|
||||
Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
|
||||
Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
|
||||
|
||||
if (access) {
|
||||
return access->filePath();
|
||||
}
|
||||
} else if (index.parent().row() != APPLICATIONS_ROW) {
|
||||
KUrl url = d->placesModel->url(sourceIndex);
|
||||
return url.isLocalFile() ? url.toLocalFile() : url.prettyUrl();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
} else if (role == DiskUsedSpaceRole || role == DiskFreeSpaceRole) {
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
QString mp;
|
||||
|
||||
if (d->placesModel->isDevice(sourceIndex)) {
|
||||
Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
|
||||
Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
|
||||
|
||||
if (access) {
|
||||
mp = access->filePath();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mp.isEmpty() && d->usageByMountpoint.contains(mp)) {
|
||||
UsageInfo info = d->usageByMountpoint[mp];
|
||||
|
||||
if (role == DiskUsedSpaceRole) {
|
||||
return info.used;
|
||||
} else {
|
||||
return info.available;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return d->placesModel->data(mapToSource(index), role);
|
||||
}
|
||||
|
||||
QVariant SystemModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal || section != 0) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return i18n("Computer");
|
||||
break;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
UsageFinder::UsageFinder(QObject *parent)
|
||||
: QThread(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UsageFinder::add(int index, const QString &mountPoint)
|
||||
{
|
||||
//NOTE: this is not particularly perfect for a threaded object ;)
|
||||
// but the assumption here is that add is called before run()
|
||||
m_toCheck.append(qMakePair(index, mountPoint));
|
||||
}
|
||||
|
||||
void UsageFinder::run()
|
||||
{
|
||||
typedef QPair<int, QString> CheckPair;
|
||||
foreach (CheckPair check, m_toCheck) {
|
||||
KDiskFreeSpaceInfo freeSpace = KDiskFreeSpaceInfo::freeSpaceInfo(check.second);
|
||||
if (freeSpace.isValid()) {
|
||||
UsageInfo info;
|
||||
info.used = freeSpace.used() / 1024;
|
||||
info.available = freeSpace.available() / 1024;
|
||||
emit usageInfo(check.first, check.second, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SystemModel::refreshUsageInfo()
|
||||
{
|
||||
if (d->usageFinder) {
|
||||
d->refreshRequested = true;
|
||||
} else {
|
||||
QTimer::singleShot(100, this, SLOT(startUsageInfoFetch()));
|
||||
}
|
||||
}
|
||||
|
||||
void SystemModel::setUsageInfo(int index, const QString &mountPoint, const UsageInfo &usageInfo)
|
||||
{
|
||||
QModelIndex sourceIndex = d->placesModel->index(index, 0);
|
||||
if (sourceIndex.isValid()) {
|
||||
d->usageByMountpoint[mountPoint] = usageInfo;
|
||||
QModelIndex index = mapFromSource(sourceIndex);
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemModel::stopRefreshingUsageInfo()
|
||||
{
|
||||
d->refreshRequested = false;
|
||||
}
|
||||
|
||||
void SystemModel::usageFinderFinished()
|
||||
{
|
||||
if (d->refreshRequested) {
|
||||
d->refreshRequested = false;
|
||||
QTimer::singleShot(100, this, SLOT(startUsageInfoFetch()));
|
||||
}
|
||||
}
|
||||
|
||||
void SystemModel::startUsageInfoFetch()
|
||||
{
|
||||
if (d->usageFinder) {
|
||||
return;
|
||||
}
|
||||
|
||||
UsageFinder *usageFinder = new UsageFinder(this);
|
||||
d->usageFinder = usageFinder;
|
||||
connect(usageFinder, SIGNAL(finished()),
|
||||
this, SLOT(usageFinderFinished()));
|
||||
connect(usageFinder, SIGNAL(finished()),
|
||||
usageFinder, SLOT(deleteLater()));
|
||||
connect(usageFinder, SIGNAL(usageInfo(int,QString,UsageInfo)),
|
||||
this, SLOT(setUsageInfo(int,QString,UsageInfo)));
|
||||
|
||||
bool hasDevices = false;
|
||||
|
||||
for (int i = 0; i < d->placesModel->rowCount(); ++i) {
|
||||
QModelIndex sourceIndex = d->placesModel->index(i, 0);
|
||||
if (d->placesModel->isDevice(sourceIndex)) {
|
||||
Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
|
||||
Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
|
||||
|
||||
if (access && !access->filePath().isEmpty()) {
|
||||
usageFinder->add(i, access->filePath());
|
||||
hasDevices = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDevices) {
|
||||
usageFinder->start();
|
||||
} else {
|
||||
delete usageFinder;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemModel::reloadApplications()
|
||||
{
|
||||
const QStringList apps = Kickoff::systemApplicationList();
|
||||
d->appsList.clear();
|
||||
|
||||
foreach (const QString &app, apps) {
|
||||
KService::Ptr service = KService::serviceByStorageId(app);
|
||||
|
||||
if (service) {
|
||||
d->appsList << service;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Kickoff::SystemModel::sourceDataChanged(const QModelIndex &start, const QModelIndex &end)
|
||||
{
|
||||
if (start.parent().isValid()) return;
|
||||
|
||||
for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
|
||||
QModelIndex section = index(row, 0);
|
||||
|
||||
QModelIndex new_start = index(start.row(), start.column(), section);
|
||||
QModelIndex new_end = index(end.row(), end.column(), section);
|
||||
emit dataChanged(new_start, new_end);
|
||||
}
|
||||
}
|
||||
|
||||
void Kickoff::SystemModel::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
|
||||
{
|
||||
if (parent.isValid()) return;
|
||||
|
||||
for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
|
||||
QModelIndex section = index(row, 0);
|
||||
beginInsertRows(section, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
void Kickoff::SystemModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int /*end*/)
|
||||
{
|
||||
if (parent.isValid()) return;
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void Kickoff::SystemModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
|
||||
{
|
||||
if (parent.isValid()) return;
|
||||
|
||||
for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
|
||||
QModelIndex section = index(row, 0);
|
||||
beginRemoveRows(section, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
void Kickoff::SystemModel::sourceRowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
|
||||
{
|
||||
if (parent.isValid()) return;
|
||||
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
#include "moc_systemmodel.cpp"
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2007 Kevin Ottens <ervin@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEMMODEL_H
|
||||
#define SYSTEMMODEL_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
#include "core/kickoffproxymodel.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
struct UsageInfo {
|
||||
UsageInfo()
|
||||
: used(0),
|
||||
available(0)
|
||||
{}
|
||||
|
||||
quint64 used;
|
||||
quint64 available;
|
||||
};
|
||||
|
||||
class UsageFinder : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UsageFinder(QObject *parent);
|
||||
void add(int index, const QString &mountPoint);
|
||||
|
||||
Q_SIGNALS:
|
||||
void usageInfo(int index, const QString &mountPoint, const UsageInfo &usageInfo);
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
private:
|
||||
QList<QPair<int, QString> > m_toCheck;
|
||||
};
|
||||
|
||||
/**
|
||||
* Model which provides a tree of items for important system setup tools (eg. System Settings) ,
|
||||
* folders (eg. the user's home folder and the local network) and fixed and removable storage.
|
||||
*/
|
||||
class KICKOFF_EXPORT SystemModel : public KickoffProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Constructs a new SystemModel with the specified parent. */
|
||||
SystemModel(QObject *parent = 0);
|
||||
virtual ~SystemModel();
|
||||
|
||||
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
|
||||
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QModelIndex parent(const QModelIndex &item) const;
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
void refreshUsageInfo();
|
||||
void stopRefreshingUsageInfo();
|
||||
|
||||
private Q_SLOTS:
|
||||
void startUsageInfoFetch();
|
||||
void reloadApplications();
|
||||
void sourceDataChanged(const QModelIndex &start, const QModelIndex &end);
|
||||
void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
|
||||
void sourceRowsInserted(const QModelIndex &parent, int start, int end);
|
||||
void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
|
||||
void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
|
||||
void setUsageInfo(int index, const QString &mountPoint, const UsageInfo &usageInfo);
|
||||
void usageFinderFinished();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SYSTEMMODEL_H
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2007 Kevin Ottens <ervin@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "urlitemlauncher.h"
|
||||
|
||||
// Qt
|
||||
#include <QFileInfo>
|
||||
#include <QHash>
|
||||
#include <QtCore/qabstractitemmodel.h>
|
||||
|
||||
// KDE
|
||||
#include <KDebug>
|
||||
#include <KRun>
|
||||
#include <KUrl>
|
||||
#include <Solid/Device>
|
||||
#include <Solid/StorageAccess>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
#include "core/urlitemlauncher.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
class HandlerInfo
|
||||
{
|
||||
public:
|
||||
HandlerInfo() : type(UrlItemLauncher::ProtocolHandler) , handler(0) {}
|
||||
UrlItemLauncher::HandlerType type;
|
||||
UrlItemHandler *handler;
|
||||
};
|
||||
|
||||
class GenericItemHandler : public UrlItemHandler
|
||||
{
|
||||
public:
|
||||
virtual bool openUrl(const KUrl& url) {
|
||||
new KRun(url, nullptr);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class UrlItemLauncher::Private
|
||||
{
|
||||
public:
|
||||
static QHash<QString, HandlerInfo> globalHandlers;
|
||||
static GenericItemHandler genericHandler;
|
||||
|
||||
static bool openUrl(const QString &urlString) {
|
||||
kDebug() << "Opening item with URL" << urlString;
|
||||
|
||||
KUrl url(urlString);
|
||||
HandlerInfo protocolHandler = globalHandlers[url.scheme()];
|
||||
if (protocolHandler.type == ProtocolHandler && protocolHandler.handler != 0) {
|
||||
return protocolHandler.handler->openUrl(url);
|
||||
}
|
||||
|
||||
QString extension = QFileInfo(url.path()).suffix();
|
||||
HandlerInfo extensionHandler = globalHandlers[extension];
|
||||
if (extensionHandler.type == ExtensionHandler && extensionHandler.handler != 0) {
|
||||
return extensionHandler.handler->openUrl(url);
|
||||
}
|
||||
|
||||
return genericHandler.openUrl(url);
|
||||
}
|
||||
};
|
||||
|
||||
QHash<QString, HandlerInfo> UrlItemLauncher::Private::globalHandlers;
|
||||
GenericItemHandler UrlItemLauncher::Private::genericHandler;
|
||||
|
||||
UrlItemLauncher::UrlItemLauncher(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
UrlItemLauncher::~UrlItemLauncher()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool UrlItemLauncher::openItem(const QModelIndex& index)
|
||||
{
|
||||
QString urlString = index.data(UrlRole).value<QString>();
|
||||
if (urlString.isEmpty()) {
|
||||
QString udi = index.data(DeviceUdiRole).toString();
|
||||
if (!udi.isEmpty()) {
|
||||
Solid::Device device(udi);
|
||||
Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
|
||||
|
||||
if (access && !access->isAccessible()) {
|
||||
connect(access, SIGNAL(setupDone(Solid::ErrorType,QString,QString)),
|
||||
this, SLOT(onSetupDone(Solid::ErrorType,QString,QString)));
|
||||
access->setup();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
kDebug() << "Item" << index.data(Qt::DisplayRole) << "has no URL to open.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return Private::openUrl(urlString);
|
||||
}
|
||||
|
||||
bool UrlItemLauncher::openUrl(const QString& url)
|
||||
{
|
||||
return Private::openUrl(url);
|
||||
}
|
||||
|
||||
void UrlItemLauncher::onSetupDone(Solid::ErrorType error, const QString &errorData, const QString &udi)
|
||||
{
|
||||
Q_UNUSED(errorData);
|
||||
|
||||
if (error != Solid::NoError) {
|
||||
return;
|
||||
}
|
||||
|
||||
Solid::Device device(udi);
|
||||
Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
|
||||
|
||||
Q_ASSERT(access);
|
||||
|
||||
QString urlString = "file://" + access->filePath();
|
||||
Private::openUrl(urlString);
|
||||
}
|
||||
|
||||
// FIXME: the handlers are leaked, as they are added with each new Kickoff instance,
|
||||
// but never deleted.
|
||||
void UrlItemLauncher::addGlobalHandler(HandlerType type, const QString& name, UrlItemHandler *handler)
|
||||
{
|
||||
HandlerInfo info;
|
||||
info.type = type;
|
||||
info.handler = handler;
|
||||
Private::globalHandlers.insert(name, info);
|
||||
}
|
||||
|
||||
|
||||
#include "moc_urlitemlauncher.cpp"
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2007 Kevin Ottens <ervin@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef URLITEMLAUNCHER_H
|
||||
#define URLITEMLAUNCHER_H
|
||||
|
||||
#include "kickoff_export.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QModelIndex>
|
||||
#include <solid/storageaccess.h>
|
||||
|
||||
|
||||
class KUrl;
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* UrlItemHandler is an abstract base class for handlers which can open particular
|
||||
* types of URL.
|
||||
*
|
||||
* @see UrlItemLauncher
|
||||
*/
|
||||
class UrlItemHandler
|
||||
{
|
||||
public:
|
||||
virtual ~UrlItemHandler() {}
|
||||
virtual bool openUrl(const KUrl& url) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* UrlItemLauncher provides facilities to open a item from a Kickoff model based on its UrlRole
|
||||
* data.
|
||||
*
|
||||
* By default, a UrlItemLauncher opens all URLs using the KRun class. Additional handlers can be created
|
||||
* to handle URLs with particular protocols or extensions differently. Handlers can be
|
||||
* registered using the static addGlobalHandler() method.
|
||||
*/
|
||||
class KICKOFF_EXPORT UrlItemLauncher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UrlItemLauncher(QObject *parent = 0);
|
||||
virtual ~UrlItemLauncher();
|
||||
|
||||
enum HandlerType {
|
||||
ProtocolHandler,
|
||||
ExtensionHandler
|
||||
};
|
||||
static void addGlobalHandler(HandlerType type,
|
||||
const QString& name,
|
||||
UrlItemHandler *handler);
|
||||
|
||||
public Q_SLOTS:
|
||||
/** Open the specified @p index from a Kickoff model. */
|
||||
bool openItem(const QModelIndex& index);
|
||||
/** Open the specified @p url */
|
||||
bool openUrl(const QString& url);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onSetupDone(Solid::ErrorType error, const QString &errorData, const QString &udi);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // URLITEMLAUNCHER_H
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// KDE
|
||||
#include <KAboutData>
|
||||
#include <KApplication>
|
||||
#include <KCmdLineArgs>
|
||||
|
||||
// Local
|
||||
#include "ui/launcher.h"
|
||||
|
||||
#define KICKOFF_VERSION "1.9.3"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
KAboutData about("kickoff", 0, ki18n("Kickoff"), KICKOFF_VERSION,
|
||||
ki18n("Application Launcher"),
|
||||
KAboutData::License_GPL_V2);
|
||||
KCmdLineArgs::init(argc, argv, &about);
|
||||
|
||||
KApplication app;
|
||||
|
||||
Kickoff::Launcher *launcher = new Kickoff::Launcher((QWidget*)0);
|
||||
launcher->setWindowTitle("Kickoff KDE 4 Test Application");
|
||||
// ensure launcher gets deleted when the app closes so that favorites,
|
||||
// recent applications etc. are saved
|
||||
launcher->setAttribute(Qt::WA_DeleteOnClose);
|
||||
launcher->show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
|
@ -1,563 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2008-2009 Sebastian Sauer <mail@dipe.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "menuview.h"
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QAbstractItemModel>
|
||||
#include <QtCore/qabstractitemmodel.h>
|
||||
#include <QtCore/QStack>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qstandarditemmodel.h>
|
||||
#include <QtGui/qstyleoption.h>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QToolTip>
|
||||
|
||||
// KDE
|
||||
#include <KDebug>
|
||||
#include <KUrl>
|
||||
#include <KIconLoader>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
#include "core/itemhandlers.h"
|
||||
|
||||
#define MAX_NAME_SIZE 50
|
||||
|
||||
Q_DECLARE_METATYPE(QPersistentModelIndex)
|
||||
Q_DECLARE_METATYPE(QAction*)
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
/// @internal d-pointer class
|
||||
class MenuView::Private
|
||||
{
|
||||
public:
|
||||
enum { ActionRole = Qt::UserRole + 52 };
|
||||
|
||||
Private(MenuView *q) : q(q), column(0), launcher(new UrlItemLauncher(q)), formattype(MenuView::DescriptionName) {}
|
||||
~Private()
|
||||
{
|
||||
qDeleteAll(items);
|
||||
}
|
||||
|
||||
QAction *createActionForIndex(QAbstractItemModel *model, const QModelIndex& index, QMenu *parent)
|
||||
{
|
||||
Q_ASSERT(index.isValid());
|
||||
QAction *action = 0;
|
||||
if (model->hasChildren(index)) {
|
||||
KMenu *childMenu = new KMenu(parent);
|
||||
childMenu->installEventFilter(q);
|
||||
childMenu->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(childMenu, SIGNAL(customContextMenuRequested(QPoint)),
|
||||
q, SLOT(contextMenuRequested(QPoint)));
|
||||
action = childMenu->menuAction();
|
||||
buildBranch(childMenu, model, index);
|
||||
} else {
|
||||
action = q->createLeafAction(index, parent);
|
||||
}
|
||||
|
||||
q->updateAction(model, action, index);
|
||||
return action;
|
||||
}
|
||||
|
||||
QString trunctuateName(QString name, int maxSize)
|
||||
{
|
||||
if (name.length() <= maxSize) {
|
||||
return name;
|
||||
}
|
||||
|
||||
maxSize -= 2; // remove the 3 placeholder points
|
||||
const int start = maxSize / 3; //use one third of the chars for the start of the name
|
||||
const int end = maxSize - start;
|
||||
return name.left(start) + ".." + name.right(end);
|
||||
}
|
||||
|
||||
void buildBranch(KMenu *menu, QAbstractItemModel *model, const QModelIndex& parent)
|
||||
{
|
||||
if (model->canFetchMore(parent)) {
|
||||
model->fetchMore(parent);
|
||||
}
|
||||
const int rowCount = model->rowCount(parent);
|
||||
for (int i = 0; i < rowCount; i++) {
|
||||
QAction *action = createActionForIndex(model, model->index(i, column, parent), menu);
|
||||
action->setText(trunctuateName(action->text(), MAX_NAME_SIZE));
|
||||
menu->addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex findByRelPath(QAbstractItemModel * model, const QModelIndex & parent, const QString & relPath)
|
||||
{
|
||||
QModelIndex newRoot;
|
||||
if (model->canFetchMore(parent)) {
|
||||
model->fetchMore(parent);
|
||||
}
|
||||
const int rowCount = model->rowCount(parent);
|
||||
for (int row = 0; row < rowCount; row++) {
|
||||
QModelIndex index = model->index(row, 0, parent);
|
||||
Q_ASSERT(index.isValid());
|
||||
if (index.data(Kickoff::RelPathRole).isValid()) {
|
||||
QString indexRelPath = index.data(Kickoff::RelPathRole).toString();
|
||||
if (relPath == indexRelPath) {
|
||||
newRoot = index;
|
||||
break;
|
||||
}
|
||||
if (!indexRelPath.isEmpty() && relPath.startsWith(indexRelPath)) {
|
||||
newRoot = findByRelPath(model, index, relPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newRoot;
|
||||
}
|
||||
|
||||
|
||||
MenuView * const q;
|
||||
int column;
|
||||
UrlItemLauncher *launcher;
|
||||
MenuView::FormatType formattype;
|
||||
QPoint mousePressPos;
|
||||
QList<QStandardItem*> items;
|
||||
QHash<QAbstractItemModel*, QAction*> modelsHeader;
|
||||
QList<QWeakPointer<QAbstractItemModel> > models;
|
||||
};
|
||||
|
||||
MenuView::MenuView(QWidget *parent, const QString &title, const QIcon &icon)
|
||||
: KMenu(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
if (! title.isNull())
|
||||
setTitle(title);
|
||||
if (! icon.isNull())
|
||||
setIcon(icon);
|
||||
|
||||
installEventFilter(this);
|
||||
|
||||
connect(this, SIGNAL(customContextMenuRequested(QPoint)),
|
||||
this, SLOT(contextMenuRequested(QPoint)));
|
||||
}
|
||||
|
||||
MenuView::~MenuView()
|
||||
{
|
||||
QListIterator<QWeakPointer<QAbstractItemModel> > it(d->models);
|
||||
while (it.hasNext()) {
|
||||
QAbstractItemModel *model = it.next().data();
|
||||
if (model) {
|
||||
model->disconnect(this);
|
||||
}
|
||||
}
|
||||
|
||||
delete d;
|
||||
}
|
||||
|
||||
QAction *MenuView::createLeafAction(const QModelIndex &index, QObject *parent)
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
return new QAction(parent);
|
||||
}
|
||||
|
||||
void MenuView::updateAction(QAbstractItemModel *model, QAction *action, const QModelIndex& index)
|
||||
{
|
||||
bool isSeparator = index.data(Kickoff::SeparatorRole).value<bool>();
|
||||
|
||||
// if Description or DescriptionName -> displayOrder = Kickoff::NameAfterDescription
|
||||
// Qt::DisplayRole returns genericName, the generic name e.g. "Advanced Text Editor" or "Spreadsheet" or just "" (right, it's a mess too)
|
||||
// Kickoff::SubTitleRole returns appName, the name e.g. "Kate" or "OpenOffice.org Calc" (right, sometimes the text is also used for the generic app-name)
|
||||
//
|
||||
// if Name or NameDescription or NameDashDescription -> displayOrder = Kickoff::NameBeforeDescription
|
||||
// Qt::DisplayRole returns appName,
|
||||
// Kickoff::SubTitleRole returns genericName.
|
||||
|
||||
QString mainText = index.data(Qt::DisplayRole).value<QString>().replace('&', "&&");
|
||||
QString altText = index.data(Kickoff::SubTitleRole).value<QString>().replace('&', "&&");
|
||||
if (action->menu() != 0) { // if it is an item with sub-menuitems, we probably like to thread them another way...
|
||||
action->setText(mainText);
|
||||
} else {
|
||||
switch (d->formattype) {
|
||||
case Name:
|
||||
case Description: {
|
||||
action->setText(mainText);
|
||||
action->setToolTip(altText);
|
||||
} break;
|
||||
case NameDescription: // fall through
|
||||
case NameDashDescription: // fall through
|
||||
case DescriptionName: {
|
||||
if (!mainText.isEmpty()) { // seems we have a program, but some of them don't define a name at all
|
||||
if (mainText.contains(altText, Qt::CaseInsensitive)) { // sometimes the description contains also the name
|
||||
action->setText(mainText);
|
||||
} else if (altText.contains(mainText, Qt::CaseInsensitive)) { // and sometimes the name also contains the description
|
||||
action->setText(altText);
|
||||
} else { // seems we have a perfect desktop-file (likely a KDE one, heh) and name+description are clear separated
|
||||
if (d->formattype == NameDashDescription) {
|
||||
action->setText(QString("%1 - %2").arg(mainText).arg(altText));
|
||||
} else {
|
||||
action->setText(QString("%1 (%2)").arg(mainText).arg(altText));
|
||||
}
|
||||
}
|
||||
} else { // if there is no name, let's just use the describing text
|
||||
action->setText(altText);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
action->setSeparator(isSeparator);
|
||||
if (!isSeparator) {
|
||||
action->setIcon(index.data(Qt::DecorationRole).value<QIcon>());
|
||||
}
|
||||
|
||||
// we map modelindex and action together
|
||||
action->setData(qVariantFromValue(QPersistentModelIndex(index)));
|
||||
|
||||
// don't emit the dataChanged-signal cause else we may end in a infinite loop
|
||||
model->blockSignals(true);
|
||||
model->setData(index, qVariantFromValue(action), Private::ActionRole);
|
||||
model->blockSignals(false);
|
||||
}
|
||||
|
||||
bool MenuView::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
switch(event->type()) {
|
||||
case QEvent::MouseMove: {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
QMenu *watchedMenu = qobject_cast<QMenu*>(watched);
|
||||
const int mousePressDistance = !d->mousePressPos.isNull() ? (mouseEvent->pos() - d->mousePressPos).manhattanLength() : 0;
|
||||
|
||||
if (watchedMenu && mouseEvent->buttons() & Qt::LeftButton
|
||||
&& mousePressDistance >= QApplication::startDragDistance()) {
|
||||
QAction *action = watchedMenu->actionAt(mouseEvent->pos());
|
||||
if (!action) {
|
||||
return KMenu::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
QPersistentModelIndex index = action->data().value<QPersistentModelIndex>();
|
||||
if (!index.isValid()) {
|
||||
return KMenu::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
QUrl url = index.data(UrlRole).toUrl();
|
||||
if (url.isEmpty()) {
|
||||
return KMenu::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
mimeData->setUrls(QList<QUrl>() << url);
|
||||
mimeData->setText(url.toString());
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setMimeData(mimeData);
|
||||
|
||||
QIcon icon = action->icon();
|
||||
drag->setPixmap(icon.pixmap(IconSize(KIconLoader::Desktop)));
|
||||
|
||||
d->mousePressPos = QPoint();
|
||||
|
||||
Qt::DropAction dropAction = drag->exec();
|
||||
Q_UNUSED(dropAction);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::MouseButtonPress: {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
QMenu *watchedMenu = qobject_cast<QMenu*>(watched);
|
||||
if (watchedMenu) {
|
||||
d->mousePressPos = mouseEvent->pos();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::MouseButtonRelease: {
|
||||
QMenu *watchedMenu = qobject_cast<QMenu*>(watched);
|
||||
if (watchedMenu) {
|
||||
d->mousePressPos = QPoint();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::Hide: {
|
||||
emit afterBeingHidden();
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::ToolTip: {
|
||||
bool hide = true;
|
||||
|
||||
if ((d->formattype == Name) || (d->formattype == Description)) {
|
||||
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
|
||||
QMenu *watchedMenu = qobject_cast<QMenu*>(watched);
|
||||
|
||||
if (watchedMenu && watchedMenu->activeAction()) {
|
||||
QString toolTip = watchedMenu->activeAction()->toolTip();
|
||||
|
||||
if ((toolTip != watchedMenu->activeAction()->text()) && (watchedMenu->activeAction()->menu() == 0)) {
|
||||
QToolTip::showText(helpEvent->globalPos(), toolTip);
|
||||
hide = false ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hide) {
|
||||
QToolTip::hideText();
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return KMenu::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void MenuView::addModel(QAbstractItemModel *model, MenuView::ModelOptions options, const QString & relativePath)
|
||||
{
|
||||
QString title = model->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString();
|
||||
|
||||
QAction *header = addTitle(title);
|
||||
header->setVisible(false);
|
||||
|
||||
d->modelsHeader.insert(model, header);
|
||||
d->models.append(model);
|
||||
|
||||
if (options & MergeFirstLevel) {
|
||||
const int count = model->rowCount();
|
||||
for (int row = 0; row < count; ++row) {
|
||||
QModelIndex index = model->index(row, 0, QModelIndex());
|
||||
Q_ASSERT(index.isValid());
|
||||
|
||||
const QString title = index.data(Qt::DisplayRole).value<QString>();
|
||||
if (count > 1 && ! title.isEmpty() && model->rowCount(index) > 0) {
|
||||
addTitle(title);
|
||||
}
|
||||
|
||||
model->blockSignals(true);
|
||||
model->setData(index, qVariantFromValue(this->menuAction()), Private::ActionRole);
|
||||
model->blockSignals(false);
|
||||
|
||||
d->buildBranch(this, model, index);
|
||||
}
|
||||
} else {
|
||||
QModelIndex root;
|
||||
if (!relativePath.isEmpty()) {
|
||||
root = d->findByRelPath(model, root, relativePath);
|
||||
}
|
||||
d->buildBranch(this, model, root);
|
||||
}
|
||||
|
||||
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
|
||||
connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex)));
|
||||
connect(model, SIGNAL(modelReset()), this, SLOT(modelReset()));
|
||||
}
|
||||
|
||||
void MenuView::addItem(QStandardItem *item)
|
||||
{
|
||||
QAction *action = new QAction(item->icon(), item->text(), this);
|
||||
KUrl url(item->data(Kickoff::UrlRole).toString());
|
||||
Q_ASSERT(url.isValid());
|
||||
action->setData(url);
|
||||
addAction(action);
|
||||
d->items << item;
|
||||
}
|
||||
|
||||
UrlItemLauncher *MenuView::launcher() const
|
||||
{
|
||||
return d->launcher;
|
||||
}
|
||||
|
||||
QModelIndex MenuView::indexForAction(QAction *action) const
|
||||
{
|
||||
Q_ASSERT(action != 0);
|
||||
QPersistentModelIndex index = action->data().value<QPersistentModelIndex>();
|
||||
return index;
|
||||
}
|
||||
|
||||
QAction *MenuView::actionForIndex(const QModelIndex& index) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return this->menuAction();
|
||||
}
|
||||
|
||||
const QAbstractItemModel *model = index.model();
|
||||
Q_ASSERT(model);
|
||||
QVariant v = model->data(index, Private::ActionRole);
|
||||
Q_ASSERT(v.isValid());
|
||||
QAction* a = v.value<QAction*>();
|
||||
Q_ASSERT(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
bool MenuView::isValidIndex(const QModelIndex& index) const
|
||||
{
|
||||
QVariant v = (index.isValid() && index.model()) ? index.model()->data(index, Private::ActionRole) : QVariant();
|
||||
return v.isValid() && v.value<QAction*>();
|
||||
}
|
||||
|
||||
void MenuView::rowsInserted(const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
kDebug() << start << end;
|
||||
|
||||
Q_ASSERT(parent.isValid());
|
||||
Q_ASSERT(parent.model());
|
||||
|
||||
//Q_ASSERT( ! isValidIndex(parent) );
|
||||
QMenu *menu = isValidIndex(parent) ? actionForIndex(parent)->menu() : this;
|
||||
|
||||
QAbstractItemModel *model = const_cast<QAbstractItemModel*>(parent.model());
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QAction*> newActions;
|
||||
for (int row = start; row <= end; row++) {
|
||||
QModelIndex index = model->index(row, d->column, parent);
|
||||
QAction *newAction = d->createActionForIndex(model, index, menu);
|
||||
kDebug()<<"new action="<<newAction->text();
|
||||
newActions << newAction;
|
||||
}
|
||||
|
||||
int lastidx = -1, offset = -1;
|
||||
for (int i = 0; i < menu->actions().count(); ++i) {
|
||||
QAction *action = menu->actions()[i];
|
||||
Q_ASSERT(action);
|
||||
QModelIndex index = indexForAction(action);
|
||||
if (index.isValid() && index.model() == model) {
|
||||
lastidx = i;
|
||||
if(++offset == start)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastidx < 0 && d->modelsHeader.contains(model)) {
|
||||
QAction *header = d->modelsHeader[model];
|
||||
lastidx = menu->actions().indexOf(header);
|
||||
}
|
||||
|
||||
if (lastidx >= 0) {
|
||||
if (offset < start) {
|
||||
lastidx++; // insert action the item right after the last valid index
|
||||
}
|
||||
|
||||
if (lastidx < menu->actions().count()) {
|
||||
menu->insertActions(menu->actions()[lastidx], newActions);
|
||||
} else {
|
||||
lastidx = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastidx < 0) {
|
||||
// just append the action
|
||||
menu->addActions(newActions);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuView::rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
kDebug() << start << end;
|
||||
Q_UNUSED(parent);
|
||||
Q_UNUSED(start);
|
||||
Q_UNUSED(end);
|
||||
modelReset();
|
||||
}
|
||||
|
||||
void MenuView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||
{
|
||||
QAbstractItemModel *model = const_cast<QAbstractItemModel*>(topLeft.model());
|
||||
Q_ASSERT(model);
|
||||
|
||||
//Q_ASSERT( ! isValidIndex(topLeft) );
|
||||
QMenu *menu = isValidIndex(topLeft) ? actionForIndex(topLeft)->menu() : this;
|
||||
|
||||
QList<QAction*> actions = menu->actions();
|
||||
Q_ASSERT(bottomRight.row() < actions.count());
|
||||
|
||||
for (int row = topLeft.row(); row <= bottomRight.row() && row < actions.count(); ++row) {
|
||||
QModelIndex index = model->index(row, d->column, topLeft.parent());
|
||||
kDebug()<<row<<index.data(Qt::DisplayRole).value<QString>();
|
||||
updateAction(model, actions[row], index);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuView::modelReset()
|
||||
{
|
||||
kDebug();
|
||||
deleteLater(); // we need to force clearance of the menu and rebuild from scratch
|
||||
}
|
||||
|
||||
void MenuView::setColumn(int column)
|
||||
{
|
||||
d->column = column;
|
||||
modelReset();
|
||||
}
|
||||
|
||||
int MenuView::column() const
|
||||
{
|
||||
return d->column;
|
||||
}
|
||||
|
||||
MenuView::FormatType MenuView::formatType() const
|
||||
{
|
||||
return d->formattype;
|
||||
}
|
||||
|
||||
void MenuView::setFormatType(MenuView::FormatType formattype)
|
||||
{
|
||||
d->formattype = formattype;
|
||||
}
|
||||
|
||||
void MenuView::setModelTitleVisible(QAbstractItemModel *model, bool visible)
|
||||
{
|
||||
if (d->modelsHeader.contains(model)) {
|
||||
QAction *header = d->modelsHeader[model];
|
||||
header->setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuView::actionTriggered(QAction *action)
|
||||
{
|
||||
KUrl url = action->data().value<KUrl>();
|
||||
if (url.isValid()) {
|
||||
d->launcher->openUrl(url.url());
|
||||
} else {
|
||||
QModelIndex index = indexForAction(action);
|
||||
if (index.isValid()) {
|
||||
d->launcher->openItem(index);
|
||||
} else {
|
||||
kWarning()<<"Invalid action objectName="<<action->objectName()<<"text="<<action->text()<<"parent="<<(action->parent()?action->parent()->metaObject()->className():"NULL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuView::contextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
KMenu *menu = qobject_cast<KMenu *>(sender());
|
||||
emit customContextMenuRequested(menu, pos);
|
||||
}
|
||||
|
||||
#include "moc_menuview.cpp"
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2008-2009 Sebastian Sauer <mail@dipe.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef MENUVIEW_H
|
||||
#define MENUVIEW_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/qabstractitemmodel.h>
|
||||
|
||||
// KDE
|
||||
#include <KMenu>
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QStandardItem>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class UrlItemLauncher;
|
||||
|
||||
/**
|
||||
* A view for a QAbstractItemModel which displays the model (set with setModel())
|
||||
* as a hierarchical menu.
|
||||
*
|
||||
* When the menu is executed and an item is triggered, the model index associated with the
|
||||
* chosen item can be found by calling indexForAction() with the triggered action. The action
|
||||
* associated with a particular model index can be found using actionForIndex().
|
||||
*
|
||||
* MenuView creates actions for parts of the model on demand as the user explores the menu.
|
||||
* The type of action created for leaf items in the tree can be changed by re-implementing
|
||||
* createLeafAction(). When a new action is created or if the corresponding model
|
||||
* index's data changes, updateAction() is called to set the action's properties. This
|
||||
* can be reimplemented in sub-classes to change the appearance of the actions.
|
||||
*/
|
||||
class MenuView : public KMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
/** Constructs a new menu with the specified @p parent */
|
||||
MenuView(QWidget *parent = 0, const QString &title = QString(), const QIcon &icon = QIcon());
|
||||
/** Destructor */
|
||||
virtual ~MenuView();
|
||||
|
||||
/// Options for a model.
|
||||
enum ModelOptions {
|
||||
None, ///< no options.
|
||||
MergeFirstLevel ///< merge the first both levels of items within the model into one hirachy in the menuview.
|
||||
};
|
||||
|
||||
/** Adds a model to display within this menu. */
|
||||
void addModel(QAbstractItemModel *model, ModelOptions options = None, const QString & relativePath = QString());
|
||||
|
||||
/** Adds a QStandardItem to display within this menu. This menu will take over the ownership of the item. */
|
||||
void addItem(QStandardItem *item);
|
||||
|
||||
/** Returns the UrlItemLauncher used to handle launching of urls. */
|
||||
UrlItemLauncher *launcher() const;
|
||||
|
||||
/** Maps an action in the menu to its corresponding index in model() */
|
||||
QModelIndex indexForAction(QAction *action) const;
|
||||
|
||||
/**
|
||||
* Maps an index in the model to its corresponding action in the menu.
|
||||
* If @p index is invalid then menuAction() will be returned. If @p index
|
||||
* is in a part of the tree which the user has not yet explored then 0 will
|
||||
* be returned because the menu hierarchy is constructed on-demand as the user
|
||||
* explores the menu.
|
||||
*/
|
||||
QAction *actionForIndex(const QModelIndex& index) const;
|
||||
|
||||
/**
|
||||
* Returns true if the passed \p index is a valid QModelIndex and does
|
||||
* represent a QAction. This method is equal to the actionForIndex() method
|
||||
* above except allowing to explicit ask if the QModelIndex is valid and
|
||||
* to indicate that way, that it may the case that the QModelIndex went
|
||||
* out of scope already.
|
||||
*/
|
||||
bool isValidIndex(const QModelIndex& index) const;
|
||||
|
||||
/** Sets the column from the model which is used to construct the actions in the menu. */
|
||||
void setColumn(int column);
|
||||
/** Returns the column from the model which is used to construct the actions in the menu. */
|
||||
int column() const;
|
||||
|
||||
/** The format type enumeration. */
|
||||
enum FormatType {
|
||||
Name = 0, ///< Name only
|
||||
Description, ///< Description only
|
||||
NameDescription, ///< Name (Description)
|
||||
DescriptionName, ///< Description (Name)
|
||||
NameDashDescription ///< Name - Description
|
||||
};
|
||||
/** \return the format type. */
|
||||
FormatType formatType() const;
|
||||
/** Set the format type. */
|
||||
void setFormatType(FormatType formattype);
|
||||
/** Set visibility of model title on menu. */
|
||||
void setModelTitleVisible(QAbstractItemModel *model, bool visible);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Creates a new action to represent a leaf index in the tree. A leaf index
|
||||
* is one which does not have children. The default implementation creates a new
|
||||
* QAction with no properties set. updateAction() is immediately called on the
|
||||
* return action to set its text and icon.
|
||||
*
|
||||
* @param index The index in the model for which an action should be created
|
||||
* @param parent The object which should be set as the parent of the new action
|
||||
*/
|
||||
virtual QAction *createLeafAction(const QModelIndex& index, QObject *parent);
|
||||
|
||||
/**
|
||||
* Sets the text, icon and other properties of @p action using the data
|
||||
* associated with @p index in the model(). This is called whenever the data for
|
||||
* a range of indexes in the tree is altered.
|
||||
*
|
||||
* The default implementation sets the action's text to the index's Qt::DisplayRole data
|
||||
* and the action's icon to the index's Qt::DecorationRole data.
|
||||
*/
|
||||
virtual void updateAction(QAbstractItemModel *model, QAction *action, const QModelIndex& index);
|
||||
|
||||
// reimplemented
|
||||
virtual bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* An item in the menu got triggered.
|
||||
*/
|
||||
void actionTriggered(QAction* action);
|
||||
|
||||
void contextMenuRequested(const QPoint& pos);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Compared to the aboutToShow() this signal will be emitted after the menu
|
||||
* got hidden.
|
||||
*/
|
||||
void afterBeingHidden();
|
||||
|
||||
void customContextMenuRequested(QMenu* menu, const QPoint& pos);
|
||||
|
||||
private Q_SLOTS:
|
||||
/// new items have been inserted into the model
|
||||
void rowsInserted(const QModelIndex& parent, int start, int end);
|
||||
/// existing items are about to be removed from the model
|
||||
void rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
|
||||
/// data within an item of the model change
|
||||
void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||
/// the model did reset itself and all items are invalid
|
||||
void modelReset();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MENUVIEW_H
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Name=Application Launcher Menu
|
||||
Name[af]=Programlanseerder-kieslys
|
||||
Name[ar]=قائمة مطلق التطبيقات
|
||||
Name[ast]=Menú del llanzador d'aplicaciones
|
||||
Name[be@latin]=Menu dla ŭklučeńnia aplikacyjaŭ
|
||||
Name[bg]=Стартиране на програми с меню
|
||||
Name[bn]=অ্যাপলিকেশন লঞ্চার মেনু
|
||||
Name[bs]=meni za pokretanje programa
|
||||
Name[ca]=Menú del llançador d'aplicacions
|
||||
Name[ca@valencia]=Menú del llançador d'aplicacions
|
||||
Name[cs]=Nabídka spouštěče aplikací
|
||||
Name[csb]=Menu zrëszôcza programów
|
||||
Name[da]=Startmenu
|
||||
Name[de]=K-Menü (traditionell)
|
||||
Name[el]=Μενού εκτέλεσης εφαρμογών
|
||||
Name[en_GB]=Application Launcher Menu
|
||||
Name[eo]=Aplikaĵolanĉila menuo
|
||||
Name[es]=Menú del lanzador de aplicaciones
|
||||
Name[et]=Rakenduste käivitaja menüü
|
||||
Name[eu]=Aplikazio-abiarazlearen menua
|
||||
Name[fi]=Sovellusten käynnistysvalikko
|
||||
Name[fr]=Menu de lancement des applications
|
||||
Name[fy]=Applikaasje úteinsetter menu
|
||||
Name[ga]=Roghchlár Tosaitheora Feidhmchlár
|
||||
Name[gl]=Menú iniciador de programas
|
||||
Name[gu]=કાર્યક્રમ ચલાવનાર મેનુ
|
||||
Name[he]=תפריט משגר יישומים
|
||||
Name[hi]=अनुप्रयोग चलाने वाला मेन्यू
|
||||
Name[hne]=अनुपरयोग चालू करइया मेनु
|
||||
Name[hr]=Izbornik pokretača aplikacija
|
||||
Name[hsb]=Meni startowarja aplikacijow
|
||||
Name[hu]=Programindító menü
|
||||
Name[ia]=Menu de Lanceator de application
|
||||
Name[id]=Menu Peluncur Aplikasi
|
||||
Name[is]=Valmynd forritaræsingar
|
||||
Name[ja]=アプリケーション起動メニュー
|
||||
Name[kk]=Қолданбаны жегу мәзірі
|
||||
Name[km]=ម៉ឺនុយកម្មវិធីចាប់ផ្ដើមកម្មវិធី
|
||||
Name[kn]=ಅನ್ವಯ ಪ್ರಕ್ಷೇಪಕ (ಲಾಚರ್) ಪರಿವಿಡಿ
|
||||
Name[ko]=프로그램 실행기 메뉴
|
||||
Name[lt]=Programų paleidiklio meniu
|
||||
Name[lv]=Programmu palaidēja izvēlne
|
||||
Name[ml]=പ്രയോഗവിക്ഷേപിണി മെനു
|
||||
Name[mr]=अनुप्रयोग प्रक्षेपक मेन्यू
|
||||
Name[nb]=Meny for programstarter
|
||||
Name[nds]=Programmoproopmenü
|
||||
Name[nl]=Programmastartermenu
|
||||
Name[nn]=Programstartmeny
|
||||
Name[or]=ପ୍ରୟୋଗ ଆରମ୍ଭକର୍ତ୍ତା ତାଲିକା
|
||||
Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਲਾਂਚਰ ਮੇਨੂ
|
||||
Name[pl]=Menu aktywatora programów
|
||||
Name[pt]=Menu do Lançador de Aplicações
|
||||
Name[pt_BR]=Menu do lançador de aplicativos
|
||||
Name[ro]=Meniu pentru lansatorul de aplicații
|
||||
Name[ru]=Классическое меню запуска приложений
|
||||
Name[se]=Prográmmaálggahanfállu
|
||||
Name[si]=යෙදුම් ඇරඹුම් මෙනුව
|
||||
Name[sk]=Spúšťač aplikácií (menu)
|
||||
Name[sl]=Meni zaganjalnika programov
|
||||
Name[sr]=мени за покретање програма
|
||||
Name[sr@ijekavian]=мени за покретање програма
|
||||
Name[sr@ijekavianlatin]=meni za pokretanje programa
|
||||
Name[sr@latin]=meni za pokretanje programa
|
||||
Name[sv]=Programstartmeny
|
||||
Name[ta]=பயன்பாடு ஏவல் தளம்
|
||||
Name[te]=అనువర్తనముల లాంచర్ మెనూ
|
||||
Name[tg]=Менюи оғози барномаҳо
|
||||
Name[th]=เมนูเรียกใช้งานโปรแกรม
|
||||
Name[tr]=Uygulama Başlatma Menüsü
|
||||
Name[ug]=پروگرامما ئىجرا قىلغۇچ تىزىملىكى
|
||||
Name[uk]=Інструмент запуску програм з меню
|
||||
Name[vi]=Trình đơn chạy ứng dụng
|
||||
Name[wa]=Dressêye d' enondeu di programe
|
||||
Name[x-test]=xxApplication Launcher Menuxx
|
||||
Name[zh_CN]=应用程序启动菜单
|
||||
Name[zh_TW]=應用程式啟動器選單
|
||||
Comment=Traditional menu based application launcher
|
||||
Comment[af]=Tradisionele kieslys as programlanseerder
|
||||
Comment[ar]=مطلق تطبيقات تقليدي على شكل قائمة
|
||||
Comment[ast]=Llanzador d'aplicaciones tradicional basáu en menú
|
||||
Comment[be@latin]=Tradycyjnaje menu dla ŭklučeńnia aplikacyjaŭ
|
||||
Comment[bg]=Традиционно стартиране на програми с меню
|
||||
Comment[bs]=Tradicionalno pokretanje programa pomoću menija
|
||||
Comment[ca]=Llançador d'aplicacions basat en el menú tradicional
|
||||
Comment[ca@valencia]=Llançador d'aplicacions basat en el menú tradicional
|
||||
Comment[cs]=Tradiční spouštěč aplikací založený na nabídce
|
||||
Comment[da]=Traditionel menubaseret startmenu
|
||||
Comment[de]=Programmstarter mit traditionellen Menüs
|
||||
Comment[el]=Παραδοσιακό μενού εκτέλεσης εφαρμογών
|
||||
Comment[en_GB]=Traditional menu based application launcher
|
||||
Comment[eo]=La kutima menua bazita aplikaĵolanĉilo
|
||||
Comment[es]=Lanzador de aplicaciones tradicional basado en menú
|
||||
Comment[et]=Rakenduste käivitajale tuginev traditsiooniline menüü
|
||||
Comment[eu]=Menuetan oinarritutako aplikazio-abiarazle tradizionala
|
||||
Comment[fi]=Perinteinen valikkopohjainen sovellusten käynnistin
|
||||
Comment[fr]=Lanceur d'applications utilisant un menu traditionnel
|
||||
Comment[fy]=Tradisjoneel menu bassearre applikaasje úteinsetter
|
||||
Comment[ga]=Tosaitheoir traidisiúnta feidhmchlár bunaithe ar roghchlár
|
||||
Comment[gl]=Un iniciador de programas baseado no menú tradicional
|
||||
Comment[gu]=પરંપરાગત મેનુ આધારિત કાર્યક્રમમ ચલાવનાર
|
||||
Comment[he]=משגר יישומים מסורתי מבוסס תפריטים
|
||||
Comment[hi]=पारंपरिक मेन्यू आधारित अनुप्रयोग चलाने वाला
|
||||
Comment[hne]=परंपरा वाले मेनु आधारित अनुपरयोग चालू करइया
|
||||
Comment[hr]=Tradicionalni pokretač baziran na izbornicima
|
||||
Comment[hsb]=Tradicionalny, na meniju bazowacy startowar aplikacijow
|
||||
Comment[hu]=Hagyományos programindító menü
|
||||
Comment[ia]=Lanceator de application basate sur menu traditional
|
||||
Comment[id]=Menu tradisional berbasis peluncur aplikasi
|
||||
Comment[is]=Venjuleg valmyndabyggð forritaræsing
|
||||
Comment[ja]=Kickoff ランチャーに基づく従来のアプリケーション起動メニュー
|
||||
Comment[kk]=Қолданба жеккішті негіздейтін дәстүрлі мәзір
|
||||
Comment[km]=ម៉ឺនុយបន្ថែមមានមូលដ្ឋានលើកម្មវិធីចាប់ផ្ដើមកម្មវិធី
|
||||
Comment[kn]=ಸಾಂಪ್ರದಾಯಿಕ ಪರಿವಿಡಿ ಆಧಾರಿತ ಅನ್ವಯ ಪ್ರಕ್ಷೇಪಕ (ಲಾಂಚರ್)
|
||||
Comment[ko]=전통적인 메뉴 기반 프로그램 실행기
|
||||
Comment[lt]=Tradicinio meniu programų paleidiklis
|
||||
Comment[lv]=Tradicionālais uz izvēlnēm bāzētais programmu palaidējs
|
||||
Comment[mk]=Традиционален стартувач на апликации базиран на мени
|
||||
Comment[ml]=പരമ്പരാഗതമായ മെനുഅടിസ്ഥാനമാക്കിയുള്ള പ്രയോഗവിക്ഷേപിണി
|
||||
Comment[mr]=पारंपारिक मेन्यू आधारित अनुप्रयोग प्रक्षेपक
|
||||
Comment[nb]=Tradisjonell menybasert programstarter
|
||||
Comment[nds]=Begäng Programmoproper mit Menüs
|
||||
Comment[nl]=Traditioneel menu voor het starten van programma's
|
||||
Comment[nn]=Tradisjonell menybasert programstartar
|
||||
Comment[or]=ପ୍ରଥାଗତ ତାଲିକା ଆଧାରିତ ପ୍ରୟୋଗ ଆରମ୍ଭକର୍ତ୍ତା
|
||||
Comment[pa]=ਆਮ ਮੇਨੂ ਅਧਾਰਿਤ ਐਪਲੀਕੇਸ਼ਨ ਲਾਂਚਰ
|
||||
Comment[pl]=Tradycyjny, oparty o menu, aktywator programów
|
||||
Comment[pt]=Lançador de aplicações baseado num menu tradicional
|
||||
Comment[pt_BR]=Lançador de aplicativos baseado no menu tradicional
|
||||
Comment[ro]=Lansator de aplicații bazat pe meniu tradițional
|
||||
Comment[ru]=Традиционное меню запуска приложений
|
||||
Comment[se]=Árbevirolaš fállovuođđoduvvun prográmmaálggaheaddji
|
||||
Comment[si]=සාම්ප්රදායික මෙනු පාදක කරගන් යෙදුම් අරඹනය
|
||||
Comment[sk]=Tradičný spúšťač aplikácií založený na menu
|
||||
Comment[sl]=Zaganjalnik programov, ki temelji na tradicionalnem meniju
|
||||
Comment[sr]=Традиционално покретање програма помоћу менија
|
||||
Comment[sr@ijekavian]=Традиционално покретање програма помоћу менија
|
||||
Comment[sr@ijekavianlatin]=Tradicionalno pokretanje programa pomoću menija
|
||||
Comment[sr@latin]=Tradicionalno pokretanje programa pomoću menija
|
||||
Comment[sv]=Traditionell menybaserad programstart
|
||||
Comment[ta]=Traditional menu based application launcher
|
||||
Comment[te]=సాంప్రదాయ మెనూ ఆధారిత అనువర్తనం లాంచర్
|
||||
Comment[tg]=Традиционное средство запуска приложений на основе меню
|
||||
Comment[th]=เมนูแบบดั้งเดิมสำหรับเรียกใช้งานโปรแกรม
|
||||
Comment[tr]=Geleneksel menü temelli uygulama başlatıcı
|
||||
Comment[ug]=تىزىملىك ئاساسىدىكى ئەنئەنىۋى پروگرامما ئىجرا قىلغۇچ
|
||||
Comment[uk]=Інструмент запуску програм з традиційним меню
|
||||
Comment[wa]=Enondeu d' programe båzé sol tradicionele dressêye
|
||||
Comment[x-test]=xxTraditional menu based application launcherxx
|
||||
Comment[zh_CN]=基于菜单的传统程序启动器
|
||||
Comment[zh_TW]=傳統選單式的應用程式啟動器
|
||||
Icon=start-here-kde
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=Plasma/Applet
|
||||
X-KDE-Library=plasma_applet_simplelauncher
|
||||
X-KDE-PluginInfo-Author=Robert Knight
|
||||
X-KDE-PluginInfo-Email=robertknight@gmail.com
|
||||
X-KDE-PluginInfo-Name=simplelauncher
|
||||
X-KDE-PluginInfo-Version=1.0
|
||||
X-KDE-PluginInfo-Website=
|
||||
X-KDE-PluginInfo-Category=Application Launchers
|
||||
X-KDE-PluginInfo-Depends=
|
||||
X-KDE-PluginInfo-License=GPL
|
||||
X-KDE-PluginInfo-EnabledByDefault=false
|
|
@ -1,892 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2008-2009 Sebastian Sauer <mail@dipe.org>
|
||||
Copyright 2009 Christian Loose <christian.loose@kdemail.net>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "simpleapplet/simpleapplet.h"
|
||||
#include "simpleapplet/menuview.h"
|
||||
|
||||
// Katie
|
||||
#include <QtCore/QMetaObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QCheckBox>
|
||||
#include <QtGui/QSpinBox>
|
||||
#include <QtGui/QGridLayout>
|
||||
#include <QtGui/QGraphicsView>
|
||||
#include <QtGui/QGraphicsLinearLayout>
|
||||
#include <QtGui/QSpacerItem>
|
||||
#include <QtGui/QListWidget>
|
||||
|
||||
// KDE Libs
|
||||
#include <KActionCollection>
|
||||
#include <KBookmarkMenu>
|
||||
#include <KCModuleInfo>
|
||||
#include <KComboBox>
|
||||
#include <KConfigDialog>
|
||||
#include <KIcon>
|
||||
#include <KIconButton>
|
||||
#include <KIconLoader>
|
||||
#include <KMenu>
|
||||
#include <KRun>
|
||||
#include <KServiceTypeTrader>
|
||||
#include <KToolInvocation>
|
||||
#include <Solid/PowerManagement>
|
||||
|
||||
// KDE Base
|
||||
#include <kworkspace/kworkspace.h>
|
||||
|
||||
// Plasma
|
||||
#include <Plasma/IconWidget>
|
||||
#include <Plasma/Containment>
|
||||
#include <Plasma/ToolTipManager>
|
||||
|
||||
// Local
|
||||
#include "core/itemhandlers.h"
|
||||
#include "core/models.h"
|
||||
#include "core/applicationmodel.h"
|
||||
#include "core/favoritesmodel.h"
|
||||
#include "core/systemmodel.h"
|
||||
#include "core/recentlyusedmodel.h"
|
||||
#include "core/recentapplications.h"
|
||||
#include "core/leavemodel.h"
|
||||
#include "core/urlitemlauncher.h"
|
||||
#include "ui/contextmenufactory.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QPersistentModelIndex)
|
||||
|
||||
/// @internal KBookmarkOwner specialization
|
||||
class BookmarkOwner : public KBookmarkOwner
|
||||
{
|
||||
public:
|
||||
BookmarkOwner() : KBookmarkOwner() {}
|
||||
virtual bool enableOption(BookmarkOption) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool supportsTabs() const {
|
||||
return false;
|
||||
}
|
||||
virtual void openBookmark(const KBookmark& b, Qt::MouseButtons, Qt::KeyboardModifiers) {
|
||||
new KRun(b.url(), (QWidget*)0);
|
||||
}
|
||||
};
|
||||
|
||||
/// @internal d-pointer class
|
||||
class MenuLauncherApplet::Private
|
||||
{
|
||||
public:
|
||||
MenuLauncherApplet *q;
|
||||
|
||||
QWeakPointer<Kickoff::MenuView> menuview;
|
||||
Plasma::IconWidget *icon;
|
||||
QString iconname;
|
||||
QWeakPointer<Kickoff::UrlItemLauncher> launcher;
|
||||
|
||||
KActionCollection* bookmarkcollection;
|
||||
BookmarkOwner* bookmarkowner;
|
||||
KBookmarkMenu* bookmarkmenu;
|
||||
|
||||
QStringList viewtypes;//QList<MenuLauncherApplet::ViewType>
|
||||
QString relativePath;
|
||||
MenuLauncherApplet::FormatType formattype;
|
||||
int maxRecentApps;
|
||||
bool showMenuTitles;
|
||||
bool showRecentlyInstalled;
|
||||
|
||||
QListWidget *view;
|
||||
KIconButton *iconButton;
|
||||
KComboBox *formatComboBox;
|
||||
QSpinBox *recentApplicationsSpinBox;
|
||||
QCheckBox *showMenuTitlesCheckBox;
|
||||
QCheckBox *showRecentlyInstalledCheckBox;
|
||||
|
||||
QList<QAction*> actions;
|
||||
QAction* switcher;
|
||||
Kickoff::ContextMenuFactory *contextMenuFactory;
|
||||
|
||||
bool delayedConfigLoad;
|
||||
|
||||
explicit Private(MenuLauncherApplet *q)
|
||||
: q(q),
|
||||
icon(0),
|
||||
bookmarkcollection(0),
|
||||
bookmarkowner(0),
|
||||
bookmarkmenu(0),
|
||||
view(0),
|
||||
iconButton(0),
|
||||
formatComboBox(0),
|
||||
showMenuTitlesCheckBox(0),
|
||||
showRecentlyInstalledCheckBox(0),
|
||||
switcher(0),
|
||||
contextMenuFactory(0)
|
||||
{}
|
||||
|
||||
~Private()
|
||||
{
|
||||
delete bookmarkmenu;
|
||||
delete bookmarkowner;
|
||||
delete menuview.data();
|
||||
}
|
||||
|
||||
void setMaxRecentApps(int num) {
|
||||
maxRecentApps = qMax(0, num);
|
||||
if (maxRecentApps > Kickoff::RecentApplications::self()->maximum()) {
|
||||
Kickoff::RecentApplications::self()->setMaximum(maxRecentApps);
|
||||
}
|
||||
}
|
||||
|
||||
void addItem(KComboBox* combo, const QString& caption, int index, const QString& icon = QString())
|
||||
{
|
||||
if (icon.isEmpty()) {
|
||||
combo->addItem(caption, index);
|
||||
} else {
|
||||
combo->addItem(KIcon(icon), caption, index);
|
||||
}
|
||||
}
|
||||
|
||||
void setCurrentItem(KComboBox* combo, int currentIndex)
|
||||
{
|
||||
for (int i = combo->count() - 1; i >= 0; --i) {
|
||||
if (combo->itemData(i).toInt() == currentIndex) {
|
||||
combo->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (combo->count() > 0)
|
||||
combo->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void addModel(QAbstractItemModel *model, ViewType viewtype, Kickoff::MenuView::ModelOptions options = Kickoff::MenuView::MergeFirstLevel, int formattype = -1)
|
||||
{
|
||||
Kickoff::MenuView* mainView = menuview.data();
|
||||
Kickoff::MenuView* m = mainView;
|
||||
if (viewtypes.count() > 1 || !m) {
|
||||
m = new Kickoff::MenuView(mainView, viewText(viewtype), KIcon(viewIcon(viewtype)));
|
||||
m->setFormatType((formattype >= 0 || !mainView) ? (Kickoff::MenuView::FormatType)formattype : mainView->formatType());
|
||||
mainView->addMenu(m);
|
||||
}
|
||||
m->addModel(model, options);
|
||||
}
|
||||
|
||||
QString viewText(MenuLauncherApplet::ViewType vt) const {
|
||||
switch (vt) {
|
||||
case Favorites: return i18n("Favorites");
|
||||
case Bookmarks: return i18n("Bookmarks");
|
||||
case Applications: return i18n("Applications");
|
||||
case Computer: return i18n("Computer");
|
||||
case RecentlyUsed: return i18n("Recently Used");
|
||||
case RecentlyUsedApplications: return i18n("Recently Used Applications");
|
||||
case RecentlyUsedDocuments: return i18n("Recently Used Documents");
|
||||
case Settings: return i18n("System Settings");
|
||||
case SwitchUser: return i18n("Switch User");
|
||||
case SaveSession: return i18n("Save Session");
|
||||
case LockScreen: return i18n("Lock Screen");
|
||||
case SuspendDisk: return i18n("Hibernate");
|
||||
case SuspendRAM: return i18n("Sleep");
|
||||
case HybridSuspend: return i18n("Hybrid Suspend");
|
||||
case Restart: return i18nc("Restart Computer", "Restart");
|
||||
case Shutdown: return i18n("Shut down");
|
||||
case Logout: return i18n("Log out");
|
||||
case Leave: return i18n("Leave");
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString viewIcon(MenuLauncherApplet::ViewType vt) const {
|
||||
switch (vt) {
|
||||
case Favorites: return "bookmarks";
|
||||
case Bookmarks: return "folder-bookmarks";
|
||||
case Applications: return "applications-other";
|
||||
case Computer: return "computer";
|
||||
case RecentlyUsed: return "document-open-recent";
|
||||
case RecentlyUsedApplications: return "document-open-recent";
|
||||
case RecentlyUsedDocuments: return "document-open-recent";
|
||||
case Settings: return "preferences-system";
|
||||
case SwitchUser: return "system-switch-user";
|
||||
case SaveSession: return "document-save";
|
||||
case LockScreen: return "system-lock-screen";
|
||||
case SuspendDisk: return "system-suspend-hibernate";
|
||||
case SuspendRAM: return "system-suspend-hibernate";
|
||||
case HybridSuspend: return "system-suspend";
|
||||
case Restart: return "system-reboot";
|
||||
case Shutdown: return "system-shutdown";
|
||||
case Logout: return "system-log-out";
|
||||
case Leave: return "system-shutdown";
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
MenuLauncherApplet::ViewType viewType(const QByteArray& type) const {
|
||||
QMetaEnum e = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewType"));
|
||||
return (MenuLauncherApplet::ViewType) e.keyToValue(type);
|
||||
}
|
||||
|
||||
/*
|
||||
QByteArray viewType(MenuLauncherApplet::ViewType type) const {
|
||||
QMetaEnum e = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewType"));
|
||||
return e.valueToKey(types);
|
||||
}
|
||||
QList<MenuLauncherApplet::ViewType> viewTypes(const QStringList &types) const {
|
||||
QList<MenuLauncherApplet::ViewType> l;
|
||||
foreach(QString t, types) l << viewType(t.toUtf());
|
||||
return l;
|
||||
}
|
||||
QStringList viewTypes(const QList<MenuLauncherApplet::ViewType> &types) const {
|
||||
QStringList l;
|
||||
foreach(MenuLauncherApplet::ViewType t, types) l << viewType(t);
|
||||
return l;
|
||||
}
|
||||
*/
|
||||
|
||||
void updateTooltip() {
|
||||
QStringList names;
|
||||
foreach(const QString &vtname, viewtypes)
|
||||
names << viewText(viewType(vtname.toUtf8()));
|
||||
Plasma::ToolTipContent data(i18n("Application Launcher Menu"), names.join(", "), icon->icon());
|
||||
Plasma::ToolTipManager::self()->setContent(q, data);
|
||||
}
|
||||
};
|
||||
|
||||
MenuLauncherApplet::MenuLauncherApplet(QObject *parent, const QVariantList &args)
|
||||
: Plasma::Applet(parent, args),
|
||||
d(new Private(this))
|
||||
{
|
||||
KGlobal::locale()->insertCatalog("plasma_applet_launcher");
|
||||
|
||||
setAspectRatioMode(Plasma::ConstrainedSquare);
|
||||
setHasConfigurationInterface(true);
|
||||
setBackgroundHints(NoBackground);
|
||||
|
||||
resize(IconSize(KIconLoader::Desktop) * 2, IconSize(KIconLoader::Desktop) * 2);
|
||||
|
||||
d->icon = new Plasma::IconWidget(QString(), this);
|
||||
d->icon->setFlag(ItemIsMovable, false);
|
||||
connect(d->icon, SIGNAL(pressed(bool)), this, SLOT(showMenu(bool)));
|
||||
connect(this, SIGNAL(activate()), this, SLOT(toggleMenu()));
|
||||
|
||||
d->delayedConfigLoad = false;
|
||||
switch(args.count()) {
|
||||
case 2: { //Use submenu paths
|
||||
d->viewtypes << "Applications";
|
||||
d->relativePath = args.value(0).toString();
|
||||
d->iconname = args.value(1).toString();
|
||||
break;
|
||||
}
|
||||
case 1: { //Check for delayed config (switch from Kickoff)
|
||||
d->delayedConfigLoad = true;
|
||||
//Do not "break;", as we may need the default views configuration
|
||||
//(if SimpleLauncher was never used before)
|
||||
}
|
||||
default: { //Default configuration
|
||||
d->viewtypes << "RecentlyUsedApplications" << "Applications" << "Favorites";
|
||||
d->viewtypes << "Leave";
|
||||
d->iconname = "start-here-kde";
|
||||
}
|
||||
}
|
||||
d->formattype = NameDescription;
|
||||
|
||||
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
layout->addItem(d->icon);
|
||||
|
||||
d->contextMenuFactory = new Kickoff::ContextMenuFactory(this);
|
||||
d->contextMenuFactory->setApplet(this);
|
||||
}
|
||||
|
||||
MenuLauncherApplet::~MenuLauncherApplet()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::init()
|
||||
{
|
||||
bool receivedArgs = false;
|
||||
if (!d->relativePath.isEmpty()) {
|
||||
receivedArgs = true;
|
||||
}
|
||||
|
||||
configChanged();
|
||||
|
||||
Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ExtensionHandler, "desktop", new Kickoff::ServiceItemHandler);
|
||||
Kickoff::UrlItemLauncher::addGlobalHandler(Kickoff::UrlItemLauncher::ProtocolHandler, "leave", new Kickoff::LeaveItemHandler);
|
||||
|
||||
if (KService::serviceByStorageId("kmenuedit.desktop")) {
|
||||
QAction* menueditor = new QAction(i18n("Edit Applications..."), this);
|
||||
d->actions.append(menueditor);
|
||||
connect(menueditor, SIGNAL(triggered(bool)), this, SLOT(startMenuEditor()));
|
||||
}
|
||||
|
||||
Q_ASSERT(! d->switcher);
|
||||
d->switcher = new QAction(i18n("Switch to Application Launcher Style"), this);
|
||||
d->actions.append(d->switcher);
|
||||
connect(d->switcher, SIGNAL(triggered(bool)), this, SLOT(switchMenuStyle()));
|
||||
|
||||
if (receivedArgs) {
|
||||
KConfigGroup cg = config();
|
||||
cg.writeEntry("relativePath", d->relativePath);
|
||||
cg.writeEntry("icon", d->iconname);
|
||||
emit configNeedsSaving();
|
||||
}
|
||||
|
||||
connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
|
||||
this, SLOT(iconSizeChanged(int)));
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::constraintsEvent(Plasma::Constraints constraints)
|
||||
{
|
||||
setBackgroundHints(NoBackground);
|
||||
if (constraints & Plasma::FormFactorConstraint) {
|
||||
if (formFactor() == Plasma::Planar || formFactor() == Plasma::MediaCenter) {
|
||||
//FIXME set correct minimum size
|
||||
//setMinimumContentSize(d->icon->sizeFromIconSize(IconSize(KIconLoader::Desktop)));
|
||||
} else {
|
||||
//setMinimumContentSize(d->icon->sizeFromIconSize(IconSize(KIconLoader::Small)));
|
||||
}
|
||||
}
|
||||
|
||||
if ((constraints & Plasma::ImmutableConstraint) && d->switcher) {
|
||||
d->switcher->setVisible(immutability() == Plasma::Mutable);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::switchMenuStyle()
|
||||
{
|
||||
if (containment()) {
|
||||
Plasma::Applet *launcher = containment()->addApplet("launcher", QVariantList(), geometry());
|
||||
//Copy all the config items to the simple launcher
|
||||
QMetaObject::invokeMethod(launcher, "saveConfigurationFromSimpleLauncher",
|
||||
Qt::DirectConnection, Q_ARG(KConfigGroup, config()),
|
||||
Q_ARG(KConfigGroup, globalConfig()));
|
||||
|
||||
//Switch shortcuts with the new launcher to avoid losing it
|
||||
KShortcut currentShortcut = globalShortcut();
|
||||
setGlobalShortcut(KShortcut());
|
||||
launcher->setGlobalShortcut(currentShortcut);
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::startMenuEditor()
|
||||
{
|
||||
KToolInvocation::kdeinitExec("kmenuedit");
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::customContextMenuRequested(QMenu* menu, const QPoint& pos)
|
||||
{
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
// there are 2 possible cases
|
||||
// 1) An an actual action is active - menu is the menu containing the action wanted
|
||||
// 2) either a submenu is active, but none of its actions are active. menu is the submenu,
|
||||
// not the menu containing the submenu
|
||||
QAction* menuAction = menu->activeAction();
|
||||
if (menuAction) { // case 1)
|
||||
const QPersistentModelIndex index = menuAction->data().value<QPersistentModelIndex>();
|
||||
d->contextMenuFactory->showContextMenu(0, index, pos);
|
||||
} else { // case 2)
|
||||
menuAction = menu->menuAction();
|
||||
if (menuAction) {
|
||||
const QPersistentModelIndex index = menuAction->data().value<QPersistentModelIndex>();
|
||||
d->contextMenuFactory->showContextMenu(0, index, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::createConfigurationInterface(KConfigDialog *parent)
|
||||
{
|
||||
d->view = 0;
|
||||
d->recentApplicationsSpinBox = 0;
|
||||
if (d->relativePath.isEmpty()) {
|
||||
QWidget *viewpage = new QWidget(parent);
|
||||
QVBoxLayout *l = new QVBoxLayout(viewpage);
|
||||
l->setMargin(0);
|
||||
viewpage->setLayout(l);
|
||||
d->view = new QListWidget(viewpage);
|
||||
d->view->resize(300,500);
|
||||
l->addWidget(d->view);
|
||||
|
||||
QMetaEnum vte = metaObject()->enumerator(metaObject()->indexOfEnumerator("ViewType"));
|
||||
for(int i = 0; i < vte.keyCount(); ++i) {
|
||||
ViewType vt = (ViewType) vte.value(i);
|
||||
const QByteArray vtname = vte.key(i);
|
||||
QListWidgetItem *item = new QListWidgetItem(KIcon(d->viewIcon(vt)), d->viewText(vt), d->view);
|
||||
item->setCheckState(d->viewtypes.contains(vtname) ? Qt::Checked : Qt::Unchecked);
|
||||
item->setData(Qt::UserRole, vtname);
|
||||
d->view->addItem(item);
|
||||
}
|
||||
parent->addPage(viewpage, i18n("View"), "view-list-details");
|
||||
}
|
||||
|
||||
QWidget *p = new QWidget(parent);
|
||||
QGridLayout *grid = new QGridLayout(p);
|
||||
grid->setMargin(0);
|
||||
|
||||
QLabel *iconLabel = new QLabel(i18n("Icon:"), p);
|
||||
grid->addWidget(iconLabel, 0, 0, Qt::AlignRight);
|
||||
d->iconButton = new KIconButton(p);
|
||||
d->iconButton->setIcon(d->icon->icon());
|
||||
iconLabel->setBuddy(d->iconButton);
|
||||
grid->addWidget(d->iconButton, 0, 1);
|
||||
|
||||
QLabel *formatLabel = new QLabel(i18nc("@label:listbox How to present applications in a KMenu-like menu", "Format:"), p);
|
||||
grid->addWidget(formatLabel, 1, 0, Qt::AlignRight);
|
||||
d->formatComboBox = new KComboBox(p);
|
||||
formatLabel->setBuddy(d->formatComboBox);
|
||||
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name Only"), MenuLauncherApplet::Name);
|
||||
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Description Only"), MenuLauncherApplet::Description);
|
||||
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name (Description)"), MenuLauncherApplet::NameDescription);
|
||||
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Description (Name)"), MenuLauncherApplet::DescriptionName);
|
||||
d->addItem(d->formatComboBox, i18nc("@item:inlistbox Format:", "Name - Description"), MenuLauncherApplet::NameDashDescription);
|
||||
d->setCurrentItem(d->formatComboBox, d->formattype);
|
||||
grid->addWidget(d->formatComboBox, 1, 1);
|
||||
|
||||
if (d->relativePath.isEmpty()) {
|
||||
QLabel *recentLabel = new QLabel(i18n("Recently used applications:"), p);
|
||||
grid->addWidget(recentLabel, 2, 0, Qt::AlignRight);
|
||||
d->recentApplicationsSpinBox = new QSpinBox(p);
|
||||
d->recentApplicationsSpinBox->setMaximum(10);
|
||||
d->recentApplicationsSpinBox->setMinimum(0);
|
||||
d->recentApplicationsSpinBox->setValue(d->maxRecentApps);
|
||||
recentLabel->setBuddy(d->recentApplicationsSpinBox);
|
||||
grid->addWidget(d->recentApplicationsSpinBox, 2, 1);
|
||||
}
|
||||
|
||||
QLabel *showMenuTitlesLabel = new QLabel(i18n("Show menu titles:"), p);
|
||||
grid->addWidget(showMenuTitlesLabel, 3, 0, Qt::AlignRight);
|
||||
d->showMenuTitlesCheckBox = new QCheckBox(p);
|
||||
d->showMenuTitlesCheckBox->setChecked(d->showMenuTitles);
|
||||
grid->addWidget(d->showMenuTitlesCheckBox, 3, 1);
|
||||
|
||||
QLabel *showMenuRecentlyInstalledLabel = new QLabel(i18n("Show 'Recently Installed':"), p);
|
||||
grid->addWidget(showMenuRecentlyInstalledLabel, 4, 0, Qt::AlignRight);
|
||||
d->showRecentlyInstalledCheckBox = new QCheckBox(p);
|
||||
d->showRecentlyInstalledCheckBox->setChecked(d->showRecentlyInstalled);
|
||||
grid->addWidget(d->showRecentlyInstalledCheckBox, 4, 1);
|
||||
|
||||
grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), 5, 0, 1, 3);
|
||||
parent->addPage(p, i18n("Options"), "configure");
|
||||
|
||||
connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
|
||||
connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
|
||||
connect(d->iconButton, SIGNAL(iconChanged(QString)), parent, SLOT(settingsModified()));
|
||||
connect(d->formatComboBox, SIGNAL(currentIndexChanged(QString)), parent, SLOT(settingsModified()));
|
||||
connect(d->recentApplicationsSpinBox, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
|
||||
connect(d->showMenuTitlesCheckBox, SIGNAL(toggled(bool)), parent, SLOT(settingsModified()));
|
||||
connect(d->showRecentlyInstalledCheckBox, SIGNAL(toggled(bool)), parent, SLOT(settingsModified()));
|
||||
connect(d->view, SIGNAL(currentTextChanged(QString)), parent, SLOT(settingsModified()));
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::configAccepted()
|
||||
{
|
||||
bool needssaving = false;
|
||||
KConfigGroup cg = config();
|
||||
|
||||
if (d->view) {
|
||||
QStringList viewtypes;
|
||||
for(int i = 0; i < d->view->count(); ++i) {
|
||||
QListWidgetItem *item = d->view->item(i);
|
||||
QByteArray vtname = item->data(Qt::UserRole).toByteArray();
|
||||
if(item->checkState() == Qt::Checked)
|
||||
viewtypes << vtname;
|
||||
if( !needssaving && ((item->checkState() == Qt::Checked && ! d->viewtypes.contains(vtname)) || (item->checkState() == Qt::Unchecked && d->viewtypes.contains(vtname))) )
|
||||
needssaving = true;
|
||||
}
|
||||
if(needssaving) {
|
||||
d->viewtypes = viewtypes;
|
||||
d->updateTooltip();
|
||||
cg.writeEntry("views", d->viewtypes);
|
||||
cg.deleteEntry("view"); // "view" was from <KDE4.3, we are using "views" now
|
||||
}
|
||||
}
|
||||
|
||||
const QString iconname = d->iconButton->icon();
|
||||
if (! iconname.isEmpty()) {
|
||||
needssaving = true;
|
||||
d->icon->setIcon(KIcon(iconname));
|
||||
d->updateTooltip();
|
||||
cg.writeEntry("icon", iconname);
|
||||
}
|
||||
|
||||
const int ft = d->formatComboBox->itemData(d->formatComboBox->currentIndex()).toInt();
|
||||
if (ft != d->formattype) {
|
||||
needssaving = true;
|
||||
d->formattype = (MenuLauncherApplet::FormatType) ft;
|
||||
QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
|
||||
cg.writeEntry("format", QByteArray(e.valueToKey(d->formattype)));
|
||||
}
|
||||
|
||||
if (d->recentApplicationsSpinBox) {
|
||||
const int maxRecentApps = d->recentApplicationsSpinBox->value();
|
||||
if (maxRecentApps != d->maxRecentApps) {
|
||||
needssaving = true;
|
||||
d->setMaxRecentApps(maxRecentApps);
|
||||
cg.writeEntry("maxRecentApps", maxRecentApps);
|
||||
}
|
||||
}
|
||||
|
||||
const bool showMenuTitles = d->showMenuTitlesCheckBox->isChecked();
|
||||
if (showMenuTitles != d->showMenuTitles) {
|
||||
needssaving = true;
|
||||
d->showMenuTitles = showMenuTitles;
|
||||
cg.writeEntry("showMenuTitles", showMenuTitles);
|
||||
}
|
||||
|
||||
const bool showRecentlyInstalled = d->showRecentlyInstalledCheckBox->isChecked();
|
||||
if (showRecentlyInstalled != d->showRecentlyInstalled) {
|
||||
needssaving = true;
|
||||
d->showRecentlyInstalled = showRecentlyInstalled;
|
||||
cg.writeEntry("showRecentlyInstalled", showRecentlyInstalled);
|
||||
}
|
||||
|
||||
if (needssaving) {
|
||||
d->updateTooltip();
|
||||
emit configNeedsSaving();
|
||||
if (d->menuview) {
|
||||
d->menuview.data()->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int weightOfService( const KService::Ptr service )
|
||||
{
|
||||
QVariant tmp = service->property("X-KDE-Weight", QVariant::Int);
|
||||
return (tmp.isValid() ? tmp.toInt() : 100);
|
||||
}
|
||||
inline bool sortServiceItemsByWeight(const KService::Ptr left, const KService::Ptr right)
|
||||
{
|
||||
return weightOfService(left) < weightOfService(right);
|
||||
}
|
||||
KService::List sortServices(KService::List list)
|
||||
{
|
||||
qSort(list.begin(), list.end(), sortServiceItemsByWeight);
|
||||
return list;
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::toggleMenu()
|
||||
{
|
||||
showMenu(!d->menuview || !d->menuview.data()->isVisible());
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::showMenu(bool pressed)
|
||||
{
|
||||
if (!pressed || d->viewtypes.count()<=0) {
|
||||
if (d->menuview) {
|
||||
d->menuview.data()->deleteLater();
|
||||
d->menuview.clear();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
d->icon->setPressed();
|
||||
|
||||
if (!d->menuview) {
|
||||
Kickoff::MenuView *menuview = new Kickoff::MenuView();
|
||||
d->menuview = menuview;
|
||||
menuview->setAttribute(Qt::WA_DeleteOnClose);
|
||||
menuview->setFormatType( (Kickoff::MenuView::FormatType) d->formattype );
|
||||
menuview->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(menuview, SIGNAL(triggered(QAction*)), this, SLOT(actionTriggered(QAction*)));
|
||||
connect(menuview, SIGNAL(aboutToHide()), this, SLOT(menuHiding()));
|
||||
connect(menuview, SIGNAL(customContextMenuRequested(QMenu*,QPoint)),
|
||||
this, SLOT(customContextMenuRequested(QMenu*,QPoint)));
|
||||
//connect(menuview, SIGNAL(afterBeingHidden()), menuview, SLOT(deleteLater()));
|
||||
|
||||
//Kickoff::MenuView::ModelOptions options = d->viewtypes.count() < 2 ? Kickoff::MenuView::MergeFirstLevel : Kickoff::MenuView::None;
|
||||
foreach(const QString &vtname, d->viewtypes) {
|
||||
if(vtname == "Applications") {
|
||||
Kickoff::ApplicationModel *appModel = new Kickoff::ApplicationModel(menuview, true /*allow separators*/);
|
||||
appModel->setApplet(this);
|
||||
appModel->setDuplicatePolicy(Kickoff::ApplicationModel::ShowLatestOnlyPolicy);
|
||||
if (d->formattype == Name || d->formattype == NameDescription || d->formattype == NameDashDescription) {
|
||||
appModel->setNameDisplayOrder(Kickoff::NameBeforeDescription);
|
||||
appModel->setPrimaryNamePolicy(Kickoff::ApplicationModel::AppNamePrimary);
|
||||
}
|
||||
appModel->setSystemApplicationPolicy(Kickoff::ApplicationModel::ShowApplicationAndSystemPolicy);
|
||||
appModel->setShowRecentlyInstalled(d->showRecentlyInstalled);
|
||||
|
||||
menuview->addModel(appModel, Kickoff::MenuView::None, d->relativePath);
|
||||
|
||||
if (d->relativePath.isEmpty()) {
|
||||
if (d->showMenuTitles) {
|
||||
menuview->setModelTitleVisible(appModel, true);
|
||||
menuview->addTitle(i18n("Actions"));
|
||||
} else {
|
||||
menuview->addSeparator();
|
||||
}
|
||||
}
|
||||
} else if(vtname == "Favorites") {
|
||||
Kickoff::FavoritesModel *favoritesModel = new Kickoff::FavoritesModel(menuview);
|
||||
if (d->formattype == Name || d->formattype == NameDescription || d->formattype == NameDashDescription) {
|
||||
favoritesModel->setNameDisplayOrder(Kickoff::NameBeforeDescription);
|
||||
}
|
||||
d->addModel(favoritesModel, Favorites);
|
||||
} else if(vtname == "Computer") {
|
||||
d->addModel(new Kickoff::SystemModel(menuview), Computer);
|
||||
} else if(vtname == "RecentlyUsed") {
|
||||
Kickoff::RecentlyUsedModel *recentModel = new Kickoff::RecentlyUsedModel(menuview);
|
||||
if (d->formattype == Name || d->formattype == NameDescription || d->formattype == NameDashDescription) {
|
||||
recentModel->setNameDisplayOrder(Kickoff::NameBeforeDescription);
|
||||
}
|
||||
d->addModel(recentModel, RecentlyUsed);
|
||||
} else if(vtname == "RecentlyUsedApplications") {
|
||||
if (d->maxRecentApps > 0) {
|
||||
Kickoff::RecentlyUsedModel *recentModel = new Kickoff::RecentlyUsedModel(menuview, Kickoff::RecentlyUsedModel::ApplicationsOnly, d->maxRecentApps);
|
||||
if (d->formattype == Name || d->formattype == NameDescription || d->formattype == NameDashDescription) {
|
||||
recentModel->setNameDisplayOrder(Kickoff::NameBeforeDescription);
|
||||
}
|
||||
menuview->addModel(recentModel, Kickoff::MenuView::MergeFirstLevel);
|
||||
|
||||
if (d->showMenuTitles) {
|
||||
menuview->setModelTitleVisible(recentModel, true);
|
||||
} else {
|
||||
menuview->addSeparator();
|
||||
}
|
||||
}
|
||||
} else if(vtname == "RecentlyUsedDocuments") {
|
||||
Kickoff::RecentlyUsedModel *recentModel = new Kickoff::RecentlyUsedModel(menuview, Kickoff::RecentlyUsedModel::DocumentsOnly);
|
||||
menuview->addModel(recentModel, Kickoff::MenuView::MergeFirstLevel);
|
||||
|
||||
if (d->showMenuTitles) {
|
||||
menuview->setModelTitleVisible(recentModel, true);
|
||||
} else {
|
||||
menuview->addSeparator();
|
||||
}
|
||||
} else if(vtname == "Bookmarks") {
|
||||
KMenu* menu = menuview;
|
||||
if(d->viewtypes.count() > 1) {
|
||||
menu = new KMenu(d->viewText(Bookmarks), menuview);
|
||||
menu->setIcon(KIcon(d->viewIcon(Bookmarks)));
|
||||
menuview->addMenu(menu);
|
||||
}
|
||||
KBookmarkManager* mgr = KBookmarkManager::userBookmarksManager();
|
||||
if (! d->bookmarkcollection) {
|
||||
d->bookmarkcollection = new KActionCollection(this);
|
||||
d->bookmarkowner = new BookmarkOwner();
|
||||
}
|
||||
delete d->bookmarkmenu;
|
||||
d->bookmarkmenu = new KBookmarkMenu(mgr, d->bookmarkowner, menu, d->bookmarkcollection);
|
||||
} else if(vtname == "Settings") {
|
||||
KMenu* parentmenu = menuview;
|
||||
if(d->viewtypes.count() > 1) {
|
||||
parentmenu = new KMenu(d->viewText(Settings), menuview);
|
||||
parentmenu->setIcon(KIcon(d->viewIcon(Settings)));
|
||||
menuview->addMenu(parentmenu);
|
||||
}
|
||||
QMap<QString, KMenu*> menus;
|
||||
foreach(const KService::Ptr &rootentry, sortServices(KServiceTypeTrader::self()->query("SystemSettingsCategory", "(not exist [X-KDE-System-Settings-Parent-Category]) or [X-KDE-System-Settings-Parent-Category]==''"))) {
|
||||
parentmenu->addTitle(rootentry->name().replace('&',"&&"));
|
||||
const QString rootcategory = rootentry->property("X-KDE-System-Settings-Category").toString();
|
||||
foreach(const KService::Ptr &entry, sortServices(KServiceTypeTrader::self()->query("SystemSettingsCategory", QString("[X-KDE-System-Settings-Parent-Category]=='%1'").arg(rootcategory)))) {
|
||||
KMenu* menu = new KMenu(entry->name().replace('&',"&&"), parentmenu);
|
||||
menu->setIcon(KIcon(entry->icon()));
|
||||
parentmenu->addMenu(menu);
|
||||
const QString category = entry->property("X-KDE-System-Settings-Category").toString();
|
||||
menus[category] = menu;
|
||||
}
|
||||
}
|
||||
QMap<QString, QList<KService::Ptr> > modules;
|
||||
foreach(const KService::Ptr &entry, sortServices(KServiceTypeTrader::self()->query("KCModule"))) {
|
||||
const QString category = entry->property("X-KDE-System-Settings-Parent-Category").toString();
|
||||
if(! category.isEmpty() && ! entry->noDisplay())
|
||||
modules[category] << entry;
|
||||
}
|
||||
foreach(const QString& category, modules.keys()) {
|
||||
QString menucategory = category;
|
||||
KService::Ptr subcategory = KService::Ptr();
|
||||
while(! menucategory.isEmpty() && ! menus.contains(menucategory)) {
|
||||
KService::List services = KServiceTypeTrader::self()->query("SystemSettingsCategory", QString("[X-KDE-System-Settings-Category]=='%1'").arg(menucategory));
|
||||
//Q_ASSERT(services.count() > 0); //if that happens then we miss the desktop-file defining the category
|
||||
//Q_ASSERT(services.count() < 2); //if that happens then we have more then one desktop-file defining the same category
|
||||
if(services.count() < 1) {
|
||||
menucategory.clear();
|
||||
} else {
|
||||
subcategory = services[0];
|
||||
menucategory = subcategory->property("X-KDE-System-Settings-Parent-Category").toString();
|
||||
}
|
||||
}
|
||||
if(menucategory.isEmpty()) continue; //skip the category
|
||||
KMenu* m = menus[menucategory];
|
||||
if(! subcategory.isNull())
|
||||
m->addTitle(subcategory->name().replace('&',"&&"));
|
||||
foreach(const KService::Ptr &entry, modules[category]) {
|
||||
KCModuleInfo module(entry->entryPath());
|
||||
m->addAction(KIcon(module.icon()), module.moduleName().replace('&',"&&"))->setData(KUrl("kcm:/" + entry->entryPath()));
|
||||
}
|
||||
}
|
||||
} else if(vtname == "SwitchUser") {
|
||||
menuview->addAction(KIcon(d->viewIcon(SwitchUser)), d->viewText(SwitchUser))->setData(KUrl("leave:/switch"));
|
||||
} else if(vtname == "SaveSession") {
|
||||
KConfigGroup c(KSharedConfig::openConfig("ksmserverrc", KConfig::NoGlobals), "General");
|
||||
if (c.readEntry("loginMode") == "restoreSavedSession")
|
||||
menuview->addAction(KIcon(d->viewIcon(SaveSession)), d->viewText(SaveSession))->setData(KUrl("leave:/savesession"));
|
||||
} else if(vtname == "LockScreen") {
|
||||
menuview->addAction(KIcon(d->viewIcon(LockScreen)), d->viewText(LockScreen))->setData(KUrl("leave:/lock"));
|
||||
} else if(vtname == "Logout") {
|
||||
menuview->addAction(KIcon(d->viewIcon(Logout)), d->viewText(Logout))->setData(KUrl("leave:/logout"));
|
||||
} else if(vtname == "Leave") {
|
||||
Kickoff::LeaveModel *leavemodel = new Kickoff::LeaveModel(menuview);
|
||||
leavemodel->updateModel();
|
||||
d->addModel(leavemodel, Leave, Kickoff::MenuView::MergeFirstLevel, Kickoff::MenuView::Name);
|
||||
} else {
|
||||
QSet< Solid::PowerManagement::SleepState > spdMethods = Solid::PowerManagement::supportedSleepStates();
|
||||
if(vtname == "SuspendDisk") {
|
||||
if (spdMethods.contains(Solid::PowerManagement::HibernateState))
|
||||
menuview->addAction(KIcon(d->viewIcon(SuspendDisk)), d->viewText(SuspendDisk))->setData(KUrl("leave:/suspenddisk"));
|
||||
} else if(vtname == "SuspendRAM") {
|
||||
if (spdMethods.contains(Solid::PowerManagement::SuspendState))
|
||||
menuview->addAction(KIcon(d->viewIcon(SuspendRAM)), d->viewText(SuspendRAM))->setData(KUrl("leave:/suspendram"));
|
||||
} else if (vtname == "HybridSuspend") {
|
||||
if (spdMethods.contains(Solid::PowerManagement::HybridSuspendState))
|
||||
menuview->addAction(KIcon(d->viewIcon(HybridSuspend)), d->viewText(HybridSuspend))->setData(KUrl("leave:/suspendhybrid"));
|
||||
} else if(vtname == "Restart") {
|
||||
if (KWorkSpace::canShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeReboot))
|
||||
menuview->addAction(KIcon(d->viewIcon(Restart)), d->viewText(Restart))->setData(KUrl("leave:/restart"));
|
||||
} else if(vtname == "Shutdown") {
|
||||
if (KWorkSpace::canShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeHalt))
|
||||
menuview->addAction(KIcon(d->viewIcon(Shutdown)), d->viewText(Shutdown))->setData(KUrl("leave:/shutdown"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Plasma::ToolTipManager::self()->hide(this);
|
||||
setStatus(Plasma::NeedsAttentionStatus);
|
||||
d->menuview.data()->popup(popupPosition(d->menuview.data()->sizeHint()));
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::menuHiding()
|
||||
{
|
||||
d->icon->setUnpressed();
|
||||
setStatus(Plasma::PassiveStatus);
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::actionTriggered(QAction *action)
|
||||
{
|
||||
const KUrl url = action->data().value<KUrl>();
|
||||
if (url.scheme() == "leave") {
|
||||
if (!d->launcher) {
|
||||
d->launcher = new Kickoff::UrlItemLauncher(d->menuview.data());
|
||||
}
|
||||
|
||||
d->launcher.data()->openUrl(url.url());
|
||||
return;
|
||||
}
|
||||
if (url.scheme() == "kcm") {
|
||||
KToolInvocation::kdeinitExec("kcmshell4", QStringList() << url.fileName());
|
||||
return;
|
||||
}
|
||||
for (QWidget* w = action->parentWidget(); w; w = w->parentWidget()) {
|
||||
if (Kickoff::MenuView *view = qobject_cast<Kickoff::MenuView*>(w)) {
|
||||
view->actionTriggered(action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QAction*> MenuLauncherApplet::contextualActions()
|
||||
{
|
||||
return d->actions;
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::iconSizeChanged(int group)
|
||||
{
|
||||
if (group == KIconLoader::Desktop || group == KIconLoader::Panel) {
|
||||
updateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
QSizeF MenuLauncherApplet::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
|
||||
{
|
||||
if (which == Qt::PreferredSize) {
|
||||
int iconSize = -1;
|
||||
|
||||
switch (formFactor()) {
|
||||
case Plasma::Planar:
|
||||
case Plasma::MediaCenter:
|
||||
iconSize = IconSize(KIconLoader::Desktop);
|
||||
break;
|
||||
|
||||
case Plasma::Horizontal:
|
||||
case Plasma::Vertical:
|
||||
iconSize = IconSize(KIconLoader::Panel);
|
||||
break;
|
||||
}
|
||||
|
||||
return QSizeF(iconSize, iconSize);
|
||||
}
|
||||
|
||||
return Plasma::Applet::sizeHint(which, constraint);
|
||||
}
|
||||
|
||||
|
||||
void MenuLauncherApplet::saveConfigurationFromKickoff(const KConfigGroup & configGroup, const KConfigGroup & globalConfigGroup)
|
||||
{
|
||||
//Copy configuration values
|
||||
KConfigGroup cg = config();
|
||||
configGroup.copyTo(&cg);
|
||||
|
||||
KConfigGroup gcg = globalConfig();
|
||||
globalConfigGroup.copyTo(&gcg);
|
||||
|
||||
configChanged();
|
||||
emit configNeedsSaving();
|
||||
}
|
||||
|
||||
void MenuLauncherApplet::configChanged()
|
||||
{
|
||||
KConfigGroup cg = config();
|
||||
|
||||
const QStringList viewtypes = cg.readEntry("views", QStringList());
|
||||
if(viewtypes.isEmpty()) { // backward-compatibility to <KDE4.3
|
||||
QByteArray oldview = cg.readEntry("view", QByteArray());
|
||||
if (!oldview.isEmpty() && oldview != "Combined") {
|
||||
d->viewtypes = QStringList() << oldview;
|
||||
d->iconname = d->viewIcon(d->viewType(oldview));
|
||||
} // else we use the default d->viewtypes
|
||||
} else {
|
||||
d->viewtypes = viewtypes;
|
||||
}
|
||||
|
||||
QMetaEnum fte = metaObject()->enumerator(metaObject()->indexOfEnumerator("FormatType"));
|
||||
QByteArray ftb = cg.readEntry("format", QByteArray(fte.valueToKey(d->formattype)));
|
||||
d->formattype = (MenuLauncherApplet::FormatType) fte.keyToValue(ftb);
|
||||
|
||||
d->setMaxRecentApps(cg.readEntry("maxRecentApps", qMin(5, Kickoff::RecentApplications::self()->maximum())));
|
||||
d->showMenuTitles = cg.readEntry("showMenuTitles", false);
|
||||
d->showRecentlyInstalled = cg.readEntry("showRecentlyInstalled", true);
|
||||
|
||||
d->icon->setIcon(KIcon(cg.readEntry("icon", d->iconname)));
|
||||
|
||||
d->relativePath = cg.readEntry("relativePath", d->relativePath);
|
||||
if (!d->relativePath.isEmpty()) {
|
||||
d->viewtypes.clear();
|
||||
d->viewtypes << "Applications";
|
||||
}
|
||||
|
||||
d->updateTooltip();
|
||||
|
||||
constraintsEvent(Plasma::ImmutableConstraint);
|
||||
}
|
||||
|
||||
#include "moc_simpleapplet.cpp"
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2008-2009 Sebastian Sauer <mail@dipe.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SIMPLEAPPLET_H
|
||||
#define SIMPLEAPPLET_H
|
||||
|
||||
// Plasma
|
||||
#include <Plasma/Applet>
|
||||
|
||||
#include <QAction>
|
||||
|
||||
/**
|
||||
* The MenuLauncherApplet class implements an applet that provides the traditional
|
||||
* aka classic KDE3 like KMenu application launcher using the Kickoff functionality.
|
||||
*/
|
||||
class MenuLauncherApplet : public Plasma::Applet
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(ViewType)
|
||||
Q_ENUMS(FormatType)
|
||||
public:
|
||||
|
||||
/**
|
||||
* The content we like to display within the menu.
|
||||
*/
|
||||
enum ViewType {
|
||||
RecentlyUsedApplications, ///< Recently Used Applications Menu
|
||||
RecentlyUsedDocuments, ///< Recently Used Documents Menu
|
||||
Applications, ///< Applications Menu
|
||||
Favorites, ///< Favorites Menu
|
||||
Bookmarks, ///< Bookmarks Menu
|
||||
Computer, ///< Computer Menu
|
||||
RecentlyUsed, ///< Recently Used Menu
|
||||
Settings, ///< Settings Menu
|
||||
SwitchUser, ///< Switch User Action
|
||||
SaveSession, ///< Save Session Action (only enabled if restoreSavedSession is enabled)
|
||||
LockScreen, ///< Lock Screen Action
|
||||
SuspendDisk, ///< Suspend to Disk Action
|
||||
SuspendRAM, ///< Suspend to RAM Action
|
||||
HybridSuspend, ///< Hybrid Suspend Action
|
||||
Restart, ///< Restart Action
|
||||
Shutdown, ///< Shutdown Action
|
||||
Logout, ///< Logout Action
|
||||
Leave ///< Leave Menu
|
||||
};
|
||||
|
||||
/**
|
||||
* How the text of the menuitems got formatted.
|
||||
*/
|
||||
enum FormatType {
|
||||
Name = 0, ///< Name only
|
||||
Description, ///< Description only
|
||||
NameDescription, ///< Name Description
|
||||
DescriptionName, ///< Description (Name)
|
||||
NameDashDescription ///< Name - Description
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* \param parent The parent QObject.
|
||||
* \param args The optional list of arguments.
|
||||
*/
|
||||
MenuLauncherApplet(QObject *parent, const QVariantList &args);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~MenuLauncherApplet();
|
||||
|
||||
/**
|
||||
* This method is called once the applet is loaded and added to a Corona.
|
||||
**/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Called when any of the geometry constraints have been updated.
|
||||
*
|
||||
* @param constraints the type of constraints that were updated
|
||||
*/
|
||||
void constraintsEvent(Plasma::Constraints constraints);
|
||||
|
||||
/**
|
||||
* Returns a list of context-related QAction instances.
|
||||
*/
|
||||
virtual QList<QAction*> contextualActions();
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Switch the menu style from the traditional aka classic KDE3 like
|
||||
* KMenu to the new Kickoff menu.
|
||||
*/
|
||||
void switchMenuStyle();
|
||||
|
||||
/**
|
||||
* Start the menu editor by launching kmenuedit.
|
||||
*/
|
||||
void startMenuEditor();
|
||||
|
||||
/**
|
||||
* Show a custom context menu for the selected action.
|
||||
*/
|
||||
void customContextMenuRequested(QMenu* menu, const QPoint& pos);
|
||||
|
||||
/**
|
||||
* Save config values stored on Kickoff after a menu switch
|
||||
*/
|
||||
void saveConfigurationFromKickoff(const KConfigGroup & configGroup,
|
||||
const KConfigGroup & globalConfigGroup);
|
||||
|
||||
/**
|
||||
* Reload configuration values
|
||||
* Useful to load previously stored configurations after a menu switch
|
||||
*/
|
||||
void configChanged();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Create a configuration dialog.
|
||||
*/
|
||||
void createConfigurationInterface(KConfigDialog *parent);
|
||||
|
||||
QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF()) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
/// Configuration-dialog accepted.
|
||||
void configAccepted();
|
||||
/// The menu got toggled or activated.
|
||||
void toggleMenu();
|
||||
/// Shows the menu due to being toggled / activated.
|
||||
void showMenu(bool pressed);
|
||||
/// An action within the menu got triggered.
|
||||
void actionTriggered(QAction *action);
|
||||
/// Icon size setting changed
|
||||
void iconSizeChanged(int group);
|
||||
/// Menu is hidden, reset the UI
|
||||
void menuHiding();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
K_EXPORT_PLASMA_APPLET(menulauncher, MenuLauncherApplet)
|
||||
|
||||
#endif
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright 2008 Andrew Lake <jamboarder@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "contentareacap.h"
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
|
||||
ContentAreaCap::ContentAreaCap(QWidget *parent, bool flip)
|
||||
:QWidget(parent)
|
||||
{
|
||||
setMaximumHeight(3);
|
||||
setMinimumHeight(3);
|
||||
sizePolicy().setVerticalPolicy(QSizePolicy::Fixed);
|
||||
flipCap = flip;
|
||||
|
||||
parent->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
|
||||
void ContentAreaCap::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
QPainterPath path;
|
||||
QRect r = rect();
|
||||
if (!flipCap) {
|
||||
path.moveTo(r.topLeft() + QPoint(0,3));
|
||||
path.quadTo(r.topLeft(), r.topLeft() + QPoint(3,0));
|
||||
path.lineTo(r.topRight() + QPoint(-2,0));
|
||||
path.quadTo(r.topRight() + QPoint(1,0), r.topRight() + QPoint(1,3));
|
||||
} else {
|
||||
path.moveTo(r.topLeft());
|
||||
path.quadTo(r.topLeft() + QPoint(0,3), r.topLeft() + QPoint(3,3));
|
||||
path.lineTo(r.topRight() + QPoint(-2,3));
|
||||
path.quadTo(r.topRight() + QPoint(1,3), r.topRight() + QPoint(1,0));
|
||||
}
|
||||
painter.setPen(QPen(palette().base(), 1));
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.fillPath(path, palette().base());
|
||||
painter.end();
|
||||
}
|
||||
|
|
@ -1,311 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2007 Kevin Ottens <ervin@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ui/contextmenufactory.h"
|
||||
|
||||
// Qt
|
||||
#include <QAbstractItemView>
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusConnection>
|
||||
|
||||
// KDE
|
||||
#include <KIcon>
|
||||
#include <KMenu>
|
||||
#include <KActionCollection>
|
||||
#include <KFileItem>
|
||||
#include <KBookmarkManager>
|
||||
#include <Solid/Device>
|
||||
#include <Solid/StorageAccess>
|
||||
#include <Solid/OpticalDrive>
|
||||
#include <Solid/OpticalDisc>
|
||||
#include <KUrl>
|
||||
#include <KStandardDirs>
|
||||
#include <KWindowSystem>
|
||||
|
||||
// Plasma
|
||||
#include <Plasma/Containment>
|
||||
#include <Plasma/Corona>
|
||||
|
||||
// Local
|
||||
#include "core/favoritesmodel.h"
|
||||
#include "core/models.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QPersistentModelIndex)
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
class ContextMenuFactory::Private
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: applet(0) {
|
||||
}
|
||||
|
||||
QMap<QAbstractItemView*, QList<QAction*> > viewActions;
|
||||
Plasma::Applet *applet;
|
||||
};
|
||||
|
||||
ContextMenuFactory::ContextMenuFactory(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
ContextMenuFactory::~ContextMenuFactory()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void ContextMenuFactory::showContextMenu(QAbstractItemView *view,
|
||||
const QPersistentModelIndex& index, const QPoint& pos)
|
||||
{
|
||||
Q_UNUSED(pos);
|
||||
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString url = index.data(UrlRole).value<QString>();
|
||||
qDebug() << "ContextMenuFactory::showContextMenu: " << url;
|
||||
|
||||
if (url.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ivan: The url handling is dirty - instead of handling it in
|
||||
// the source data models (that define them), we are handling
|
||||
// them here. So, we need to make urls from KRunner model
|
||||
// to behave properly
|
||||
if (url.startsWith(QLatin1String("krunner://"))) {
|
||||
url = url.remove("krunner://");
|
||||
qDebug() << "ContextMenuFactory::showContextMenu: 1 " << url;
|
||||
if (url.startsWith(QLatin1String("services/services_"))) {
|
||||
url = url.remove("services/services_");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
KService::Ptr service = KService::serviceByStorageId(url);
|
||||
if(!service) {
|
||||
return;
|
||||
}
|
||||
|
||||
url = service->entryPath();
|
||||
|
||||
qDebug() << "ContextMenuFactory::showContextMenu: " << "KRunner service runner: " << url;
|
||||
}
|
||||
|
||||
|
||||
const bool isFavorite = FavoritesModel::isFavorite(url);
|
||||
|
||||
QList<QAction*> actions;
|
||||
|
||||
QAction *favoriteAction = 0;
|
||||
|
||||
if (url.endsWith(QLatin1String(".desktop"))) {
|
||||
// add to / remove from favorites
|
||||
favoriteAction = new QAction(this);
|
||||
if (isFavorite) {
|
||||
favoriteAction->setText(i18n("Remove From Favorites"));
|
||||
favoriteAction->setIcon(KIcon("list-remove"));
|
||||
actions << favoriteAction;
|
||||
//exclude stuff in the leave tab
|
||||
} else if (KUrl(url).protocol() != "leave") {
|
||||
favoriteAction->setText(i18n("Add to Favorites"));
|
||||
favoriteAction->setIcon(KIcon("bookmark-new"));
|
||||
actions << favoriteAction;
|
||||
}
|
||||
}
|
||||
|
||||
// add to desktop
|
||||
QAction *addToDesktopAction = new QAction(this);
|
||||
|
||||
// add to main panel
|
||||
QAction *addToPanelAction = new QAction(this);
|
||||
|
||||
//### FIXME : icons in leave-view are not properly based on a .desktop file
|
||||
//so you cant put them in desktop or panel
|
||||
//### TODO : do not forget to remove (kurl.scheme() != "leave") and kurl declaration
|
||||
//when proper action for such case will be provided
|
||||
KUrl kurl(url);
|
||||
if ((d->applet) && (kurl.scheme() != "leave")) {
|
||||
Plasma::Containment *containment = d->applet->containment();
|
||||
|
||||
// There might be relative paths for .desktop installed in
|
||||
// /usr/shar/applnk, we need to locate them
|
||||
bool urlFound = true;
|
||||
if (kurl.isRelative() && kurl.url().endsWith(QLatin1String(".desktop"))) {
|
||||
kurl = KStandardDirs::locate("apps", url);
|
||||
urlFound = !kurl.isEmpty();
|
||||
}
|
||||
|
||||
if (urlFound && containment && containment->corona()) {
|
||||
Plasma::Containment *desktop = containment->corona()->containmentForScreen(containment->screen());
|
||||
|
||||
if (desktop && desktop->immutability() == Plasma::Mutable) {
|
||||
addToDesktopAction->setText(i18n("Add to Desktop"));
|
||||
actions << addToDesktopAction;
|
||||
}
|
||||
}
|
||||
|
||||
if (urlFound && containment && containment->immutability() == Plasma::Mutable &&
|
||||
(containment->containmentType() == Plasma::Containment::PanelContainment ||
|
||||
containment->containmentType() == Plasma::Containment::CustomPanelContainment)) {
|
||||
addToPanelAction->setText(i18n("Add to Panel"));
|
||||
actions << addToPanelAction;
|
||||
}
|
||||
}
|
||||
|
||||
QAction *advancedSeparator = new QAction(this);
|
||||
if (actions.count() > 0) {
|
||||
// advanced item actions
|
||||
advancedSeparator->setSeparator(true);
|
||||
actions << advancedSeparator;
|
||||
}
|
||||
|
||||
// device actions
|
||||
const QString udi = index.data(DeviceUdiRole).toString();
|
||||
Solid::Device device(udi);
|
||||
Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
|
||||
QAction *ejectAction = 0;
|
||||
if (device.isValid() && access) {
|
||||
ejectAction = new QAction(this);
|
||||
if (device.is<Solid::OpticalDisc>()) {
|
||||
ejectAction->setText(i18n("Eject"));
|
||||
} else {
|
||||
ejectAction->setText(i18n("Safely Remove"));
|
||||
}
|
||||
actions << ejectAction;
|
||||
}
|
||||
|
||||
// add view specific actions
|
||||
QAction *viewSeparator = new QAction(this);
|
||||
if (view) {
|
||||
if (actions.count() > 0) {
|
||||
viewSeparator->setSeparator(true);
|
||||
actions << viewSeparator;
|
||||
}
|
||||
actions << viewActions(view);
|
||||
}
|
||||
|
||||
//return if we added just a separator so far
|
||||
if (actions.count() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// display menu
|
||||
KMenu menu;
|
||||
menu.addTitle(index.data(Qt::DisplayRole).value<QString>());
|
||||
foreach(QAction* action, actions) {
|
||||
menu.addAction(action);
|
||||
}
|
||||
|
||||
QAction *result = menu.exec(QCursor::pos());
|
||||
|
||||
if (favoriteAction && result == favoriteAction) {
|
||||
if (isFavorite) {
|
||||
FavoritesModel::remove(url);
|
||||
} else {
|
||||
FavoritesModel::add(url);
|
||||
}
|
||||
} else if (ejectAction && result == ejectAction) {
|
||||
if (device.is<Solid::OpticalDisc>()) {
|
||||
Solid::OpticalDrive *drive = device.as<Solid::OpticalDrive>();
|
||||
drive->eject();
|
||||
} else {
|
||||
access->teardown();
|
||||
}
|
||||
} else if (addToDesktopAction && result == addToDesktopAction) {
|
||||
if (d->applet) {
|
||||
Plasma::Containment *containment = d->applet->containment();
|
||||
if (containment) {
|
||||
Plasma::Corona *corona = containment->corona();
|
||||
if (corona) {
|
||||
int vdesk = KWindowSystem::currentDesktop() - 1;
|
||||
Plasma::Containment *desktop = corona->containmentForScreen(containment->screen(), vdesk);
|
||||
//PVDA disabled?
|
||||
if (!desktop) {
|
||||
desktop = corona->containmentForScreen(containment->screen(), -1);
|
||||
}
|
||||
if (desktop) {
|
||||
QVariantList args;
|
||||
args << kurl.url() << index.data(Kickoff::IconNameRole);
|
||||
if (kurl.scheme() == "applications") { // it's a service group
|
||||
desktop->addApplet("simplelauncher", args);
|
||||
} else if (desktop->metaObject()->indexOfSlot("addUrls(KUrl::List)") != -1) {
|
||||
QMetaObject::invokeMethod(desktop, "addUrls",
|
||||
Qt::DirectConnection, Q_ARG(KUrl::List, KUrl::List(kurl)));
|
||||
} else {
|
||||
desktop->addApplet("icon", args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if (addToPanelAction && result == addToPanelAction) {
|
||||
if (d->applet) {
|
||||
// we assume that the panel is the same containment where the kickoff is located
|
||||
Plasma::Containment *panel = d->applet->containment();
|
||||
if (panel) {
|
||||
QVariantList args;
|
||||
args << kurl.url() << index.data(Kickoff::IconNameRole);
|
||||
|
||||
// move it to the middle of the panel
|
||||
QRectF rect(panel->geometry().width() / 2, 0, 150, panel->boundingRect().height());
|
||||
if (kurl.scheme() == "applications") { // it's a service group
|
||||
panel->addApplet("simplelauncher", args);
|
||||
} else {
|
||||
panel->addApplet("icon", args, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete favoriteAction;
|
||||
delete addToDesktopAction;
|
||||
delete addToPanelAction;
|
||||
delete advancedSeparator;
|
||||
delete viewSeparator;
|
||||
delete ejectAction;
|
||||
}
|
||||
|
||||
void ContextMenuFactory::setViewActions(QAbstractItemView *view, const QList<QAction*>& actions)
|
||||
{
|
||||
if (actions.isEmpty()) {
|
||||
d->viewActions.remove(view);
|
||||
} else {
|
||||
d->viewActions.insert(view, actions);
|
||||
}
|
||||
}
|
||||
QList<QAction*> ContextMenuFactory::viewActions(QAbstractItemView *view) const
|
||||
{
|
||||
return d->viewActions[view];
|
||||
}
|
||||
|
||||
void ContextMenuFactory::setApplet(Plasma::Applet *applet)
|
||||
{
|
||||
d->applet = applet;
|
||||
}
|
||||
|
||||
#include "moc_contextmenufactory.cpp"
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef CONTEXTMENUFACTORY_H
|
||||
#define CONTEXTMENUFACTORY_H
|
||||
|
||||
// Qt
|
||||
#include <QAction>
|
||||
#include <QtCore/qabstractitemmodel.h>
|
||||
|
||||
// Plasma
|
||||
#include <Plasma/Applet>
|
||||
|
||||
#include <QAbstractItemView>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class ContextMenuFactory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ContextMenuFactory(QObject *parent = 0);
|
||||
~ContextMenuFactory();
|
||||
|
||||
void setViewActions(QAbstractItemView *view, const QList<QAction*>& actions);
|
||||
QList<QAction*> viewActions(QAbstractItemView *view) const;
|
||||
|
||||
void setApplet(Plasma::Applet *applet);
|
||||
|
||||
public Q_SLOTS:
|
||||
void showContextMenu(QAbstractItemView *view,
|
||||
const QPersistentModelIndex& index, const QPoint& pos);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONTEXTMENUFACTORY_H
|
|
@ -1,567 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ui/flipscrollview.h"
|
||||
|
||||
// Qt
|
||||
#include <QCoreApplication>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
#include <QStack>
|
||||
#include <QTimeLine>
|
||||
|
||||
// KDE
|
||||
#include <KDebug>
|
||||
#include <KGlobalSettings>
|
||||
#include <KIconLoader>
|
||||
#include <KColorScheme>
|
||||
|
||||
#include "ui/itemdelegate.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
class FlipScrollView::Private
|
||||
{
|
||||
public:
|
||||
Private(FlipScrollView *view)
|
||||
: q(view)
|
||||
, flipAnimTimeLine(new QTimeLine())
|
||||
, animLeftToRight(true)
|
||||
, itemHeight(-1) {
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
delete flipAnimTimeLine;
|
||||
}
|
||||
|
||||
QModelIndex currentRoot() const
|
||||
{
|
||||
if (currentRootIndex.isValid()) {
|
||||
return currentRootIndex;
|
||||
} else {
|
||||
return q->rootIndex();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex previousRoot() const
|
||||
{
|
||||
if (previousRootIndices.isEmpty()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
return previousRootIndices.top();
|
||||
}
|
||||
|
||||
void setCurrentRoot(const QModelIndex& index)
|
||||
{
|
||||
if (previousRootIndices.isEmpty() || previousRootIndices.top() != index) {
|
||||
// we're entering into a submenu
|
||||
//kDebug() << "pushing" << currentRootIndex.data(Qt::DisplayRole).value<QString>();
|
||||
animLeftToRight = true;
|
||||
hoveredIndex = QModelIndex();
|
||||
previousRootIndices.push(currentRootIndex);
|
||||
currentRootIndex = index;
|
||||
previousVerticalOffsets.append(q->verticalOffset());
|
||||
updateScrollBarRange();
|
||||
q->verticalScrollBar()->setValue(0);
|
||||
} else {
|
||||
// we're exiting to the parent menu
|
||||
//kDebug() << "popping" << previousRootIndices.top().data(Qt::DisplayRole).value<QString>();
|
||||
animLeftToRight = false;
|
||||
hoveredIndex = currentRootIndex;
|
||||
previousRootIndices.pop();
|
||||
//if (!previousRootIndices.isEmpty()) {
|
||||
// kDebug() << "now the previos root is" << previousRootIndices.top().data(Qt::DisplayRole).value<QString>();
|
||||
//}
|
||||
currentRootIndex = index;
|
||||
updateScrollBarRange();
|
||||
q->verticalScrollBar()->setValue(previousVerticalOffsets.pop());
|
||||
}
|
||||
|
||||
emit q->currentRootChanged(index);
|
||||
|
||||
if (q->viewOptions().direction == Qt::RightToLeft) {
|
||||
animLeftToRight = !animLeftToRight;
|
||||
}
|
||||
|
||||
flipAnimTimeLine->setCurrentTime(0);
|
||||
q->update();
|
||||
}
|
||||
|
||||
int previousVerticalOffset()
|
||||
{
|
||||
return previousVerticalOffsets.isEmpty() ? 0 : previousVerticalOffsets.top();
|
||||
}
|
||||
|
||||
int treeDepth(const QModelIndex& headerIndex) const
|
||||
{
|
||||
int depth = 0;
|
||||
QModelIndex index = headerIndex;
|
||||
while (index.isValid()) {
|
||||
index = index.parent();
|
||||
depth++;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
QPainterPath trianglePath(qreal width = 5, qreal height = 10) {
|
||||
QPainterPath path(QPointF(-width / 2, 0.0));
|
||||
path.lineTo(width, -height / 2);
|
||||
path.lineTo(width, height / 2);
|
||||
path.lineTo(-width / 2, 0.0);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void updateScrollBarRange()
|
||||
{
|
||||
int childCount = q->model()->rowCount(currentRootIndex);
|
||||
int pageSize = q->height();
|
||||
int itemH = q->sizeHintForIndex(q->model()->index(0, 0)).height();
|
||||
q->verticalScrollBar()->setRange(0, (childCount * itemH) - pageSize);
|
||||
q->verticalScrollBar()->setPageStep(pageSize);
|
||||
q->verticalScrollBar()->setSingleStep(itemH);
|
||||
}
|
||||
|
||||
FlipScrollView * const q;
|
||||
QPersistentModelIndex hoveredIndex;
|
||||
QPersistentModelIndex watchedIndexForDrag;
|
||||
|
||||
QTimeLine *flipAnimTimeLine;
|
||||
bool animLeftToRight;
|
||||
|
||||
int itemHeight;
|
||||
static const int FLIP_ANIM_DURATION = 200;
|
||||
|
||||
private:
|
||||
QPersistentModelIndex currentRootIndex;
|
||||
QStack<QPersistentModelIndex> previousRootIndices;
|
||||
QStack<int> previousVerticalOffsets;
|
||||
};
|
||||
|
||||
FlipScrollView::FlipScrollView(QWidget *parent)
|
||||
: QAbstractItemView(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(openItem(QModelIndex)));
|
||||
connect(d->flipAnimTimeLine, SIGNAL(valueChanged(qreal)), this, SLOT(updateFlipAnimation(qreal)));
|
||||
d->flipAnimTimeLine->setDuration(Private::FLIP_ANIM_DURATION);
|
||||
d->flipAnimTimeLine->setCurrentTime(Private::FLIP_ANIM_DURATION);
|
||||
setIconSize(QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium));
|
||||
setMouseTracking(true);
|
||||
setAutoScroll(true);
|
||||
QPalette viewPalette(palette());
|
||||
viewPalette.setColor(QPalette::Window, palette().color(QPalette::Active, QPalette::Base));
|
||||
setPalette(viewPalette);
|
||||
setAutoFillBackground(true);
|
||||
}
|
||||
FlipScrollView::~FlipScrollView()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void FlipScrollView::setCurrentRoot(const QModelIndex &index)
|
||||
{
|
||||
d->setCurrentRoot(index);
|
||||
}
|
||||
|
||||
void FlipScrollView::viewRoot()
|
||||
{
|
||||
QModelIndex index;
|
||||
while (d->currentRoot().isValid()) {
|
||||
index = d->currentRoot();
|
||||
d->setCurrentRoot(d->currentRoot().parent());
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
update(d->hoveredIndex);
|
||||
d->hoveredIndex = index;
|
||||
}
|
||||
|
||||
QModelIndex FlipScrollView::indexAt(const QPoint& point) const
|
||||
{
|
||||
const int items = model()->rowCount(d->currentRoot());
|
||||
const int rowIndex = (point.y() + verticalOffset()) / itemHeight();
|
||||
|
||||
if (rowIndex < items) {
|
||||
return model()->index(rowIndex, 0, d->currentRoot());
|
||||
} else {
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
int FlipScrollView::itemHeight() const
|
||||
{
|
||||
//TODO: reset on font change
|
||||
if (d->itemHeight < 1) {
|
||||
QModelIndex index = model()->index(0, 0, d->currentRoot());
|
||||
d->itemHeight = sizeHintForIndex(index).height();
|
||||
}
|
||||
|
||||
return d->itemHeight;
|
||||
}
|
||||
|
||||
void FlipScrollView::scrollTo(const QModelIndex& index, ScrollHint hint)
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QRect itemRect = visualRect(index);
|
||||
if (itemRect.isValid() && hint == EnsureVisible) {
|
||||
if (itemRect.top() < 0) {
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->value() +
|
||||
itemRect.top());
|
||||
} else if (itemRect.bottom() > height()) {
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->value() +
|
||||
(itemRect.bottom() - height()));
|
||||
}
|
||||
update(itemRect);
|
||||
}
|
||||
}
|
||||
|
||||
bool FlipScrollView::isIndexHidden(const QModelIndex&) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QRect FlipScrollView::visualRect(const QModelIndex& index) const
|
||||
{
|
||||
const int leftOffset = ItemDelegate::ITEM_LEFT_MARGIN;
|
||||
|
||||
if (index.parent() != d->currentRoot() &&
|
||||
index.parent() != d->previousRoot() &&
|
||||
index.parent() != (QModelIndex)d->hoveredIndex) {
|
||||
return QRect();
|
||||
}
|
||||
|
||||
const bool parentIsPreviousRoot = d->previousRoot().isValid() && index.parent() == d->previousRoot();
|
||||
if (parentIsPreviousRoot && d->flipAnimTimeLine->state() == QTimeLine::NotRunning) {
|
||||
return QRect();
|
||||
}
|
||||
|
||||
const int scrollBarWidth = verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0;
|
||||
QRect itemRect(leftOffset, index.row() * itemHeight() - verticalOffset() ,
|
||||
width() - leftOffset - scrollBarWidth, itemHeight());
|
||||
|
||||
const qreal timeValue = d->flipAnimTimeLine->currentValue();
|
||||
if (index.parent() == d->currentRoot()) {
|
||||
if (d->animLeftToRight) {
|
||||
itemRect.translate(itemRect.width() * (1 - timeValue), 0);
|
||||
} else {
|
||||
itemRect.translate(-itemRect.width() * (1 - timeValue), 0);
|
||||
}
|
||||
} else {
|
||||
if (d->animLeftToRight) {
|
||||
itemRect.translate((-timeValue*itemRect.width()), 0);
|
||||
} else {
|
||||
itemRect.translate((timeValue*itemRect.width()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
return itemRect;
|
||||
}
|
||||
|
||||
int FlipScrollView::horizontalOffset() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FlipScrollView::verticalOffset() const
|
||||
{
|
||||
return verticalScrollBar()->value();
|
||||
}
|
||||
|
||||
QRegion FlipScrollView::visualRegionForSelection(const QItemSelection& selection) const
|
||||
{
|
||||
QRegion region;
|
||||
foreach(const QModelIndex& index , selection.indexes()) {
|
||||
region |= visualRect(index);
|
||||
}
|
||||
return region;
|
||||
}
|
||||
QModelIndex FlipScrollView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers)
|
||||
{
|
||||
QModelIndex index = currentIndex();
|
||||
// kDebug() << "Moving cursor with current index" << index.data(Qt::DisplayRole);
|
||||
switch (cursorAction) {
|
||||
case MoveUp:
|
||||
if (!currentIndex().isValid()) {
|
||||
index = model()->index(model()->rowCount(d->currentRoot()) - 1, 0, d->currentRoot());
|
||||
} else if (currentIndex().row() > 0) {
|
||||
index = currentIndex().sibling(currentIndex().row() - 1,
|
||||
currentIndex().column());
|
||||
}
|
||||
break;
|
||||
case MoveDown:
|
||||
if (!currentIndex().isValid()) {
|
||||
index = model()->index(0, 0, d->currentRoot());
|
||||
} else if (currentIndex().row() <
|
||||
model()->rowCount(currentIndex().parent()) - 1) {
|
||||
index = currentIndex().sibling(currentIndex().row() + 1,
|
||||
currentIndex().column());
|
||||
}
|
||||
break;
|
||||
case MoveLeft:
|
||||
if (d->currentRoot().isValid()) {
|
||||
index = d->currentRoot();
|
||||
d->setCurrentRoot(d->currentRoot().parent());
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
break;
|
||||
case MoveRight:
|
||||
if (model()->hasChildren(currentIndex())) {
|
||||
openItem(currentIndex());
|
||||
// return the new current index set by openItem()
|
||||
index = currentIndex();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// clear the hovered index
|
||||
update(d->hoveredIndex);
|
||||
d->hoveredIndex = index;
|
||||
|
||||
//kDebug() << "New index after move" << index.data(Qt::DisplayRole);
|
||||
return index;
|
||||
}
|
||||
|
||||
void FlipScrollView::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags flags)
|
||||
{
|
||||
QItemSelection selection;
|
||||
selection.select(indexAt(rect.topLeft()), indexAt(rect.bottomRight()));
|
||||
selectionModel()->select(selection, flags);
|
||||
}
|
||||
|
||||
void FlipScrollView::openItem(const QModelIndex& index)
|
||||
{
|
||||
if (model()->canFetchMore(index)) {
|
||||
model()->fetchMore(index);
|
||||
}
|
||||
|
||||
const bool hasChildren = model()->hasChildren(index);
|
||||
|
||||
if (hasChildren) {
|
||||
d->setCurrentRoot(index);
|
||||
setCurrentIndex(model()->index(0, 0, index));
|
||||
} else {
|
||||
//TODO Emit a signal to open/execute the item
|
||||
}
|
||||
}
|
||||
|
||||
void FlipScrollView::resizeEvent(QResizeEvent*)
|
||||
{
|
||||
d->updateScrollBarRange();
|
||||
}
|
||||
|
||||
void FlipScrollView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
d->watchedIndexForDrag = indexAt(event->pos());
|
||||
QAbstractItemView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void FlipScrollView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
d->watchedIndexForDrag = QModelIndex();
|
||||
QAbstractItemView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void FlipScrollView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
const QModelIndex itemUnderMouse = indexAt(event->pos());
|
||||
if (itemUnderMouse != d->hoveredIndex) {
|
||||
update(itemUnderMouse);
|
||||
update(d->hoveredIndex);
|
||||
|
||||
d->hoveredIndex = itemUnderMouse;
|
||||
setCurrentIndex(d->hoveredIndex);
|
||||
}
|
||||
|
||||
QAbstractItemView::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void FlipScrollView::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Enter ||
|
||||
event->key() == Qt::Key_Return ||
|
||||
event->key() == Qt::Key_Right) {
|
||||
moveCursor(MoveRight, event->modifiers());
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->key() == Qt::Key_Escape || event->key() == Qt::Key_Left) {
|
||||
if (d->currentRoot().isValid()) {
|
||||
moveCursor(MoveLeft, event->modifiers());
|
||||
event->accept();
|
||||
return;
|
||||
} else {
|
||||
// we are already in the leftmost column.
|
||||
kDebug() << "we are in Left-Most column, processing Key_Left";
|
||||
event->accept();
|
||||
emit focusNextViewLeft();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QAbstractItemView::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void FlipScrollView::leaveEvent(QEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
d->hoveredIndex = QModelIndex();
|
||||
setCurrentIndex(QModelIndex());
|
||||
}
|
||||
|
||||
void FlipScrollView::paintItems(QPainter &painter, QPaintEvent *event, QModelIndex &root)
|
||||
{
|
||||
const int rows = model()->rowCount(root);
|
||||
//kDebug() << "painting" << rows << "items";
|
||||
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
QModelIndex index = model()->index(i, 0, root);
|
||||
|
||||
QStyleOptionViewItem option = viewOptions();
|
||||
option.rect = visualRect(index);
|
||||
|
||||
// only draw items intersecting the region of the widget
|
||||
// being updated
|
||||
if (!event->rect().intersects(option.rect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectionModel()->isSelected(index)) {
|
||||
option.state |= QStyle::State_Selected;
|
||||
}
|
||||
|
||||
if (index == d->hoveredIndex) {
|
||||
option.state |= QStyle::State_MouseOver;
|
||||
}
|
||||
|
||||
if (index == currentIndex()) {
|
||||
option.state |= QStyle::State_HasFocus;
|
||||
}
|
||||
|
||||
itemDelegate(index)->paint(&painter, option, index);
|
||||
|
||||
if (model()->hasChildren(index)) {
|
||||
painter.save();
|
||||
painter.setPen(Qt::NoPen);
|
||||
// there is an assumption made here that the delegate will fill the background
|
||||
// with the selected color or some similar color which contrasts well with the
|
||||
// highlighted text color
|
||||
if (option.state & QStyle::State_MouseOver) {
|
||||
painter.setBrush(palette().highlight());
|
||||
} else {
|
||||
painter.setBrush(palette().text());
|
||||
}
|
||||
|
||||
QRect triRect = option.rect;
|
||||
QPainterPath tPath = d->trianglePath();
|
||||
if (option.direction == Qt::LeftToRight) {
|
||||
triRect.setLeft(triRect.right() - ItemDelegate::ITEM_RIGHT_MARGIN);
|
||||
painter.translate(triRect.center().x() - 6, triRect.y() + (option.rect.height() / 2));
|
||||
|
||||
} else {
|
||||
triRect.setRight(triRect.left() + ItemDelegate::ITEM_RIGHT_MARGIN);
|
||||
painter.translate(triRect.center().x() + 6, triRect.y() + (option.rect.height() / 2));
|
||||
}
|
||||
|
||||
|
||||
if (option.direction == Qt::LeftToRight) {
|
||||
painter.rotate(180);
|
||||
}
|
||||
|
||||
painter.drawPath(tPath);
|
||||
painter.resetTransform();
|
||||
painter.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FlipScrollView::paintEvent(QPaintEvent * event)
|
||||
{
|
||||
QPalette viewPalette(palette());
|
||||
viewPalette.setColor(QPalette::Window, palette().color(QPalette::Active, QPalette::Base));
|
||||
setPalette(viewPalette);
|
||||
setAutoFillBackground(true);
|
||||
|
||||
QPainter painter(viewport());
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
// draw items
|
||||
QModelIndex currentRoot = d->currentRoot();
|
||||
QModelIndex previousRoot = d->animLeftToRight ? d->previousRoot() : (QModelIndex)d->hoveredIndex;
|
||||
//kDebug() << "current root is" << currentRoot.data(Qt::DisplayRole).value<QString>();
|
||||
|
||||
paintItems(painter, event, currentRoot);
|
||||
|
||||
const qreal timerValue = d->flipAnimTimeLine->currentValue();
|
||||
|
||||
if (timerValue < 1.0) {
|
||||
//kDebug() << "previous root is" << previousRoot.data(Qt::DisplayRole).value<QString>();
|
||||
paintItems(painter, event, previousRoot);
|
||||
|
||||
if (d->flipAnimTimeLine->state() != QTimeLine::Running) {
|
||||
d->flipAnimTimeLine->start();
|
||||
}
|
||||
}
|
||||
|
||||
// draw navigation
|
||||
QStyle::State state = 0;
|
||||
if (currentRoot.isValid()) {
|
||||
state |= QStyle::State_Enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void FlipScrollView::startDrag(Qt::DropActions supportedActions)
|
||||
{
|
||||
kDebug() << "Starting UrlItemView drag with actions" << supportedActions;
|
||||
|
||||
if (!d->watchedIndexForDrag.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
QMimeData *mimeData = model()->mimeData(selectionModel()->selectedIndexes());
|
||||
|
||||
if (mimeData->text().isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
drag->setMimeData(mimeData);
|
||||
|
||||
QModelIndex idx = selectionModel()->selectedIndexes().first();
|
||||
QIcon icon = idx.data(Qt::DecorationRole).value<QIcon>();
|
||||
drag->setPixmap(icon.pixmap(IconSize(KIconLoader::Desktop)));
|
||||
|
||||
drag->exec();
|
||||
}
|
||||
|
||||
void FlipScrollView::updateFlipAnimation(qreal)
|
||||
{
|
||||
setDirtyRegion(rect());
|
||||
}
|
||||
|
||||
#include "moc_flipscrollview.cpp"
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef FLIPSCROLLVIEW_H
|
||||
#define FLIPSCROLLVIEW_H
|
||||
|
||||
// Qt
|
||||
#include <QAbstractItemView>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* An "iPod-style" item view for single-column tree and list data models which
|
||||
* displays items in pages (one per tree branch).
|
||||
*
|
||||
* Clicking on an item which has children (eg. a folder in a directory model)
|
||||
* scrolls the whole contents of the view to show the items children. A large back
|
||||
* arrow is displayed on the left of the display if the current item has a valid parent,
|
||||
* when clicked on this scrolls the whole contents of the view to show the parent item's
|
||||
* children.
|
||||
*
|
||||
* The view assumes that the item delegate will fill the background with the current palette's
|
||||
* highlight color when the user hovers over items with the mouse. Item delegates should check
|
||||
* for the QStyle::State_MouseOver or QStyle::State_Selected flags in the state
|
||||
* field of the QStyleOptionViewItem passed to the QAbstractItemDelegate::paint() method.
|
||||
*/
|
||||
class FlipScrollView : public QAbstractItemView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Construct a new FlipScrollView with the specified parent. */
|
||||
FlipScrollView(QWidget *parent = 0);
|
||||
virtual ~FlipScrollView();
|
||||
|
||||
void setCurrentRoot(const QModelIndex &index);
|
||||
|
||||
/** Go to the root item. */
|
||||
void viewRoot();
|
||||
|
||||
// reimplemented from QAbstractItemView
|
||||
virtual QModelIndex indexAt(const QPoint& point) const;
|
||||
virtual void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible);
|
||||
virtual QRect visualRect(const QModelIndex& index) const;
|
||||
|
||||
int itemHeight() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void currentRootChanged(const QModelIndex &index);
|
||||
void focusNextViewLeft();
|
||||
|
||||
protected:
|
||||
// reimplemented from QWidget
|
||||
virtual void paintEvent(QPaintEvent *event);
|
||||
virtual void mouseMoveEvent(QMouseEvent *event);
|
||||
virtual void mousePressEvent(QMouseEvent *event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event);
|
||||
virtual void resizeEvent(QResizeEvent *event);
|
||||
virtual void keyPressEvent(QKeyEvent *event);
|
||||
virtual void leaveEvent(QEvent *event);
|
||||
|
||||
// reimplemented from QAbstractItemView
|
||||
virtual bool isIndexHidden(const QModelIndex& index) const;
|
||||
virtual int horizontalOffset() const;
|
||||
virtual int verticalOffset() const;
|
||||
virtual QRegion visualRegionForSelection(const QItemSelection& selection) const;
|
||||
virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
|
||||
virtual void setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags flags);
|
||||
virtual void startDrag(Qt::DropActions supportedActions);
|
||||
|
||||
private Q_SLOTS:
|
||||
void openItem(const QModelIndex& index);
|
||||
void updateFlipAnimation(qreal value);
|
||||
|
||||
private:
|
||||
void paintItems(QPainter &painter, QPaintEvent *event, QModelIndex &index);
|
||||
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FLIPSCROLLVIEW_H
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2007 Kevin Ottens <ervin@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ui/itemdelegate.h"
|
||||
|
||||
// Qt
|
||||
#include <QtCore/qabstractitemmodel.h>
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
#include <QtGui/qstyleoption.h>
|
||||
|
||||
// KDE
|
||||
#include <KDebug>
|
||||
#include <KGlobal>
|
||||
#include <kcapacitybar.h>
|
||||
|
||||
// plasma
|
||||
#include <Plasma/Plasma>
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
ItemDelegate::ItemDelegate(QObject *parent)
|
||||
: Plasma::Delegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
Plasma::Delegate::paint(painter, option, index);
|
||||
|
||||
qreal freeSpace = -1;
|
||||
qreal usedSpace = -1;
|
||||
if (!index.data(DiskFreeSpaceRole).isNull()) {
|
||||
freeSpace = index.data(DiskFreeSpaceRole).value<int>() / 1024.0 / 1024.0;
|
||||
usedSpace = index.data(DiskUsedSpaceRole).value<int>() / 1024.0 / 1024.0;
|
||||
}
|
||||
|
||||
|
||||
// draw free space information (for drive icons)
|
||||
if (usedSpace >= 0) {
|
||||
painter->save();
|
||||
|
||||
QRect emptyRect = rectAfterTitle(option, index);
|
||||
|
||||
QSize barSize = QSize(qMin(emptyRect.width(), option.rect.width() / 3), emptyRect.height());
|
||||
|
||||
if (barSize.width() > 0) {
|
||||
// if the item view is gradually resized smaller or larger, make the bar fade out/in
|
||||
// as enough space for it becomes available
|
||||
if (barSize.width() < 20.0) {
|
||||
painter->setOpacity(barSize.width() / 20.0);
|
||||
}
|
||||
|
||||
QRect spaceRect = QStyle::alignedRect(option.direction,
|
||||
Qt::AlignRight, barSize, emptyRect);
|
||||
|
||||
if (!(option.state & (QStyle::State_Selected | QStyle::State_MouseOver | QStyle::State_HasFocus))) {
|
||||
painter->setOpacity(painter->opacity() / 2.5);
|
||||
} else {
|
||||
}
|
||||
|
||||
KCapacityBar capacityBar(KCapacityBar::DrawTextInline);
|
||||
capacityBar.setValue((usedSpace / (freeSpace + usedSpace))*100);
|
||||
capacityBar.drawCapacityBar(painter, spaceRect);
|
||||
|
||||
// -- Removed the free space text because it added too much 'visual noise' to the item
|
||||
//
|
||||
// some precision is lost here, but it is acceptible given that the disk-free bar
|
||||
// is only shown as a guide
|
||||
// QString freeSpaceString = KGlobal::locale()->formatByteSize(freeSpace*1024*1024*1024);
|
||||
// painter->drawText(spaceRect,Qt::AlignCenter,i18n("%1 free",freeSpaceString));
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ItemDelegate::isVisible(const QModelIndex& index) const
|
||||
{
|
||||
if (!index.isValid()) return false;
|
||||
|
||||
if (index.model()->hasChildren(index)) {
|
||||
const int childCount = index.model()->rowCount(index);
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
QModelIndex child = index.model()->index(i, 0, index);
|
||||
if (!child.data(UrlRole).isNull()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return !index.data(UrlRole).isNull();
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef ITEMDELEGATE_H
|
||||
#define ITEMDELEGATE_H
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QAbstractItemDelegate>
|
||||
|
||||
//Plasma
|
||||
#include <Plasma/Delegate>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* Item delegate for rendering items in the Kickoff launcher's views.
|
||||
*
|
||||
* The delegate makes use of the various additional Kickoff item data roles
|
||||
* to draw the item. For example, if the DiskFreeSpaceRole and DiskUsedSpaceRole item
|
||||
* data is valid then a bar chart showing the amount of free space available on the disk
|
||||
* will be drawn.
|
||||
*/
|
||||
class ItemDelegate : public Plasma::Delegate , public ItemStateProvider
|
||||
{
|
||||
public:
|
||||
ItemDelegate(QObject *parent = 0);
|
||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
|
||||
// reimplemented from ItemStateProvider
|
||||
virtual bool isVisible(const QModelIndex& index) const;
|
||||
|
||||
static const int HEADER_LEFT_MARGIN = 5;
|
||||
static const int HEADER_TOP_MARGIN = 15;
|
||||
static const int HEADER_BOTTOM_MARGIN = 4;
|
||||
static const int HEADER_HEIGHT = 35;
|
||||
static const int FIRST_HEADER_HEIGHT = 20;
|
||||
|
||||
static const int ITEM_LEFT_MARGIN = 12;
|
||||
static const int ITEM_RIGHT_MARGIN = 7;
|
||||
static const int TOP_OFFSET = 5;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ITEMDELEGATE_H
|
File diff suppressed because it is too large
Load diff
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef LAUNCHER_H
|
||||
#define LAUNCHER_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/qabstractitemmodel.h>
|
||||
#include <QWidget>
|
||||
|
||||
// Plasma
|
||||
#include <Plasma/Applet>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
/**
|
||||
* The main window class for the Kickoff launcher. This class is responsible
|
||||
* for creating the various tabs, views and models which make up the launcher's
|
||||
* user interface.
|
||||
*/
|
||||
class Launcher : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Construct a new Launcher with the specified parent. */
|
||||
explicit Launcher(QWidget *parent = 0);
|
||||
/** Construct a new Launcher associated with the specified Plasma::Applet. */
|
||||
explicit Launcher(Plasma::Applet *applet = 0);
|
||||
~Launcher();
|
||||
|
||||
/** Specifies whether the launcher should hide itself when an item is activated. */
|
||||
void setAutoHide(bool autoHide);
|
||||
bool autoHide() const;
|
||||
|
||||
/** Specifies whether the application names in the launcher should be displayed *
|
||||
before or after the description */
|
||||
void setShowAppsByName(bool showAppByName);
|
||||
bool showAppsByName() const;
|
||||
|
||||
/** Specifies whether hovering switches between tabs or if a click is required to switch the tabs. */
|
||||
void setSwitchTabsOnHover(bool switchOnHover);
|
||||
bool switchTabsOnHover() const;
|
||||
|
||||
/** Specifies the number of visible items used to determinate the visible height. */
|
||||
void setVisibleItemCount(int count);
|
||||
int visibleItemCount() const;
|
||||
|
||||
/** Specifies the plasma applet the launcher is working on. */
|
||||
void setApplet(Plasma::Applet *applet);
|
||||
|
||||
/** Specifies the direction the launcher is popping up in relative to its icon */
|
||||
void setLauncherOrigin(const Plasma::PopupPlacement placement, Plasma::Location location);
|
||||
void setAppViewIsReceivingKeyEvents(bool isReceiving);
|
||||
bool appViewIsReceivingKeyEvents() const;
|
||||
// reimplemented
|
||||
virtual bool eventFilter(QObject *object, QEvent *event);
|
||||
virtual QSize minimumSizeHint() const;
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
/** Reset the launcher. This is called e.g. by the Kickoff-applet before shown to be sure
|
||||
we don't display old searches and switch back to the favorite-view. */
|
||||
void reset();
|
||||
|
||||
/** Specifies whether 'Recently Installed' hierarchy shall be shown in application view */
|
||||
void setShowRecentlyInstalled(bool showRecentlyInstalled);
|
||||
bool showRecentlyInstalled() const;
|
||||
|
||||
signals:
|
||||
void aboutToHide();
|
||||
void configNeedsSaving();
|
||||
|
||||
protected:
|
||||
virtual void keyPressEvent(QKeyEvent *event);
|
||||
virtual void showEvent(QShowEvent *event);
|
||||
virtual void hideEvent(QHideEvent *event);
|
||||
|
||||
private Q_SLOTS:
|
||||
void focusSearchView(const QString& query);
|
||||
void showViewContextMenu(const QPoint& pos);
|
||||
void focusFavoritesView();
|
||||
void resultsAvailable();
|
||||
void updateThemedPalette();
|
||||
void fillBreadcrumbs(const QModelIndex &index);
|
||||
void breadcrumbActivated();
|
||||
void moveViewToLeft();
|
||||
|
||||
private:
|
||||
void addBreadcrumb(const QModelIndex &index, bool isLeaf);
|
||||
void init();
|
||||
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LAUNCHER_H
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ui/searchbar.h"
|
||||
#include "ui/itemdelegate.h"
|
||||
|
||||
// Katie
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QHBoxLayout>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
|
||||
// KDE
|
||||
#include <KIcon>
|
||||
#include <KIconLoader>
|
||||
#include <KLineEdit>
|
||||
|
||||
//Plasma
|
||||
#include <Plasma/Theme>
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
class SearchBar::Private
|
||||
{
|
||||
public:
|
||||
Private() : editWidget(0), timer(0) {}
|
||||
|
||||
KLineEdit *editWidget;
|
||||
QLabel *searchLabel;
|
||||
QTimer *timer;
|
||||
};
|
||||
|
||||
SearchBar::SearchBar(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
// timer for buffered updates
|
||||
d->timer = new QTimer(this);
|
||||
d->timer->setInterval(300);
|
||||
d->timer->setSingleShot(true);
|
||||
connect(d->timer, SIGNAL(timeout()), this, SLOT(updateTimerExpired()));
|
||||
connect(this, SIGNAL(startUpdateTimer()), d->timer, SLOT(start()));
|
||||
|
||||
// setup UI
|
||||
QHBoxLayout *layout = new QHBoxLayout;
|
||||
layout->setMargin(3);
|
||||
layout->setSpacing(0); // we do the spacing manually to line up with the views below
|
||||
|
||||
d->searchLabel = new QLabel(i18nc("Label of the search bar textedit", "Search:"), this);
|
||||
QLabel *searchIcon = new QLabel(this);
|
||||
|
||||
const QFileInfo fi(QDir(QDir::homePath()), ".face.icon");
|
||||
if (fi.exists()) {
|
||||
searchIcon->setPixmap(QPixmap(fi.absoluteFilePath()).scaled(KIconLoader::SizeMedium, KIconLoader::SizeMedium, Qt::KeepAspectRatio));
|
||||
} else {
|
||||
searchIcon->setPixmap(KIcon("system-search").pixmap(KIconLoader::SizeMedium, KIconLoader::SizeMedium));
|
||||
}
|
||||
|
||||
d->editWidget = new KLineEdit(this);
|
||||
d->editWidget->installEventFilter(this);
|
||||
d->editWidget->setClearButtonShown(true);
|
||||
connect(d->editWidget, SIGNAL(textChanged(QString)), this, SIGNAL(startUpdateTimer()));
|
||||
|
||||
//add arbitrary spacing
|
||||
layout->addSpacing(2);
|
||||
layout->addWidget(searchIcon);
|
||||
layout->addSpacing(5);
|
||||
layout->addWidget(d->searchLabel);
|
||||
layout->addSpacing(5);
|
||||
layout->addWidget(d->editWidget);
|
||||
setLayout(layout);
|
||||
|
||||
setFocusProxy(d->editWidget);
|
||||
|
||||
updateThemedPalette();
|
||||
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()),
|
||||
this, SLOT(updateThemedPalette()));
|
||||
}
|
||||
|
||||
void SearchBar::updateThemedPalette()
|
||||
{
|
||||
QColor color = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
|
||||
QPalette p = d->searchLabel->palette();
|
||||
p.setColor(QPalette::Normal, QPalette::WindowText, color);
|
||||
p.setColor(QPalette::Inactive, QPalette::WindowText, color);
|
||||
d->searchLabel->setPalette(p);
|
||||
}
|
||||
|
||||
void SearchBar::updateTimerExpired()
|
||||
{
|
||||
emit queryChanged(d->editWidget->text());
|
||||
}
|
||||
|
||||
SearchBar::~SearchBar()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool SearchBar::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == d->editWidget && event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
||||
|
||||
// Left and right arrow key presses in the search edit when the
|
||||
// edit is empty are propagated up to the 'launcher'. This allows
|
||||
// the launcher to navigate among views (switch among the Tabs)
|
||||
//while the search bar still has the focus.
|
||||
if ((keyEvent->key() == Qt::Key_Left || keyEvent->key() == Qt::Key_Right) &&
|
||||
d->editWidget->text().isEmpty()) {
|
||||
QCoreApplication::sendEvent(this, event);
|
||||
return true;
|
||||
}
|
||||
// Up and Down arrows, as well as Tab, propagate up to 'launcher'.
|
||||
// It will recognize them as a request to enter the currently-visible Tab View.
|
||||
if (keyEvent->key() == Qt::Key_Down ||
|
||||
keyEvent->key() == Qt::Key_Up ||
|
||||
keyEvent->key() == Qt::Key_Tab) {
|
||||
QCoreApplication::sendEvent(this, event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SearchBar::clear()
|
||||
{
|
||||
d->editWidget->clear();
|
||||
}
|
||||
|
||||
#include "moc_searchbar.cpp"
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SEARCHBAR_H
|
||||
#define SEARCHBAR_H
|
||||
|
||||
// Qt
|
||||
#include <QWidget>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class SearchBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SearchBar(QWidget *parent);
|
||||
virtual ~SearchBar();
|
||||
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
void clear();
|
||||
|
||||
Q_SIGNALS:
|
||||
void queryChanged(const QString& newQuery);
|
||||
|
||||
// internal
|
||||
void startUpdateTimer();
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateTimerExpired();
|
||||
void updateThemedPalette();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SEARCHBAR_H
|
||||
|
|
@ -1,440 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ui/tabbar.h"
|
||||
|
||||
// KDE
|
||||
#include <KGlobalSettings>
|
||||
#include <KColorScheme>
|
||||
|
||||
// Qt
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QPainter>
|
||||
#include <QIcon>
|
||||
#include <QEasingCurve>
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
#include <Plasma/Plasma>
|
||||
#include <Plasma/Theme>
|
||||
#include <Plasma/FrameSvg>
|
||||
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
TabBar::TabBar(QWidget *parent)
|
||||
: KTabBar(parent),
|
||||
m_hoveredTabIndex(-1),
|
||||
m_switchOnHover(true),
|
||||
m_animateSwitch(true),
|
||||
m_animProgress(1.0)
|
||||
{
|
||||
m_lastIndex[0] = -1;
|
||||
connect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
|
||||
|
||||
m_tabSwitchTimer.setSingleShot(true);
|
||||
connect(&m_tabSwitchTimer, SIGNAL(timeout()), this, SLOT(switchToHoveredTab()));
|
||||
setAcceptDrops(true);
|
||||
setMouseTracking(true);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
setUsesScrollButtons(false);
|
||||
|
||||
background = new Plasma::FrameSvg(this);
|
||||
background->setImagePath("dialogs/kickoff");
|
||||
background->setEnabledBorders(
|
||||
Plasma::FrameSvg::BottomBorder |
|
||||
Plasma::FrameSvg::LeftBorder |
|
||||
Plasma::FrameSvg::RightBorder
|
||||
);
|
||||
background->resizeFrame(size());
|
||||
background->setElementPrefix("plain");
|
||||
|
||||
connect(background, SIGNAL(repaintNeeded()), this, SLOT(update()));
|
||||
}
|
||||
|
||||
void TabBar::setShape(Shape shape)
|
||||
{
|
||||
resize(0, 0); // This is required, so that the custom implementation of tabSizeHint,
|
||||
// which expands the tabs to the full width of the widget does not pick up
|
||||
// the previous width, e.g. if the panel is moved from the bottom to the left
|
||||
KTabBar::setShape(shape);
|
||||
resize(sizeHint());
|
||||
}
|
||||
|
||||
void TabBar::setCurrentIndexWithoutAnimation(int index)
|
||||
{
|
||||
disconnect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
|
||||
setCurrentIndex(index);
|
||||
storeLastIndex();
|
||||
connect(this, SIGNAL(currentChanged(int)), this, SLOT(startAnimation()));
|
||||
animationFinished();
|
||||
}
|
||||
|
||||
void TabBar::setSwitchTabsOnHover(bool switchOnHover)
|
||||
{
|
||||
m_switchOnHover = switchOnHover;
|
||||
}
|
||||
|
||||
bool TabBar::switchTabsOnHover() const
|
||||
{
|
||||
return m_switchOnHover;
|
||||
}
|
||||
|
||||
void TabBar::setAnimateSwitch(bool animateSwitch)
|
||||
{
|
||||
m_animateSwitch = animateSwitch;
|
||||
}
|
||||
|
||||
bool TabBar::animateSwitch() const
|
||||
{
|
||||
return m_animateSwitch;
|
||||
}
|
||||
|
||||
QSize TabBar::tabSize(int index) const
|
||||
{
|
||||
QSize hint;
|
||||
const QFontMetrics metrics(KGlobalSettings::smallestReadableFont());
|
||||
const QSize textSize = metrics.size(Qt::TextHideMnemonic, tabText(index));
|
||||
hint.rwidth() = qMax(iconSize().width(), textSize.width());
|
||||
hint.rheight() = iconSize().height() + textSize.height();
|
||||
hint.rwidth() += 4 * TAB_CONTENTS_MARGIN;
|
||||
hint.rheight() += 2 * TAB_CONTENTS_MARGIN;
|
||||
return hint;
|
||||
}
|
||||
|
||||
void TabBar::storeLastIndex()
|
||||
{
|
||||
// if first run
|
||||
if (m_lastIndex[0] == -1) {
|
||||
m_lastIndex[1] = currentIndex();
|
||||
}
|
||||
m_lastIndex[0] = m_lastIndex[1];
|
||||
m_lastIndex[1] = currentIndex();
|
||||
}
|
||||
|
||||
int TabBar::lastIndex() const
|
||||
{
|
||||
return m_lastIndex[0];
|
||||
}
|
||||
|
||||
QSize TabBar::tabSizeHint(int index) const
|
||||
{
|
||||
QSize hint = tabSize(index);
|
||||
int minwidth = 0;
|
||||
int minheight = 0;
|
||||
|
||||
Shape s = shape();
|
||||
switch (s) {
|
||||
case RoundedSouth:
|
||||
case TriangularSouth:
|
||||
case RoundedNorth:
|
||||
case TriangularNorth:
|
||||
if (count() > 0) {
|
||||
for (int i = count() - 1; i >= 0; i--) {
|
||||
minwidth += tabSize(i).width();
|
||||
}
|
||||
if (minwidth < width()) {
|
||||
hint.rwidth() += (width() - minwidth) / count();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RoundedWest:
|
||||
case TriangularWest:
|
||||
case RoundedEast:
|
||||
case TriangularEast:
|
||||
if (count() > 0) {
|
||||
for (int i = count() - 1; i >= 0; i--) {
|
||||
minheight += tabSize(i).height();
|
||||
}
|
||||
if (minheight < height()) {
|
||||
hint.rheight() += (height() - minheight) / count();
|
||||
}
|
||||
}
|
||||
hint.rwidth() = qMax(hint.width(), width());
|
||||
break;
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
|
||||
QSize TabBar::sizeHint() const
|
||||
{
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
if (isVertical()) {
|
||||
for (int i = count() - 1; i >= 0; i--) {
|
||||
height += tabSize(i).height();
|
||||
}
|
||||
|
||||
width = tabSize(0).width();
|
||||
} else {
|
||||
for (int i = count() - 1; i >= 0; i--) {
|
||||
width += tabSize(i).width();
|
||||
}
|
||||
|
||||
height = tabSize(0).height();
|
||||
}
|
||||
return QSize(width, height);
|
||||
}
|
||||
|
||||
QPainterPath TabBar::tabPath(const QRectF &_r)
|
||||
{
|
||||
const qreal radius = 6;
|
||||
Shape s = shape();
|
||||
QPainterPath path;
|
||||
QRectF r = _r;
|
||||
|
||||
switch (s) {
|
||||
case RoundedSouth:
|
||||
case TriangularSouth:
|
||||
r.adjust(0, 0, 0, -3);
|
||||
path.moveTo(r.topLeft());
|
||||
// Top left corner
|
||||
path.quadTo(r.topLeft() + QPointF(radius, 0), r.topLeft() + QPointF(radius, radius));
|
||||
path.lineTo(r.bottomLeft() + QPointF(radius, -radius));
|
||||
// Bottom left corner
|
||||
path.quadTo(r.bottomLeft() + QPointF(radius, 0), r.bottomLeft() + QPointF(radius * 2, 0));
|
||||
path.lineTo(r.bottomRight() + QPoint(-radius * 2, 0));
|
||||
// Bottom right corner
|
||||
path.quadTo(r.bottomRight() + QPointF(-radius, 0), r.bottomRight() + QPointF(-radius, -radius));
|
||||
path.lineTo(r.topRight() + QPointF(-radius, radius));
|
||||
// Top right corner
|
||||
path.quadTo(r.topRight() + QPointF(-radius, 0), r.topRight());
|
||||
break;
|
||||
case RoundedNorth:
|
||||
case TriangularNorth:
|
||||
|
||||
r.adjust(0, 3, 0, 1);
|
||||
path.moveTo(r.bottomLeft());
|
||||
// Bottom left corner
|
||||
path.quadTo(r.bottomLeft() + QPointF(radius, 0), r.bottomLeft() + QPointF(radius, -radius));
|
||||
// Top left corner
|
||||
path.lineTo(r.topLeft() + QPointF(radius, radius));
|
||||
path.quadTo(r.topLeft() + QPoint(radius, 0), r.topLeft() + QPointF(radius * 2, 0));
|
||||
// Top right corner
|
||||
path.lineTo(r.topRight() + QPointF(-radius * 2, 0));
|
||||
path.quadTo(r.topRight() + QPointF(-radius, 0), r.topRight() + QPointF(-radius, radius));
|
||||
// Bottom right corner
|
||||
path.lineTo(r.bottomRight() + QPointF(-radius, -radius));
|
||||
path.quadTo(r.bottomRight() + QPointF(-radius, 0), r.bottomRight());
|
||||
break;
|
||||
case RoundedWest:
|
||||
case TriangularWest:
|
||||
r.adjust(3, 0, 1, 0);
|
||||
path.moveTo(r.topRight());
|
||||
// Top right corner
|
||||
path.lineTo(r.topRight());
|
||||
path.quadTo(r.topRight() + QPointF(0, radius), r.topRight() + QPointF(-radius, radius));
|
||||
// Top left corner
|
||||
path.lineTo(r.topLeft() + QPointF(radius, radius));
|
||||
path.quadTo(r.topLeft() + QPointF(0, radius), r.topLeft() + QPointF(0, radius * 2));
|
||||
// Bottom left corner
|
||||
path.lineTo(r.bottomLeft() + QPointF(0, -radius * 2));
|
||||
path.quadTo(r.bottomLeft() + QPointF(0, -radius), r.bottomLeft() + QPointF(radius, -radius));
|
||||
// Bottom right corner
|
||||
path.lineTo(r.bottomRight() + QPointF(-radius, -radius));
|
||||
path.quadTo(r.bottomRight() + QPointF(0, -radius), r.bottomRight());
|
||||
break;
|
||||
case RoundedEast:
|
||||
case TriangularEast:
|
||||
r.adjust(0, 0, -3, 0);
|
||||
path.moveTo(r.topLeft());
|
||||
// Top left corner
|
||||
path.quadTo(r.topLeft() + QPointF(0, radius), r.topLeft() + QPointF(radius, radius));
|
||||
// Top right corner
|
||||
path.lineTo(r.topRight() + QPointF(-radius, radius));
|
||||
path.quadTo(r.topRight() + QPointF(0, radius), r.topRight() + QPointF(0, radius * 2));
|
||||
// Bottom right corner
|
||||
path.lineTo(r.bottomRight() + QPointF(0, -radius * 2));
|
||||
path.quadTo(r.bottomRight() + QPointF(0, -radius), r.bottomRight() + QPointF(-radius, -radius));
|
||||
// Bottom left corner
|
||||
path.lineTo(r.bottomLeft() + QPointF(radius, -radius));
|
||||
path.quadTo(r.bottomLeft() + QPointF(0, -radius), r.bottomLeft());
|
||||
break;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void TabBar::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
QPainter painter(this);
|
||||
//int numTabs = count();
|
||||
int currentTab = currentIndex();
|
||||
|
||||
background->paintFrame(&painter);
|
||||
|
||||
//bool ltr = painter.layoutDirection() == Qt::LeftToRight; // Not yet used
|
||||
painter.setFont(KGlobalSettings::smallestReadableFont());
|
||||
|
||||
// Drawing Tabborders
|
||||
QRectF movingRect;
|
||||
|
||||
if (m_currentAnimRect.isNull()) {
|
||||
movingRect = tabRect(currentIndex());
|
||||
} else {
|
||||
movingRect = m_currentAnimRect;
|
||||
}
|
||||
QPainterPath path = tabPath(movingRect);
|
||||
|
||||
painter.save();
|
||||
painter.setPen(QPen(palette().base(), 1));
|
||||
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
painter.fillPath(path, palette().base());
|
||||
|
||||
painter.restore();
|
||||
|
||||
QFontMetrics metrics(painter.font());
|
||||
int textHeight = metrics.height();
|
||||
|
||||
for (int i = 0; i < count(); i++) {
|
||||
QRect rect = tabRect(i).adjusted(TAB_CONTENTS_MARGIN, TAB_CONTENTS_MARGIN,
|
||||
-TAB_CONTENTS_MARGIN, -TAB_CONTENTS_MARGIN);
|
||||
// draw tab icon
|
||||
QRectF iconRect = rect;
|
||||
iconRect.setBottom(iconRect.bottom() - textHeight);
|
||||
iconRect.adjust(0, (isVertical() ? 1 : 0) * TAB_CONTENTS_MARGIN + 3, 0, 0);
|
||||
|
||||
tabIcon(i).paint(&painter, iconRect.toRect());
|
||||
|
||||
// draw tab text
|
||||
if (i != currentTab || m_animProgress < 0.9) {
|
||||
//painter.setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText), 0));
|
||||
painter.setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
||||
} else {
|
||||
painter.setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::NormalText), 0));
|
||||
}
|
||||
QRect textRect = rect;
|
||||
textRect.setTop(textRect.bottom() - textHeight);
|
||||
painter.drawText(textRect, Qt::AlignCenter | Qt::TextHideMnemonic, tabText(i));
|
||||
}
|
||||
}
|
||||
|
||||
void TabBar::leaveEvent(QEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
m_hoveredTabIndex = -1;
|
||||
}
|
||||
|
||||
void TabBar::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
m_hoveredTabIndex = tabAt(event->pos());
|
||||
if (m_switchOnHover && m_hoveredTabIndex > -1 && m_hoveredTabIndex != currentIndex()) {
|
||||
m_tabSwitchTimer.stop();
|
||||
m_tabSwitchTimer.start(50);
|
||||
}
|
||||
}
|
||||
|
||||
void TabBar::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
KTabBar::resizeEvent(event);
|
||||
m_currentAnimRect = tabRect(currentIndex());
|
||||
|
||||
background->resizeFrame(event->size());
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void TabBar::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
m_hoveredTabIndex = tabAt(event->pos());
|
||||
m_tabSwitchTimer.stop();
|
||||
m_tabSwitchTimer.start(50);
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void TabBar::switchToHoveredTab()
|
||||
{
|
||||
if (m_hoveredTabIndex < 0 || m_hoveredTabIndex == currentIndex()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_animateSwitch) {
|
||||
setCurrentIndex(m_hoveredTabIndex);
|
||||
} else {
|
||||
setCurrentIndexWithoutAnimation(m_hoveredTabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void TabBar::startAnimation()
|
||||
{
|
||||
storeLastIndex();
|
||||
|
||||
QPropertyAnimation *animation = m_animation.data();
|
||||
if (animation) {
|
||||
animation->pause();
|
||||
} else {
|
||||
animation = new QPropertyAnimation(this, "animValue");
|
||||
animation->setEasingCurve(QEasingCurve::OutQuad);
|
||||
animation->setDuration(150);
|
||||
animation->setStartValue(0.0);
|
||||
animation->setEndValue(1.0);
|
||||
}
|
||||
|
||||
animation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
}
|
||||
|
||||
qreal TabBar::animValue() const
|
||||
{
|
||||
return m_animProgress;
|
||||
}
|
||||
|
||||
void TabBar::setAnimValue(qreal value)
|
||||
{
|
||||
if ((m_animProgress = value) == 1.0) {
|
||||
animationFinished();
|
||||
return;
|
||||
}
|
||||
// animation rect
|
||||
QRect rect = tabRect(currentIndex());
|
||||
QRect lastRect = tabRect(lastIndex());
|
||||
int x = isHorizontal() ? (int)(lastRect.x() - value * (lastRect.x() - rect.x())) : rect.x();
|
||||
int y = isHorizontal() ? rect.y() : (int)(lastRect.y() - value * (lastRect.y() - rect.y()));
|
||||
QSizeF sz = lastRect.size() - value * (lastRect.size() - rect.size());
|
||||
m_currentAnimRect = QRect(x, y, (int)(sz.width()), (int)(sz.height()));
|
||||
update();
|
||||
}
|
||||
|
||||
void TabBar::animationFinished()
|
||||
{
|
||||
m_currentAnimRect = QRect();
|
||||
update();
|
||||
}
|
||||
|
||||
bool TabBar::isVertical() const
|
||||
{
|
||||
Shape s = shape();
|
||||
if (s == RoundedWest ||
|
||||
s == RoundedEast ||
|
||||
s == TriangularWest ||
|
||||
s == TriangularEast) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TabBar::isHorizontal() const
|
||||
{
|
||||
return !isVertical();
|
||||
}
|
||||
|
||||
#include "moc_tabbar.cpp"
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef TABBAR_H
|
||||
#define TABBAR_H
|
||||
|
||||
#include <KTabBar>
|
||||
#include <QTimer>
|
||||
#include <QtCore/qsharedpointer.h>
|
||||
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
class FrameSvg;
|
||||
}
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class TabBar : public KTabBar
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qreal animValue READ animValue WRITE setAnimValue)
|
||||
|
||||
public:
|
||||
TabBar(QWidget *parent);
|
||||
|
||||
QSize sizeHint() const;
|
||||
/** Like the setCurrentIndex() method but switches the tab without using any
|
||||
animation. This is used e.g. within Launcher::reset() to switch back to the
|
||||
favorite tab before Kickoff got shown. */
|
||||
void setCurrentIndexWithoutAnimation(int index);
|
||||
|
||||
/** Specifies whether hovering switches between tabs or if a click is required to switch the tabs. */
|
||||
void setSwitchTabsOnHover(bool switchOnHover);
|
||||
bool switchTabsOnHover() const;
|
||||
void setAnimateSwitch(bool animateSwitch);
|
||||
bool animateSwitch() const ;
|
||||
void setShape(Shape shape);
|
||||
qreal animValue() const;
|
||||
|
||||
protected:
|
||||
int lastIndex() const;
|
||||
|
||||
// reimplemented from KTabBar
|
||||
virtual QSize tabSizeHint(int index) const;
|
||||
virtual void paintEvent(QPaintEvent *event);
|
||||
virtual void leaveEvent(QEvent *event);
|
||||
virtual void mouseMoveEvent(QMouseEvent *event);
|
||||
virtual void resizeEvent(QResizeEvent* event);
|
||||
virtual void dragEnterEvent(QDragEnterEvent *event);
|
||||
|
||||
bool isHorizontal() const;
|
||||
bool isVertical() const;
|
||||
|
||||
protected slots:
|
||||
void switchToHoveredTab();
|
||||
void animationFinished();
|
||||
void startAnimation();
|
||||
void setAnimValue(qreal value);
|
||||
|
||||
private:
|
||||
QPainterPath tabPath(const QRectF &r);
|
||||
|
||||
static const int TAB_CONTENTS_MARGIN = 6;
|
||||
int m_hoveredTabIndex;
|
||||
QTimer m_tabSwitchTimer;
|
||||
bool m_switchOnHover;
|
||||
bool m_animateSwitch;
|
||||
QRectF m_currentAnimRect;
|
||||
int m_lastIndex[2];
|
||||
QWeakPointer<QPropertyAnimation> m_animation;
|
||||
qreal m_animProgress;
|
||||
Plasma::FrameSvg *background;
|
||||
|
||||
QSize tabSize(int index) const;
|
||||
void storeLastIndex();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TABBAR_H
|
|
@ -1,715 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ui/urlitemview.h"
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/qabstractitemmodel.h>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtGui/QPen>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QScrollBar>
|
||||
#include <QtGui/QToolTip>
|
||||
|
||||
|
||||
// KDE
|
||||
#include <KDebug>
|
||||
#include <KGlobalSettings>
|
||||
#include <KIconLoader>
|
||||
#include <KColorScheme>
|
||||
|
||||
// Local
|
||||
#include "core/models.h"
|
||||
#include "core/kickoffmodel.h"
|
||||
#include "ui/itemdelegate.h"
|
||||
|
||||
using namespace Kickoff;
|
||||
|
||||
class UrlItemView::Private
|
||||
{
|
||||
public:
|
||||
Private(UrlItemView *parent)
|
||||
: q(parent)
|
||||
, contentsHeight(0)
|
||||
, itemStateProvider(0) {
|
||||
}
|
||||
|
||||
void doLayout() {
|
||||
// clear existing layout information
|
||||
itemRects.clear();
|
||||
visualOrder.clear();
|
||||
|
||||
if (!q->model()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int verticalOffset = ItemDelegate::TOP_OFFSET;
|
||||
int horizontalOffset = 0;
|
||||
int row = 0;
|
||||
int visualColumn = 0;
|
||||
|
||||
QModelIndex branch = currentRootIndex;
|
||||
|
||||
while (true) {
|
||||
if (itemChildOffsets[branch] + row >= q->model()->rowCount(branch) ||
|
||||
(branch != currentRootIndex && row > MAX_CHILD_ROWS)) {
|
||||
|
||||
if (branch.isValid()) {
|
||||
row = branch.row() + 1;
|
||||
branch = branch.parent();
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex child = q->model()->index(row + itemChildOffsets[branch], 0, branch);
|
||||
|
||||
if (q->model()->hasChildren(child)) {
|
||||
QSize childSize = calculateHeaderSize(child);
|
||||
QRect rect(QPoint(ItemDelegate::HEADER_LEFT_MARGIN, verticalOffset), childSize);
|
||||
//kDebug() << "header rect for" << child.data(Qt::DisplayRole) << "is" << rect;
|
||||
itemRects.insert(child, rect);
|
||||
|
||||
if (childSize.isValid()) {
|
||||
// don't subtract 1
|
||||
verticalOffset += childSize.height();
|
||||
}
|
||||
horizontalOffset = 0;
|
||||
branch = child;
|
||||
row = 0;
|
||||
visualColumn = 0;
|
||||
} else {
|
||||
QSize childSize = calculateItemSize(child);
|
||||
//kDebug() << "item rect for" << child.data(Qt::DisplayRole) << "is" << QRect(QPoint(horizontalOffset,verticalOffset), childSize);
|
||||
|
||||
itemRects.insert(child, QRect(QPoint(horizontalOffset, verticalOffset),
|
||||
childSize));
|
||||
|
||||
if (childSize.isValid()) {
|
||||
visualOrder << child;
|
||||
}
|
||||
|
||||
horizontalOffset += contentWidth() / MAX_COLUMNS;
|
||||
|
||||
visualColumn++;
|
||||
row++;
|
||||
|
||||
bool wasLastRow = row + itemChildOffsets[branch] >= q->model()->rowCount(branch);
|
||||
bool nextItemIsBranch = false;
|
||||
if (!wasLastRow) {
|
||||
QModelIndex nextIndex = q->model()->index(row + itemChildOffsets[branch], 0, branch);
|
||||
nextItemIsBranch = q->model()->hasChildren(nextIndex);
|
||||
}
|
||||
|
||||
if (visualColumn >= MAX_COLUMNS || wasLastRow || nextItemIsBranch) {
|
||||
horizontalOffset = 0;
|
||||
visualColumn = 0;
|
||||
}
|
||||
|
||||
if (childSize.isValid()) {
|
||||
// don't subtract 1
|
||||
verticalOffset += childSize.height();
|
||||
}
|
||||
}
|
||||
}
|
||||
contentsHeight = verticalOffset;
|
||||
|
||||
updateScrollBarRange();
|
||||
}
|
||||
|
||||
void drawHeader(QPainter *painter,
|
||||
const QModelIndex& index,
|
||||
const QStyleOptionViewItem& option) {
|
||||
const bool first = isFirstHeader(index);
|
||||
const int rightMargin = q->style()->pixelMetric(QStyle::PM_ScrollBarExtent) + 6;
|
||||
const int dy = (first ? 4 : ItemDelegate::HEADER_TOP_MARGIN);
|
||||
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
|
||||
if (!first) {
|
||||
QLinearGradient gradient(option.rect.topLeft(), option.rect.topRight());
|
||||
gradient.setColorAt(0.0, Qt::transparent);
|
||||
gradient.setColorAt(0.1, option.palette.midlight().color());
|
||||
gradient.setColorAt(0.5, option.palette.mid().color());
|
||||
gradient.setColorAt(0.9, option.palette.midlight().color());
|
||||
gradient.setColorAt(1.0, Qt::transparent);
|
||||
painter->setPen(QPen(gradient, 1));
|
||||
|
||||
painter->drawLine(option.rect.x() + 6, option.rect.y() + dy + 2,
|
||||
option.rect.right() - rightMargin , option.rect.y() + dy + 2);
|
||||
}
|
||||
|
||||
painter->setFont(KGlobalSettings::smallestReadableFont());
|
||||
painter->setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText), 0));
|
||||
QString text = index.data(Qt::DisplayRole).value<QString>();
|
||||
painter->drawText(option.rect.adjusted(0, dy, -rightMargin, 0),
|
||||
Qt::AlignVCenter | Qt::AlignRight, text);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void updateScrollBarRange() {
|
||||
const int pageSize = q->height();
|
||||
q->verticalScrollBar()->setRange(0, contentsHeight - pageSize);
|
||||
q->verticalScrollBar()->setPageStep(pageSize);
|
||||
q->verticalScrollBar()->setSingleStep(q->sizeHintForRow(0));
|
||||
}
|
||||
|
||||
int contentWidth() const {
|
||||
return q->width() - q->style()->pixelMetric(QStyle::PM_ScrollBarExtent) + 2;
|
||||
}
|
||||
|
||||
QSize calculateItemSize(const QModelIndex& index) const {
|
||||
if (itemStateProvider && !itemStateProvider->isVisible(index)) {
|
||||
return QSize();
|
||||
} else {
|
||||
return QSize(contentWidth() / MAX_COLUMNS, q->sizeHintForIndex(index).height());
|
||||
}
|
||||
}
|
||||
|
||||
bool isFirstHeader(const QModelIndex &index) const {
|
||||
if (index.row() == 0) {
|
||||
return q->model()->hasChildren(index);
|
||||
}
|
||||
|
||||
QModelIndex prevHeader = index.sibling(index.row() - 1, index.column());
|
||||
while (prevHeader.isValid()) {
|
||||
//kDebug() << "checking" << prevHeader.data(Qt::DisplayRole).value<QString>();
|
||||
if (q->model()->hasChildren(prevHeader)) {
|
||||
//kDebug() << "it has children";
|
||||
return false;
|
||||
}
|
||||
|
||||
prevHeader = prevHeader.sibling(prevHeader.row() - 1, prevHeader.column());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool insertAbove(const QRect &itemRect, const QPoint &pos) const {
|
||||
return pos.y() < itemRect.top() + (itemRect.height() / 2);
|
||||
}
|
||||
|
||||
bool insertBelow(const QRect &itemRect, const QPoint &pos) const {
|
||||
return pos.y() >= itemRect.top() + (itemRect.height() / 2);
|
||||
}
|
||||
|
||||
QSize calculateHeaderSize(const QModelIndex& index) const {
|
||||
const QFontMetrics fm(KGlobalSettings::smallestReadableFont());
|
||||
int minHeight = ItemDelegate::HEADER_HEIGHT;
|
||||
const bool isFirst = isFirstHeader(index);
|
||||
|
||||
if (itemStateProvider && !itemStateProvider->isVisible(index)) {
|
||||
return QSize();
|
||||
} else if (isFirst) {
|
||||
minHeight = ItemDelegate::FIRST_HEADER_HEIGHT;
|
||||
}
|
||||
|
||||
return QSize(q->width() - ItemDelegate::HEADER_LEFT_MARGIN,
|
||||
qMax(fm.height() + (isFirst ? 4 : ItemDelegate::HEADER_TOP_MARGIN), minHeight)
|
||||
+ ItemDelegate::HEADER_BOTTOM_MARGIN) ;
|
||||
}
|
||||
|
||||
QPoint mapFromViewport(const QPoint& point) const {
|
||||
return point + QPoint(0, q->verticalOffset());
|
||||
}
|
||||
|
||||
QPoint mapToViewport(const QPoint& point) const {
|
||||
return point - QPoint(0, q->verticalOffset());
|
||||
}
|
||||
|
||||
UrlItemView * const q;
|
||||
QPersistentModelIndex currentRootIndex;
|
||||
QPersistentModelIndex hoveredIndex;
|
||||
QPersistentModelIndex watchedIndexForDrag;
|
||||
|
||||
QHash<QModelIndex, int> itemChildOffsets;
|
||||
QHash<QModelIndex, QRect> itemRects;
|
||||
QList<QModelIndex> visualOrder;
|
||||
|
||||
QRect dropRect;
|
||||
int draggedRow;
|
||||
bool dragging;
|
||||
|
||||
int contentsHeight;
|
||||
ItemStateProvider *itemStateProvider;
|
||||
|
||||
static const int MAX_COLUMNS = 1;
|
||||
|
||||
// TODO Eventually it will be possible to restrict each branch to only showing
|
||||
// a given number of children, with Next/Previous arrows to view more children
|
||||
//
|
||||
// eg.
|
||||
//
|
||||
// Recent Documents [1-10 of 100] Next
|
||||
// Recent Applications [10-20 of 30] Previous|Next
|
||||
//
|
||||
static const int MAX_CHILD_ROWS = 1000;
|
||||
};
|
||||
|
||||
UrlItemView::UrlItemView(QWidget *parent)
|
||||
: QAbstractItemView(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
d->dragging = false;
|
||||
setIconSize(QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium));
|
||||
setMouseTracking(true);
|
||||
QPalette viewPalette(palette());
|
||||
viewPalette.setColor(QPalette::Window, palette().color(QPalette::Active, QPalette::Base));
|
||||
setPalette(viewPalette);
|
||||
setAutoFillBackground(true);
|
||||
}
|
||||
|
||||
UrlItemView::~UrlItemView()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QModelIndex UrlItemView::indexAt(const QPoint& point) const
|
||||
{
|
||||
// simple linear search through the item rects, this will
|
||||
// be inefficient when the viewport is large
|
||||
QHashIterator<QModelIndex, QRect> iter(d->itemRects);
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
if (iter.value().contains(d->mapFromViewport(point))) {
|
||||
return iter.key();
|
||||
}
|
||||
}
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
bool UrlItemView::initializeSelection()
|
||||
{
|
||||
if (!selectionModel()
|
||||
|| selectionModel()->hasSelection()
|
||||
|| d->itemRects.size() == 0
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// searching for the first item - the item whose rectangle is the
|
||||
// top one
|
||||
|
||||
QHashIterator<QModelIndex, QRect> iter(d->itemRects);
|
||||
|
||||
// There is at least one item
|
||||
iter.next();
|
||||
|
||||
int y = iter.value().top();
|
||||
QModelIndex index = iter.key();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
|
||||
if (y > iter.value().top()) {
|
||||
y = iter.value().top();
|
||||
index = iter.key();
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentIndex(index);
|
||||
|
||||
return selectionModel()->hasSelection();
|
||||
}
|
||||
|
||||
void UrlItemView::setModel(QAbstractItemModel *model)
|
||||
{
|
||||
QAbstractItemView::setModel(model);
|
||||
|
||||
if (model) {
|
||||
connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(updateLayout()));
|
||||
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(updateLayout()));
|
||||
connect(model, SIGNAL(modelReset()), this, SLOT(updateLayout()));
|
||||
}
|
||||
|
||||
d->currentRootIndex = QModelIndex();
|
||||
d->itemChildOffsets.clear();
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
void UrlItemView::updateLayout()
|
||||
{
|
||||
d->doLayout();
|
||||
|
||||
if (viewport()->isVisible()) {
|
||||
viewport()->update();
|
||||
}
|
||||
}
|
||||
|
||||
void UrlItemView::scrollTo(const QModelIndex& index, ScrollHint hint)
|
||||
{
|
||||
QRect itemRect = d->itemRects[index];
|
||||
QRect viewedRect = QRect(d->mapFromViewport(QPoint(0, 0)),
|
||||
size());
|
||||
int topDifference = viewedRect.top() - itemRect.top();
|
||||
int bottomDifference = viewedRect.bottom() - itemRect.bottom();
|
||||
QScrollBar *scrollBar = verticalScrollBar();
|
||||
|
||||
if (!itemRect.isValid())
|
||||
return;
|
||||
|
||||
switch (hint) {
|
||||
case EnsureVisible: {
|
||||
if (!viewedRect.contains(itemRect)) {
|
||||
|
||||
if (topDifference < 0) {
|
||||
// scroll view down
|
||||
scrollBar->setValue(scrollBar->value() - bottomDifference);
|
||||
} else {
|
||||
// scroll view up
|
||||
scrollBar->setValue(scrollBar->value() - topDifference);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PositionAtTop: {
|
||||
//d->viewportOffset = itemRect.top();
|
||||
}
|
||||
default:
|
||||
Q_ASSERT(false); // Not implemented
|
||||
}
|
||||
}
|
||||
|
||||
QRect UrlItemView::visualRect(const QModelIndex& index) const
|
||||
{
|
||||
QRect itemRect = d->itemRects[index];
|
||||
if (!itemRect.isValid()) {
|
||||
return itemRect;
|
||||
}
|
||||
|
||||
itemRect.moveTopLeft(d->mapToViewport(itemRect.topLeft()));
|
||||
return itemRect;
|
||||
}
|
||||
|
||||
int UrlItemView::horizontalOffset() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool UrlItemView::isIndexHidden(const QModelIndex&) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex UrlItemView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers)
|
||||
{
|
||||
QModelIndex index = currentIndex();
|
||||
|
||||
int visualIndex = d->visualOrder.indexOf(index);
|
||||
|
||||
switch (cursorAction) {
|
||||
case MoveUp:
|
||||
if (!currentIndex().isValid()) {
|
||||
const QModelIndex root = model()->index(0, 0);
|
||||
index = model()->index(model()->rowCount(root) - 1, 0, root);
|
||||
} else {
|
||||
visualIndex = qMax(0, visualIndex - 1);
|
||||
}
|
||||
break;
|
||||
case MoveDown:
|
||||
if (!currentIndex().isValid()) {
|
||||
const QModelIndex root = model()->index(0, 0);
|
||||
index = model()->index(0, 0, root);
|
||||
} else {
|
||||
visualIndex = qMin(d->visualOrder.count() - 1, visualIndex + 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
d->hoveredIndex = QModelIndex();
|
||||
|
||||
return currentIndex().isValid() ? d->visualOrder.value(visualIndex, QModelIndex())
|
||||
: index;
|
||||
}
|
||||
|
||||
void UrlItemView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags)
|
||||
{
|
||||
QItemSelection selection;
|
||||
selection.select(indexAt(rect.topLeft()), indexAt(rect.bottomRight()));
|
||||
selectionModel()->select(selection, flags);
|
||||
}
|
||||
|
||||
int UrlItemView::verticalOffset() const
|
||||
{
|
||||
return verticalScrollBar()->value();
|
||||
}
|
||||
|
||||
QRegion UrlItemView::visualRegionForSelection(const QItemSelection& selection) const
|
||||
{
|
||||
QRegion region;
|
||||
foreach(const QModelIndex& index, selection.indexes()) {
|
||||
region |= visualRect(index);
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
void UrlItemView::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
if (!model()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPalette viewPalette(palette());
|
||||
viewPalette.setColor(QPalette::Window, palette().color(QPalette::Active, QPalette::Base));
|
||||
setPalette(viewPalette);
|
||||
setAutoFillBackground(true);
|
||||
|
||||
QPainter painter(viewport());
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
if (d->dragging && dragDropMode() == QAbstractItemView::DragDrop) {
|
||||
const int y = (d->dropRect.top() + d->dropRect.bottom()) / 2;
|
||||
|
||||
painter.save();
|
||||
QLinearGradient gr(d->dropRect.left(), y, d->dropRect.right(), y);
|
||||
gr.setColorAt(0, palette().base().color());
|
||||
gr.setColorAt(.35, palette().windowText().color());
|
||||
gr.setColorAt(.65, palette().windowText().color());
|
||||
gr.setColorAt(1, palette().base().color());
|
||||
painter.setPen(QPen(gr, 1));
|
||||
painter.drawLine(d->dropRect.left(), y, d->dropRect.right(), y);
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
QHashIterator<QModelIndex, QRect> indexIter(d->itemRects);
|
||||
while (indexIter.hasNext()) {
|
||||
indexIter.next();
|
||||
const QRect itemRect = visualRect(indexIter.key());
|
||||
const QModelIndex index = indexIter.key();
|
||||
|
||||
if (event->region().contains(itemRect)) {
|
||||
QStyleOptionViewItem option = viewOptions();
|
||||
option.rect = itemRect;
|
||||
|
||||
if (selectionModel()->isSelected(index)) {
|
||||
option.state |= QStyle::State_Selected;
|
||||
}
|
||||
if (index == d->hoveredIndex) {
|
||||
option.state |= QStyle::State_MouseOver;
|
||||
}
|
||||
if (index == currentIndex()) {
|
||||
option.state |= QStyle::State_HasFocus;
|
||||
}
|
||||
|
||||
if (model()->hasChildren(index)) {
|
||||
d->drawHeader(&painter, index, option);
|
||||
} else {
|
||||
if (option.rect.left() == 0) {
|
||||
option.rect.setLeft(option.rect.left() + ItemDelegate::ITEM_LEFT_MARGIN);
|
||||
option.rect.setRight(option.rect.right() - ItemDelegate::ITEM_RIGHT_MARGIN);
|
||||
}
|
||||
itemDelegate(index)->paint(&painter, option, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UrlItemView::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
|
||||
void UrlItemView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
const QModelIndex itemUnderMouse = indexAt(event->pos());
|
||||
if (itemUnderMouse != d->hoveredIndex && state() == NoState) {
|
||||
update(itemUnderMouse);
|
||||
update(d->hoveredIndex);
|
||||
|
||||
d->hoveredIndex = itemUnderMouse;
|
||||
setCurrentIndex(d->hoveredIndex);
|
||||
}
|
||||
|
||||
Plasma::Delegate *hoveredItemDelegate =
|
||||
static_cast<Plasma::Delegate*>(itemDelegate(d->hoveredIndex));
|
||||
if (hoveredItemDelegate->showToolTip()) {
|
||||
QModelIndex index = d->hoveredIndex;
|
||||
QString titleText = index.data(Qt::DisplayRole).toString();
|
||||
QString subTitleText = index.data(Plasma::Delegate::SubTitleRole).toString();
|
||||
setToolTip(titleText + '\n' + subTitleText);
|
||||
} else {
|
||||
setToolTip(QString());
|
||||
}
|
||||
|
||||
QAbstractItemView::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void UrlItemView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
d->watchedIndexForDrag = indexAt(event->pos());
|
||||
QAbstractItemView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void UrlItemView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
d->watchedIndexForDrag = QModelIndex();
|
||||
}
|
||||
|
||||
void UrlItemView::setItemStateProvider(ItemStateProvider *provider)
|
||||
{
|
||||
d->itemStateProvider = provider;
|
||||
}
|
||||
|
||||
void UrlItemView::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (dragDropMode() != QAbstractItemView::DragDrop) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->dragging = true;
|
||||
setDirtyRegion(d->dropRect);
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void UrlItemView::dragLeaveEvent(QDragLeaveEvent *event)
|
||||
{
|
||||
if (dragDropMode() != QAbstractItemView::DragDrop) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->dragging = false;
|
||||
setDirtyRegion(d->dropRect);
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void UrlItemView::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
QAbstractItemView::dragMoveEvent(event);
|
||||
|
||||
const QPoint pos = event->pos();
|
||||
const QModelIndex index = indexAt(pos);
|
||||
setDirtyRegion(d->dropRect);
|
||||
|
||||
// check to see if it's the header
|
||||
if (d->isFirstHeader(index) && index.row() == 0) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
if (index.isValid()) {
|
||||
const QRect rect = visualRect(index);
|
||||
const int gap = d->contentsHeight;
|
||||
|
||||
if (d->insertAbove(rect, pos)) {
|
||||
d->dropRect = QRect(rect.left(), rect.top() - gap / 2,
|
||||
rect.width(), gap);
|
||||
} else if (d->insertBelow(rect, pos)) {
|
||||
d->dropRect = QRect(rect.left(), rect.bottom() + 1 - gap / 2,
|
||||
rect.width(), gap);
|
||||
} else {
|
||||
d->dropRect = rect;
|
||||
}
|
||||
}
|
||||
|
||||
setDirtyRegion(d->dropRect);
|
||||
}
|
||||
|
||||
|
||||
void UrlItemView::startDrag(Qt::DropActions supportedActions)
|
||||
{
|
||||
Q_UNUSED(supportedActions)
|
||||
//kDebug() << "Starting UrlItemView drag with actions" << supportedActions;
|
||||
|
||||
if (!d->watchedIndexForDrag.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QMimeData *mimeData = model()->mimeData(selectionModel()->selectedIndexes());
|
||||
|
||||
if (!mimeData || mimeData->text().isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setMimeData(mimeData);
|
||||
|
||||
QModelIndex idx = selectionModel()->selectedIndexes().first();
|
||||
QIcon icon = idx.data(Qt::DecorationRole).value<QIcon>();
|
||||
d->draggedRow = idx.row();
|
||||
drag->setPixmap(icon.pixmap(IconSize(KIconLoader::Desktop)));
|
||||
|
||||
d->dropRect = QRect();
|
||||
drag->exec(Qt::CopyAction|Qt::MoveAction|Qt::LinkAction);
|
||||
}
|
||||
|
||||
void UrlItemView::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if (!d->dragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This special code is necessary in order to be able to
|
||||
// inidcate to the model WHERE the item should be dropped,
|
||||
// Since the model cannot tell where the user dropped the
|
||||
// item. The model itself handles the actual moving of the
|
||||
// item.
|
||||
if (dragDropMode() == QAbstractItemView::DragDrop) {
|
||||
int row;
|
||||
QPoint pos = event->pos();
|
||||
QModelIndex parent = indexAt(pos);
|
||||
|
||||
if (!parent.isValid()) {
|
||||
return;
|
||||
}
|
||||
const QRect rect = visualRect(parent);
|
||||
|
||||
row = parent.row();
|
||||
|
||||
if(d->insertBelow(rect, pos) && d->draggedRow > row) {
|
||||
row++;
|
||||
} else if(d->insertAbove(rect, pos) && d->draggedRow < row) {
|
||||
row--;
|
||||
}
|
||||
|
||||
model()->dropMimeData(event->mimeData(), event->dropAction(),
|
||||
row, 0, parent);
|
||||
|
||||
d->dragging = false;
|
||||
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
void UrlItemView::leaveEvent(QEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
//kDebug() << "UrlItemView leave event";
|
||||
|
||||
d->hoveredIndex = QModelIndex();
|
||||
setCurrentIndex(QModelIndex());
|
||||
}
|
||||
|
||||
ItemStateProvider *UrlItemView::itemStateProvider() const
|
||||
{
|
||||
return d->itemStateProvider;
|
||||
}
|
||||
#include "moc_urlitemview.cpp"
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef URLITEMVIEW_H
|
||||
#define URLITEMVIEW_H
|
||||
|
||||
// Qt
|
||||
#include <QAbstractItemView>
|
||||
|
||||
namespace Kickoff
|
||||
{
|
||||
|
||||
class ItemStateProvider;
|
||||
class UrlItemView : public QAbstractItemView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UrlItemView(QWidget *parent = 0);
|
||||
virtual ~UrlItemView();
|
||||
|
||||
void setItemStateProvider(ItemStateProvider *provider);
|
||||
ItemStateProvider *itemStateProvider() const;
|
||||
|
||||
// reimplemented from QAbstractItemView
|
||||
virtual QModelIndex indexAt(const QPoint& point) const;
|
||||
virtual void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible);
|
||||
virtual QRect visualRect(const QModelIndex& index) const;
|
||||
virtual void setModel(QAbstractItemModel *model);
|
||||
|
||||
/* if nothing is selected, the first item is
|
||||
* @returns whether the selection has changed
|
||||
*/
|
||||
bool initializeSelection();
|
||||
|
||||
protected:
|
||||
// reimplemented from QAbstractItemView
|
||||
virtual int horizontalOffset() const;
|
||||
virtual bool isIndexHidden(const QModelIndex& index) const;
|
||||
virtual QModelIndex moveCursor(CursorAction action, Qt::KeyboardModifiers modifiers);
|
||||
virtual void setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags);
|
||||
virtual int verticalOffset() const;
|
||||
virtual QRegion visualRegionForSelection(const QItemSelection& selection) const;
|
||||
virtual void startDrag(Qt::DropActions supportedActions);
|
||||
virtual void dragEnterEvent(QDragEnterEvent *event);
|
||||
virtual void dragLeaveEvent(QDragLeaveEvent *event);
|
||||
virtual void dragMoveEvent(QDragMoveEvent *event);
|
||||
|
||||
// reimplemented from QWidget
|
||||
virtual void paintEvent(QPaintEvent *event);
|
||||
virtual void resizeEvent(QResizeEvent *event);
|
||||
virtual void mouseMoveEvent(QMouseEvent *event);
|
||||
virtual void mousePressEvent(QMouseEvent *event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event);
|
||||
virtual void dropEvent(QDropEvent *event);
|
||||
virtual void leaveEvent(QEvent *event);
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
// lays out all items in the view and sets the current index to the first
|
||||
// selectable item
|
||||
void updateLayout();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // URLITEMVIEW_H
|
25
plasma/applets/launcher/CMakeLists.txt
Normal file
25
plasma/applets/launcher/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
project(plasma-applet-launcher)
|
||||
|
||||
set(launcher_SRCS
|
||||
launcher.cpp
|
||||
)
|
||||
|
||||
kde4_add_plugin(plasma_applet_launcher ${launcher_SRCS})
|
||||
target_link_libraries(plasma_applet_launcher
|
||||
KDE4::plasma
|
||||
KDE4::kio
|
||||
KDE4::solid
|
||||
KDE4::kcmutils
|
||||
${QT_QTNETWORK_LIBRARY}
|
||||
kworkspace
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS plasma_applet_launcher
|
||||
DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}
|
||||
)
|
||||
|
||||
install(
|
||||
FILES plasma-applet-launcher.desktop
|
||||
DESTINATION ${KDE4_SERVICES_INSTALL_DIR}
|
||||
)
|
|
@ -1,3 +1,2 @@
|
|||
#!/bin/bash
|
||||
$EXTRACTRC `find . -name \*.ui` >> rc.cpp
|
||||
$XGETTEXT `find . -name \*.cpp` -o $podir/plasma_applet_launcher.pot
|
976
plasma/applets/launcher/launcher.cpp
Normal file
976
plasma/applets/launcher/launcher.cpp
Normal file
|
@ -0,0 +1,976 @@
|
|||
/*
|
||||
This file is part of the KDE project
|
||||
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2, as published by the Free Software Foundation.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "launcher.h"
|
||||
#include "kworkspace/kworkspace.h"
|
||||
#include "kworkspace/kdisplaymanager.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QGraphicsLinearLayout>
|
||||
#include <QGraphicsGridLayout>
|
||||
#include <QHostInfo>
|
||||
#include <QDBusInterface>
|
||||
#include <KUser>
|
||||
#include <kdbusconnectionpool.h>
|
||||
#include <KIcon>
|
||||
#include <KIconLoader>
|
||||
#include <KStandardDirs>
|
||||
#include <KSycoca>
|
||||
#include <KRun>
|
||||
#include <KBookmarkManager>
|
||||
#include <KServiceGroup>
|
||||
#include <KDirWatch>
|
||||
#include <KDesktopFile>
|
||||
#include <KRecentDocument>
|
||||
#include <Solid/PowerManagement>
|
||||
#include <Plasma/IconWidget>
|
||||
#include <Plasma/Separator>
|
||||
#include <Plasma/Label>
|
||||
#include <Plasma/LineEdit>
|
||||
#include <Plasma/TabBar>
|
||||
#include <Plasma/ScrollWidget>
|
||||
#include <Plasma/RunnerManager>
|
||||
#include <KDebug>
|
||||
|
||||
static const QString s_defaultpopupicon = QString::fromLatin1("start-here-kde");
|
||||
static const QSizeF s_minimumsize = QSizeF(450, 350);
|
||||
static const QString s_firsttimeaddress = QString::fromLatin1("_k_firsttime");
|
||||
static const QStringList s_firsttimeservices = QStringList()
|
||||
<< QString::fromLatin1("konsole")
|
||||
<< QString::fromLatin1("dolphin")
|
||||
<< QString::fromLatin1("systemsettings");
|
||||
|
||||
static QSizeF kIconSize()
|
||||
{
|
||||
const int iconsize = KIconLoader::global()->currentSize(KIconLoader::Desktop);
|
||||
return QSizeF(iconsize, iconsize);
|
||||
}
|
||||
|
||||
// TODO: custom widget to catch hover events from anywhere in the widget rect?
|
||||
static Plasma::IconWidget* kMakeIconWidget(QGraphicsWidget *parent,
|
||||
const QSizeF &iconsize,
|
||||
const QString &text,
|
||||
const QString &infotext,
|
||||
const QString &icon,
|
||||
const QString &url)
|
||||
{
|
||||
Plasma::IconWidget* iconwidget = new Plasma::IconWidget(parent);
|
||||
iconwidget->setOrientation(Qt::Horizontal);
|
||||
iconwidget->setMinimumIconSize(iconsize);
|
||||
iconwidget->setMaximumIconSize(iconsize);
|
||||
iconwidget->setText(text);
|
||||
iconwidget->setInfoText(infotext);
|
||||
iconwidget->setIcon(icon);
|
||||
iconwidget->setProperty("_k_url", url);
|
||||
return iconwidget;
|
||||
}
|
||||
|
||||
static bool kCanLockScreen()
|
||||
{
|
||||
return KDBusConnectionPool::isServiceRegistered("org.freedesktop.ScreenSaver", QDBusConnection::sessionBus());
|
||||
}
|
||||
|
||||
static void kLockScreen()
|
||||
{
|
||||
QDBusInterface screensaver(
|
||||
"org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver",
|
||||
QDBusConnection::sessionBus()
|
||||
);
|
||||
screensaver.call("Lock");
|
||||
}
|
||||
|
||||
class LauncherSearch : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LauncherSearch(QGraphicsWidget *parent);
|
||||
|
||||
void prepare();
|
||||
void query(const QString &text);
|
||||
void finish();
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotUpdateLayout(const QList<Plasma::QueryMatch> &matches);
|
||||
void slotActivated();
|
||||
void slotTriggered();
|
||||
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
QGraphicsLinearLayout* m_layout;
|
||||
QList<Plasma::IconWidget*> m_iconwidgets;
|
||||
Plasma::Label* m_label;
|
||||
Plasma::RunnerManager* m_runnermanager;
|
||||
};
|
||||
|
||||
LauncherSearch::LauncherSearch(QGraphicsWidget *parent)
|
||||
: QGraphicsWidget(parent),
|
||||
m_layout(nullptr),
|
||||
m_label(nullptr),
|
||||
m_runnermanager(nullptr)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
|
||||
setLayout(m_layout);
|
||||
|
||||
m_label = new Plasma::Label(this);
|
||||
m_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_label->setAlignment(Qt::AlignCenter);
|
||||
m_label->setText(i18n("No matches found"));
|
||||
m_layout->addItem(m_label);
|
||||
|
||||
m_runnermanager = new Plasma::RunnerManager(this);
|
||||
connect(
|
||||
m_runnermanager, SIGNAL(matchesChanged(QList<Plasma::QueryMatch>)),
|
||||
this, SLOT(slotUpdateLayout(QList<Plasma::QueryMatch>))
|
||||
);
|
||||
// TODO: option to disable and enable runners
|
||||
// m_runnermanager->setAllowedRunners(s_allowedrunners);
|
||||
}
|
||||
|
||||
void LauncherSearch::prepare()
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
QMutexLocker locker(&m_mutex);
|
||||
foreach (Plasma::IconWidget* iconwidget, m_iconwidgets) {
|
||||
m_layout->removeItem(iconwidget);
|
||||
}
|
||||
qDeleteAll(m_iconwidgets);
|
||||
m_iconwidgets.clear();
|
||||
|
||||
m_label->setVisible(true);
|
||||
adjustSize();
|
||||
|
||||
m_runnermanager->reset();
|
||||
}
|
||||
|
||||
void LauncherSearch::query(const QString &text)
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << text;
|
||||
m_runnermanager->launchQuery(text);
|
||||
}
|
||||
|
||||
void LauncherSearch::finish()
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
m_runnermanager->matchSessionComplete();
|
||||
}
|
||||
|
||||
void LauncherSearch::slotUpdateLayout(const QList<Plasma::QueryMatch> &matches)
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_label->setVisible(false);
|
||||
adjustSize();
|
||||
|
||||
const QSizeF iconsize = kIconSize();
|
||||
foreach (const Plasma::QueryMatch &match, matches) {
|
||||
// qDebug() << Q_FUNC_INFO << match.text() << match.subtext();
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, match.text(), match.subtext(), QString(), match.id()
|
||||
);
|
||||
iconwidget->setIcon(match.icon());
|
||||
if (match.type() == Plasma::QueryMatch::InformationalMatch) {
|
||||
iconwidget->setAcceptHoverEvents(false);
|
||||
iconwidget->setAcceptedMouseButtons(Qt::NoButton);
|
||||
}
|
||||
int counter = 1;
|
||||
if (match.hasConfigurationInterface()) {
|
||||
// TODO: action is set but where is it?
|
||||
QAction* matchconfigaction = new QAction(iconwidget);
|
||||
matchconfigaction->setText(i18n("Configure"));
|
||||
matchconfigaction->setIcon(KIcon("system-preferences"));
|
||||
matchconfigaction->setProperty("_k_id", match.id());
|
||||
connect(
|
||||
matchconfigaction, SIGNAL(triggered()),
|
||||
this, SLOT(slotTriggered())
|
||||
);
|
||||
iconwidget->addIconAction(matchconfigaction);
|
||||
counter++;
|
||||
qDebug() << Q_FUNC_INFO << match.id();
|
||||
}
|
||||
foreach (QAction* action, m_runnermanager->actionsForMatch(match)) {
|
||||
iconwidget->addIconAction(action);
|
||||
if (counter >= 4) {
|
||||
// the limit of Plasma::IconWidget
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherSearch::slotActivated()
|
||||
{
|
||||
Plasma::IconWidget* iconwidget = qobject_cast<Plasma::IconWidget*>(sender());
|
||||
const QString iconwidgeturl = iconwidget->property("_k_url").toString();
|
||||
m_runnermanager->run(iconwidgeturl);
|
||||
}
|
||||
|
||||
void LauncherSearch::slotTriggered()
|
||||
{
|
||||
QAction* matchconfigaction = qobject_cast<QAction*>(sender());
|
||||
const QString matchconfigid = matchconfigaction->property("_k_id").toString();
|
||||
Plasma::AbstractRunner* runner = m_runnermanager->runner(m_runnermanager->runnerName(matchconfigid));
|
||||
if (!runner) {
|
||||
kWarning() << "no runner for" << matchconfigid;
|
||||
return;
|
||||
}
|
||||
// TODO: implement
|
||||
qDebug() << Q_FUNC_INFO << matchconfigid;
|
||||
}
|
||||
|
||||
class LauncherFavorites : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LauncherFavorites(QGraphicsWidget *parent);
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotUpdateLayout();
|
||||
void slotActivated();
|
||||
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
QGraphicsLinearLayout* m_layout;
|
||||
QList<Plasma::IconWidget*> m_iconwidgets;
|
||||
KBookmarkManager* m_bookmarkmanager;
|
||||
};
|
||||
|
||||
// TODO: context menu to remove
|
||||
LauncherFavorites::LauncherFavorites(QGraphicsWidget *parent)
|
||||
: QGraphicsWidget(parent),
|
||||
m_layout(nullptr),
|
||||
m_bookmarkmanager(nullptr)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
|
||||
setLayout(m_layout);
|
||||
|
||||
const QString bookmarfile = KStandardDirs::locateLocal("data", "plasma/bookmarks.xml");
|
||||
m_bookmarkmanager = KBookmarkManager::managerForFile(bookmarfile, "launcher");
|
||||
// m_bookmarkmanager->slotEditBookmarks();
|
||||
slotUpdateLayout();
|
||||
connect(
|
||||
m_bookmarkmanager, SIGNAL(changed(QString,QString)),
|
||||
this, SLOT(slotUpdateLayout())
|
||||
);
|
||||
connect(
|
||||
KSycoca::self(), SIGNAL(databaseChanged(QStringList)),
|
||||
this, SLOT(slotUpdateLayout())
|
||||
);
|
||||
}
|
||||
|
||||
void LauncherFavorites::slotUpdateLayout()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
foreach (Plasma::IconWidget* iconwidget, m_iconwidgets) {
|
||||
m_layout->removeItem(iconwidget);
|
||||
}
|
||||
qDeleteAll(m_iconwidgets);
|
||||
m_iconwidgets.clear();
|
||||
|
||||
adjustSize();
|
||||
|
||||
bool isfirsttime = true;
|
||||
KBookmarkGroup bookmarkgroup = m_bookmarkmanager->root();
|
||||
// first time gets a special treatment
|
||||
KBookmark bookmark = bookmarkgroup.first();
|
||||
while (!bookmark.isNull()) {
|
||||
if (bookmark.url().url() == s_firsttimeaddress) {
|
||||
isfirsttime = false;
|
||||
break;
|
||||
}
|
||||
bookmark = bookmarkgroup.next(bookmark);
|
||||
}
|
||||
if (isfirsttime) {
|
||||
bookmark = bookmarkgroup.createNewSeparator();
|
||||
bookmark.setUrl(s_firsttimeaddress);
|
||||
bookmark.setDescription("internal bookmark");
|
||||
foreach (const QString &name, s_firsttimeservices) {
|
||||
KService::Ptr service = KService::serviceByDesktopName(name);
|
||||
if (!service.isNull()) {
|
||||
bookmarkgroup.addBookmark(service->desktopEntryName(), KUrl(service->entryPath()), service->icon());
|
||||
} else {
|
||||
kWarning() << "invalid first-time serivce" << name;
|
||||
}
|
||||
}
|
||||
m_bookmarkmanager->emitChanged(bookmarkgroup);
|
||||
}
|
||||
|
||||
const QSizeF iconsize = kIconSize();
|
||||
bookmark = bookmarkgroup.first();
|
||||
while (!bookmark.isNull()) {
|
||||
// qDebug() << Q_FUNC_INFO << bookmark.text() << bookmark.description() << bookmark.icon() << bookmark.url();
|
||||
if (bookmark.isSeparator()) {
|
||||
bookmark = bookmarkgroup.next(bookmark);
|
||||
continue;
|
||||
}
|
||||
const QString serviceentrypath = bookmark.url().url();
|
||||
KService::Ptr service = KService::serviceByDesktopPath(serviceentrypath);
|
||||
if (service.isNull()) {
|
||||
service = KService::serviceByDesktopName(bookmark.text());
|
||||
}
|
||||
if (service.isNull()) {
|
||||
kWarning() << "could not find service for" << serviceentrypath;
|
||||
bookmark = bookmarkgroup.next(bookmark);
|
||||
continue;
|
||||
}
|
||||
// qDebug() << Q_FUNC_INFO << service->entryPath() << service->name() << service->comment();
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, service->name(), service->genericName(), service->icon(), service->entryPath()
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
bookmark = bookmarkgroup.next(bookmark);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherFavorites::slotActivated()
|
||||
{
|
||||
Plasma::IconWidget* iconwidget = qobject_cast<Plasma::IconWidget*>(sender());
|
||||
const QString iconwidgeturl = iconwidget->property("_k_url").toString();
|
||||
(void)new KRun(KUrl(iconwidgeturl), nullptr);
|
||||
}
|
||||
|
||||
|
||||
class LauncherServiceWidget : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LauncherServiceWidget(QGraphicsWidget *parent, Plasma::TabBar *tabbar, const int tabindex);
|
||||
|
||||
void appendGroup(Plasma::IconWidget* iconwidget, LauncherServiceWidget* servicewidget);
|
||||
void appendApp(Plasma::IconWidget* iconwidget);
|
||||
int serviceCount() const;
|
||||
int tabIndex() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void slotGroupActivated();
|
||||
void slotAppActivated();
|
||||
|
||||
private:
|
||||
Plasma::TabBar* m_tabbar;
|
||||
int m_tabindex;
|
||||
QGraphicsLinearLayout* m_layout;
|
||||
QList<Plasma::IconWidget*> m_iconwidgets;
|
||||
};
|
||||
|
||||
LauncherServiceWidget::LauncherServiceWidget(QGraphicsWidget *parent, Plasma::TabBar *tabbar, const int tabindex)
|
||||
: QGraphicsWidget(parent),
|
||||
m_tabbar(tabbar),
|
||||
m_tabindex(tabindex),
|
||||
m_layout(nullptr)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
|
||||
setLayout(m_layout);
|
||||
}
|
||||
|
||||
int LauncherServiceWidget::serviceCount() const
|
||||
{
|
||||
return m_iconwidgets.size();
|
||||
}
|
||||
|
||||
int LauncherServiceWidget::tabIndex() const
|
||||
{
|
||||
return m_tabindex;
|
||||
}
|
||||
|
||||
void LauncherServiceWidget::appendGroup(Plasma::IconWidget* iconwidget, LauncherServiceWidget* servicewidget)
|
||||
{
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
servicewidget, SLOT(slotGroupActivated())
|
||||
);
|
||||
}
|
||||
|
||||
void LauncherServiceWidget::appendApp(Plasma::IconWidget* iconwidget)
|
||||
{
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotAppActivated())
|
||||
);
|
||||
}
|
||||
|
||||
void LauncherServiceWidget::slotGroupActivated()
|
||||
{
|
||||
m_tabbar->setCurrentIndex(m_tabindex);
|
||||
}
|
||||
|
||||
void LauncherServiceWidget::slotAppActivated()
|
||||
{
|
||||
Plasma::IconWidget* iconwidget = qobject_cast<Plasma::IconWidget*>(sender());
|
||||
const QString iconwidgeturl = iconwidget->property("_k_url").toString();
|
||||
(void)new KRun(KUrl(iconwidgeturl), nullptr);
|
||||
}
|
||||
|
||||
class LauncherApplications : public Plasma::TabBar
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LauncherApplications(QGraphicsWidget *parent);
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotUpdateLayout();
|
||||
|
||||
private:
|
||||
void addGroup(LauncherServiceWidget *servicewidget, KServiceGroup::Ptr group);
|
||||
|
||||
QMutex m_mutex;
|
||||
Plasma::ScrollWidget* m_rootscrollwidget;
|
||||
LauncherServiceWidget* m_root;
|
||||
QList<Plasma::ScrollWidget*> m_tabscrollwidgets;
|
||||
QList<LauncherServiceWidget*> m_tabwidgets;
|
||||
};
|
||||
|
||||
LauncherApplications::LauncherApplications(QGraphicsWidget *parent)
|
||||
: Plasma::TabBar(parent),
|
||||
m_rootscrollwidget(nullptr),
|
||||
m_root(nullptr)
|
||||
{
|
||||
// TODO: navigation bar instead
|
||||
// setTabBarShown(false);
|
||||
|
||||
slotUpdateLayout();
|
||||
|
||||
connect(
|
||||
KSycoca::self(), SIGNAL(databaseChanged(QStringList)),
|
||||
this, SLOT(slotUpdateLayout())
|
||||
);
|
||||
}
|
||||
|
||||
void LauncherApplications::slotUpdateLayout()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
qDeleteAll(m_tabwidgets);
|
||||
m_tabwidgets.clear();
|
||||
delete m_root;
|
||||
m_root = nullptr;
|
||||
delete m_rootscrollwidget;
|
||||
m_rootscrollwidget = nullptr;
|
||||
|
||||
m_rootscrollwidget = new Plasma::ScrollWidget(this);
|
||||
m_rootscrollwidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_root = new LauncherServiceWidget(m_rootscrollwidget, this, 0);
|
||||
m_rootscrollwidget->setWidget(m_root);
|
||||
addTab(KIcon("applications-other"), "root", m_rootscrollwidget);
|
||||
|
||||
KServiceGroup::Ptr group = KServiceGroup::root();
|
||||
if (group && group->isValid()) {
|
||||
addGroup(m_root, group);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherApplications::addGroup(LauncherServiceWidget *servicewidget, KServiceGroup::Ptr group)
|
||||
{
|
||||
const QString name = group->name();
|
||||
if (name.isEmpty() || group->noDisplay()) {
|
||||
kDebug() << "hidden or invalid group" << name;
|
||||
return;
|
||||
}
|
||||
|
||||
const QSizeF iconsize = kIconSize();
|
||||
foreach (const KServiceGroup::Ptr subgroup, group->groupEntries(KServiceGroup::NoOptions)) {
|
||||
Plasma::ScrollWidget* scrollwidget = new Plasma::ScrollWidget(this);
|
||||
scrollwidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
LauncherServiceWidget* subgroupwidget = new LauncherServiceWidget(scrollwidget, this, servicewidget->tabIndex() + 1);
|
||||
addGroup(subgroupwidget, subgroup);
|
||||
if (subgroupwidget->serviceCount() < 1) {
|
||||
delete subgroupwidget;
|
||||
delete scrollwidget;
|
||||
} else {
|
||||
scrollwidget->setWidget(subgroupwidget);
|
||||
m_tabscrollwidgets.append(scrollwidget);
|
||||
Plasma::IconWidget* subgroupiconwidget = kMakeIconWidget(
|
||||
servicewidget,
|
||||
iconsize, subgroup->caption(), subgroup->comment(), subgroup->icon(), QString()
|
||||
);
|
||||
servicewidget->appendGroup(subgroupiconwidget, subgroupwidget);
|
||||
addTab(KIcon("applications-other"), subgroup->caption(), scrollwidget);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const KService::Ptr app, group->serviceEntries(KServiceGroup::NoOptions)) {
|
||||
if (app->noDisplay()) {
|
||||
kDebug() << "hidden entry" << app->name();
|
||||
continue;
|
||||
}
|
||||
Plasma::IconWidget* appiconwidget = kMakeIconWidget(
|
||||
servicewidget,
|
||||
iconsize, app->name(), app->comment(), app->icon(), app->entryPath()
|
||||
);
|
||||
servicewidget->appendApp(appiconwidget);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LauncherRecent : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LauncherRecent(QGraphicsWidget *parent);
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotUpdateLayout();
|
||||
void slotActivated();
|
||||
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
QGraphicsLinearLayout* m_layout;
|
||||
QList<Plasma::IconWidget*> m_iconwidgets;
|
||||
KDirWatch* m_dirwatch;
|
||||
};
|
||||
|
||||
LauncherRecent::LauncherRecent(QGraphicsWidget *parent)
|
||||
: QGraphicsWidget(parent),
|
||||
m_layout(nullptr),
|
||||
m_dirwatch(nullptr)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
|
||||
setLayout(m_layout);
|
||||
|
||||
m_dirwatch = new KDirWatch(this);
|
||||
m_dirwatch->addDir(KRecentDocument::recentDocumentDirectory());
|
||||
slotUpdateLayout();
|
||||
connect(
|
||||
m_dirwatch, SIGNAL(dirty(QString)),
|
||||
this, SLOT(slotUpdateLayout())
|
||||
);
|
||||
}
|
||||
|
||||
void LauncherRecent::slotUpdateLayout()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
foreach (Plasma::IconWidget* iconwidget, m_iconwidgets) {
|
||||
m_layout->removeItem(iconwidget);
|
||||
}
|
||||
qDeleteAll(m_iconwidgets);
|
||||
m_iconwidgets.clear();
|
||||
|
||||
adjustSize();
|
||||
|
||||
const QSizeF iconsize = kIconSize();
|
||||
foreach (const QString &recent, KRecentDocument::recentDocuments()) {
|
||||
KDesktopFile recentfile(recent);
|
||||
// qDebug() << Q_FUNC_INFO << recentfile.readName() << recentfile.readComment();
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, recentfile.readName(), recentfile.readComment(), recentfile.readIcon(), recentfile.readUrl()
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherRecent::slotActivated()
|
||||
{
|
||||
Plasma::IconWidget* iconwidget = qobject_cast<Plasma::IconWidget*>(sender());
|
||||
const QString iconwidgeturl = iconwidget->property("_k_url").toString();
|
||||
(void)new KRun(KUrl(iconwidgeturl), nullptr);
|
||||
}
|
||||
|
||||
|
||||
class LauncherLeave : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LauncherLeave(QGraphicsWidget *parent);
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotUpdateLayout();
|
||||
void slotActivated();
|
||||
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
QGraphicsLinearLayout* m_layout;
|
||||
QList<Plasma::IconWidget*> m_iconwidgets;
|
||||
Plasma::Separator* m_systemseparator;
|
||||
};
|
||||
|
||||
// TODO: check for lock and switchable state changes
|
||||
LauncherLeave::LauncherLeave(QGraphicsWidget *parent)
|
||||
: QGraphicsWidget(parent),
|
||||
m_systemseparator(nullptr)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
|
||||
setLayout(m_layout);
|
||||
|
||||
slotUpdateLayout();
|
||||
connect(
|
||||
Solid::PowerManagement::notifier(), SIGNAL(supportedSleepStatesChanged()),
|
||||
this, SLOT(slotUpdateLayout())
|
||||
);
|
||||
}
|
||||
|
||||
void LauncherLeave::slotUpdateLayout()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
foreach (Plasma::IconWidget* iconwidget, m_iconwidgets) {
|
||||
m_layout->removeItem(iconwidget);
|
||||
}
|
||||
qDeleteAll(m_iconwidgets);
|
||||
m_iconwidgets.clear();
|
||||
|
||||
if (m_systemseparator) {
|
||||
m_layout->removeItem(m_systemseparator);
|
||||
delete m_systemseparator;
|
||||
m_systemseparator = nullptr;
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
|
||||
const QSizeF iconsize = kIconSize();
|
||||
bool hassessionicon = false;
|
||||
if (kCanLockScreen()) {
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, i18n("Lock"), i18n("Lock screen"), "system-lock-screen", "lock"
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
hassessionicon = true;
|
||||
}
|
||||
if (KDisplayManager().isSwitchable()) {
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, i18n("Switch user"), i18n("Start a parallel session as a different user"), "system-switch-user", "switch"
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
hassessionicon = true;
|
||||
}
|
||||
if (hassessionicon) {
|
||||
m_systemseparator = new Plasma::Separator(this);
|
||||
m_systemseparator->setOrientation(Qt::Horizontal);
|
||||
m_layout->addItem(m_systemseparator);
|
||||
}
|
||||
|
||||
const QSet<Solid::PowerManagement::SleepState> sleepsates = Solid::PowerManagement::supportedSleepStates();
|
||||
if (sleepsates.contains(Solid::PowerManagement::SuspendState)) {
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, i18n("Sleep"), i18n("Suspend to RAM"), "system-suspend", "suspendram"
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
}
|
||||
if (sleepsates.contains(Solid::PowerManagement::HibernateState)) {
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, i18n("Hibernate"), i18n("Suspend to disk"), "system-suspend-hibernate", "suspenddisk"
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
}
|
||||
if (sleepsates.contains(Solid::PowerManagement::HybridSuspendState)) {
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, i18n("Hybrid Suspend"), i18n("Hybrid Suspend"), "system-suspend", "suspendhybrid"
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
}
|
||||
|
||||
if (KWorkSpace::canShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeReboot)) {
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, i18nc("Restart computer", "Restart"), i18n("Restart computer"), "system-reboot", "restart"
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
}
|
||||
if (KWorkSpace::canShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeHalt)) {
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, i18n("Shut down"), i18n("Turn off computer"), "system-shutdown", "shutdown"
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
}
|
||||
Plasma::IconWidget* iconwidget = kMakeIconWidget(
|
||||
this,
|
||||
iconsize, i18n("Log out"), i18n("End session"), "system-log-out", "logout"
|
||||
);
|
||||
m_iconwidgets.append(iconwidget);
|
||||
m_layout->addItem(iconwidget);
|
||||
connect(
|
||||
iconwidget, SIGNAL(activated()),
|
||||
this, SLOT(slotActivated())
|
||||
);
|
||||
}
|
||||
|
||||
void LauncherLeave::slotActivated()
|
||||
{
|
||||
Plasma::IconWidget* iconwidget = qobject_cast<Plasma::IconWidget*>(sender());
|
||||
const QString iconwidgeturl = iconwidget->property("_k_url").toString();
|
||||
if (iconwidgeturl == QLatin1String("lock")) {
|
||||
kLockScreen();
|
||||
} else if (iconwidgeturl == QLatin1String("switch")) {
|
||||
kLockScreen();
|
||||
KDisplayManager().newSession();
|
||||
} else if (iconwidgeturl == QLatin1String("suspendram")) {
|
||||
Solid::PowerManagement::requestSleep(Solid::PowerManagement::SuspendState);
|
||||
} else if (iconwidgeturl == QLatin1String("suspenddisk")) {
|
||||
Solid::PowerManagement::requestSleep(Solid::PowerManagement::HibernateState);
|
||||
} else if (iconwidgeturl == QLatin1String("suspendhybrid")) {
|
||||
Solid::PowerManagement::requestSleep(Solid::PowerManagement::HybridSuspendState);
|
||||
} else if (iconwidgeturl == QLatin1String("restart")) {
|
||||
KWorkSpace::requestShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeReboot);
|
||||
} else if (iconwidgeturl == QLatin1String("shutdown")) {
|
||||
KWorkSpace::requestShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeHalt);
|
||||
} else if (iconwidgeturl == QLatin1String("logout")) {
|
||||
KWorkSpace::requestShutDown(KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeNone);
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
kWarning() << "invalid url" << iconwidgeturl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LauncherAppletWidget : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LauncherAppletWidget(LauncherApplet* auncherapplet);
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotSearch(const QString &text);
|
||||
void slotTimeout();
|
||||
|
||||
private:
|
||||
LauncherApplet* m_launcherapplet;
|
||||
QGraphicsGridLayout* m_layout;
|
||||
Plasma::IconWidget* m_iconwidget;
|
||||
Plasma::Label* m_label;
|
||||
Plasma::LineEdit* m_lineedit;
|
||||
Plasma::TabBar* m_tabbar;
|
||||
Plasma::ScrollWidget* m_favoritesscrollwidget;
|
||||
LauncherFavorites* m_favoriteswidget;
|
||||
LauncherApplications* m_applicationswidget;
|
||||
Plasma::ScrollWidget* m_recentscrollwidget;
|
||||
LauncherRecent* m_recentwidget;
|
||||
Plasma::ScrollWidget* m_leavecrollwidget;
|
||||
LauncherLeave* m_leavewidget;
|
||||
Plasma::ScrollWidget* m_searchscrollwidget;
|
||||
LauncherSearch* m_searchwidget;
|
||||
QTimer* m_timer;
|
||||
};
|
||||
|
||||
LauncherAppletWidget::LauncherAppletWidget(LauncherApplet* auncherapplet)
|
||||
: QGraphicsWidget(auncherapplet),
|
||||
m_launcherapplet(auncherapplet),
|
||||
m_layout(nullptr),
|
||||
m_iconwidget(nullptr),
|
||||
m_label(nullptr),
|
||||
m_lineedit(nullptr),
|
||||
m_tabbar(nullptr),
|
||||
m_favoritesscrollwidget(nullptr),
|
||||
m_favoriteswidget(nullptr),
|
||||
m_applicationswidget(nullptr),
|
||||
m_recentscrollwidget(nullptr),
|
||||
m_recentwidget(nullptr),
|
||||
m_leavecrollwidget(nullptr),
|
||||
m_leavewidget(nullptr),
|
||||
m_searchscrollwidget(nullptr),
|
||||
m_searchwidget(nullptr),
|
||||
m_timer(nullptr)
|
||||
{
|
||||
m_layout = new QGraphicsGridLayout(this);
|
||||
|
||||
const QString hostname = QHostInfo::localHostName();
|
||||
KUser user(KUser::UseEffectiveUID);
|
||||
QString usericon = user.faceIconPath();
|
||||
if (usericon.isEmpty()) {
|
||||
usericon = QLatin1String("system-search");
|
||||
}
|
||||
m_iconwidget = new Plasma::IconWidget(this);
|
||||
const int iconsize = KIconLoader::global()->currentSize(KIconLoader::Toolbar);
|
||||
const QSizeF iconsizef = QSizeF(iconsize, iconsize);
|
||||
m_iconwidget->setMinimumIconSize(iconsizef);
|
||||
m_iconwidget->setMaximumIconSize(iconsizef);
|
||||
m_iconwidget->setAcceptHoverEvents(false);
|
||||
m_iconwidget->setAcceptedMouseButtons(Qt::NoButton);
|
||||
m_iconwidget->setIcon(usericon);
|
||||
m_layout->addItem(m_iconwidget, 0, 0);
|
||||
|
||||
QString usertext;
|
||||
QString fullusername = user.property(KUser::FullName);
|
||||
if (fullusername.isEmpty()) {
|
||||
usertext = i18nc("login name, hostname", "User <b>%1</b> on <b>%2</b>", user.loginName(), hostname);
|
||||
} else {
|
||||
usertext = i18nc("full name, login name, hostname", "<b>%1 (%2)</b> on <b>%3</b>", fullusername, user.loginName(), hostname);
|
||||
}
|
||||
m_label = new Plasma::Label(this);
|
||||
m_label->setWordWrap(false);
|
||||
m_label->setText(usertext);
|
||||
m_layout->addItem(m_label, 0, 1);
|
||||
|
||||
m_lineedit = new Plasma::LineEdit(this);
|
||||
m_lineedit->setClickMessage(i18n("Search"));
|
||||
m_layout->addItem(m_lineedit, 0, 2);
|
||||
setFocusProxy(m_lineedit);
|
||||
|
||||
m_tabbar = new Plasma::TabBar(this);
|
||||
// has not effect..
|
||||
// m_tabbar->nativeWidget()->setShape(QTabBar::RoundedSouth);
|
||||
m_favoritesscrollwidget = new Plasma::ScrollWidget(m_tabbar);
|
||||
m_favoritesscrollwidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_favoritesscrollwidget->setMinimumSize(s_minimumsize);
|
||||
m_favoriteswidget = new LauncherFavorites(m_favoritesscrollwidget);
|
||||
m_favoritesscrollwidget->setWidget(m_favoriteswidget);
|
||||
m_tabbar->addTab(KIcon("bookmarks"), i18n("Favorites"), m_favoritesscrollwidget);
|
||||
m_applicationswidget = new LauncherApplications(m_tabbar);
|
||||
m_applicationswidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_applicationswidget->setMinimumSize(s_minimumsize);
|
||||
m_tabbar->addTab(KIcon("applications-other"), i18n("Applications"), m_applicationswidget);
|
||||
m_recentscrollwidget = new Plasma::ScrollWidget(m_tabbar);
|
||||
m_recentscrollwidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_recentscrollwidget->setMinimumSize(s_minimumsize);
|
||||
m_recentwidget = new LauncherRecent(m_recentscrollwidget);
|
||||
m_recentscrollwidget->setWidget(m_recentwidget);
|
||||
m_tabbar->addTab(KIcon("document-open-recent"), i18n("Recently User"), m_recentscrollwidget);
|
||||
m_leavecrollwidget = new Plasma::ScrollWidget(m_tabbar);
|
||||
m_leavecrollwidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_leavecrollwidget->setMinimumSize(s_minimumsize);
|
||||
m_leavewidget = new LauncherLeave(m_leavecrollwidget);
|
||||
m_leavecrollwidget->setWidget(m_leavewidget);
|
||||
m_tabbar->addTab(KIcon("system-shutdown"), i18n("Leave"), m_leavecrollwidget);
|
||||
m_layout->addItem(m_tabbar, 1, 0, 1, 3);
|
||||
|
||||
m_searchscrollwidget = new Plasma::ScrollWidget(this);
|
||||
m_searchscrollwidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_searchscrollwidget->setMinimumSize(s_minimumsize);
|
||||
m_searchscrollwidget->setVisible(false);
|
||||
m_searchwidget = new LauncherSearch(m_searchscrollwidget);
|
||||
m_searchscrollwidget->setWidget(m_searchwidget);
|
||||
m_layout->addItem(m_searchscrollwidget, 2, 0, 1, 3);
|
||||
connect(
|
||||
m_lineedit, SIGNAL(textChanged(QString)),
|
||||
this, SLOT(slotSearch(QString))
|
||||
);
|
||||
|
||||
m_timer = new QTimer(this);
|
||||
m_timer->setSingleShot(true);
|
||||
m_timer->setInterval(500);
|
||||
connect(
|
||||
m_timer, SIGNAL(timeout()),
|
||||
this, SLOT(slotTimeout())
|
||||
);
|
||||
|
||||
setLayout(m_layout);
|
||||
m_layout->setColumnStretchFactor(2, 100);
|
||||
}
|
||||
|
||||
void LauncherAppletWidget::slotSearch(const QString &text)
|
||||
{
|
||||
const QString query = text.trimmed();
|
||||
if (query.isEmpty()) {
|
||||
m_timer->stop();
|
||||
m_searchwidget->finish();
|
||||
m_searchscrollwidget->setVisible(false);
|
||||
m_tabbar->setVisible(true);
|
||||
return;
|
||||
}
|
||||
m_searchwidget->prepare();
|
||||
m_timer->start();
|
||||
}
|
||||
|
||||
void LauncherAppletWidget::slotTimeout()
|
||||
{
|
||||
m_searchwidget->query(m_lineedit->text());
|
||||
m_tabbar->setVisible(false);
|
||||
m_searchscrollwidget->setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
LauncherApplet::LauncherApplet(QObject *parent, const QVariantList &args)
|
||||
: Plasma::PopupApplet(parent, args),
|
||||
m_launcherwidget(nullptr)
|
||||
{
|
||||
KGlobal::locale()->insertCatalog("plasma_applet_launcher");
|
||||
setPopupIcon(s_defaultpopupicon);
|
||||
setAspectRatioMode(Plasma::IgnoreAspectRatio);
|
||||
|
||||
m_launcherwidget = new LauncherAppletWidget(this);
|
||||
}
|
||||
|
||||
QGraphicsWidget *LauncherApplet::graphicsWidget()
|
||||
{
|
||||
return m_launcherwidget;
|
||||
}
|
||||
|
||||
void LauncherApplet::popupEvent(bool show)
|
||||
{
|
||||
if (show) {
|
||||
m_launcherwidget->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
#include "launcher.moc"
|
||||
#include "moc_launcher.cpp"
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
Copyright 2008 Andrew Lake <jamboarder@yahoo.com>
|
||||
This file is part of the KDE project
|
||||
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
License version 2, as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
@ -17,22 +17,30 @@
|
|||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CONTENTAREACAP_H
|
||||
#define CONTENTAREACAP_H
|
||||
#ifndef LAUNCHER_H
|
||||
#define LAUNCHER_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <Plasma/PopupApplet>
|
||||
|
||||
class ContentAreaCap: public QWidget
|
||||
class LauncherAppletWidget;
|
||||
|
||||
class LauncherApplet : public Plasma::PopupApplet
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ContentAreaCap(QWidget *parent, bool flip = false);
|
||||
LauncherApplet(QObject *parent, const QVariantList &args);
|
||||
|
||||
// Plasma::PopupApplet reimplementation
|
||||
QGraphicsWidget* graphicsWidget() final;
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *event);
|
||||
bool flipCap;
|
||||
void popupEvent(bool show) final;
|
||||
|
||||
private:
|
||||
friend LauncherAppletWidget;
|
||||
LauncherAppletWidget *m_launcherwidget;
|
||||
};
|
||||
|
||||
#endif
|
||||
K_EXPORT_PLASMA_APPLET(launcher, LauncherApplet)
|
||||
|
||||
#endif // LAUNCHER_H
|
|
@ -169,10 +169,10 @@ Type=Service
|
|||
X-KDE-ServiceTypes=Plasma/Applet
|
||||
|
||||
X-KDE-Library=plasma_applet_launcher
|
||||
X-KDE-PluginInfo-Author=Robert Knight
|
||||
X-KDE-PluginInfo-Email=robertknight@gmail.com
|
||||
X-KDE-PluginInfo-Author=Ivailo Monev
|
||||
X-KDE-PluginInfo-Email=xakepa10@gmail.com
|
||||
X-KDE-PluginInfo-Name=launcher
|
||||
X-KDE-PluginInfo-Version=1.0
|
||||
X-KDE-PluginInfo-Version=2.0
|
||||
X-KDE-PluginInfo-Website=
|
||||
X-KDE-PluginInfo-Category=Application Launchers
|
||||
X-KDE-PluginInfo-Depends=
|
Loading…
Add table
Reference in a new issue