subtree merge of kdelibs/plasma into plasma

This commit is contained in:
Marco Martin 2013-01-30 13:43:33 +01:00
commit 7d636803e6
288 changed files with 44779 additions and 0 deletions

2
plasma/.krazy Normal file
View File

@ -0,0 +1,2 @@
EXTRA defines,kdebug,qenums,tipsandthis
SKIP /widgets/template\.h

304
plasma/CMakeLists.txt Normal file
View File

@ -0,0 +1,304 @@
# This option should be removed, or moved down as far as possible.
# That means porting the existing frameworks to the CMake automoc
# feature. Porting is mostly removing explicit moc includes, and
# leaving the ones which are truly needed (ie, if you remove
# them, the build fails).
set(CMAKE_AUTOMOC_RELAXED_MODE ON)
if(KDE_PLATFORM_FEATURE_BINARY_COMPATIBLE_FEATURE_REDUCTION)
set(PLASMA_NO_KNEWSTUFF TRUE)
set(PLASMA_NO_SOLID TRUE)
set(PLASMA_NO_KIO TRUE)
set(PLASMA_NO_PACKAGEKIT TRUE)
set(PLASMA_NO_PACKAGE_EXTRADATA TRUE)
set(PLASMA_NO_KUTILS TRUE)
set(PLASMA_NO_GLOBAL_SHORTCUTS TRUE)
endif(KDE_PLATFORM_FEATURE_BINARY_COMPATIBLE_FEATURE_REDUCTION)
if(NOT X11_FOUND)
set(PLASMA_NO_PACKAGEKIT TRUE)
endif(NOT X11_FOUND)
#find_package(KdepimLibs 4.5.60)
#find_package(Gpgme)
#macro_log_feature(KDEPIMLIBS_FOUND "kdepimlibs" "KDE PIM libraries" "http://www.kde.org" FALSE "" "Needed for building several Plasma DataEngines")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${KDE4_KDECORE_INCLUDES}
${KDE4_KDEUI_INCLUDES}
${CMAKE_SOURCE_DIR}/experimental/libkdeclarative
${CMAKE_BINARY_DIR}/experimental/libkdeclarative
${karchive_SOURCE_DIR}/src
${karchive_BINARY_DIR}/src
${CMAKE_SOURCE_DIR}/tier2/kauth/src/
${CMAKE_BINARY_DIR}/tier2/kauth/src/
${CMAKE_SOURCE_DIR}/tier1/threadweaver/src
${CMAKE_BINARY_DIR}/tier1/threadweaver/src
${CMAKE_BINARY_DIR}/tier1/threadweaver/src/Weaver
${CMAKE_SOURCE_DIR}/tier1/kwindowsystem/
${CMAKE_BINARY_DIR}/tier1/kwindowsystem/
${CMAKE_SOURCE_DIR}/tier1/solid/src
${CMAKE_BINARY_DIR}/tier1/solid/src
${CMAKE_SOURCE_DIR}/plasma/remote
${CMAKE_SOURCE_DIR}/plasma/private/qtjolie-branch/qtjolie
${CMAKE_SOURCE_DIR}/plasma/private/qtjolie-branch
${CMAKE_SOURCE_DIR}/plasma/private/qtjolie-branch/includes
${CMAKE_SOURCE_DIR}/tier1/kcoreaddons/src/caching
${ki18n_SOURCE_DIR}/src
${ki18n_BINARY_DIR}/src
)
if(NOT PLASMA_NO_KIO)
include_directories(${KDE4_KIO_INCLUDES})
set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${KDE4_KIO_LIBS})
endif(NOT PLASMA_NO_KIO)
if(NOT PLASMA_NO_KNEWSTUFF)
include_directories(${CMAKE_SOURCE_DIR}/knewstuff/)
include_directories(${CMAKE_BINARY_DIR}/knewstuff/)
set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} knewstuff3)
endif(NOT PLASMA_NO_KNEWSTUFF)
if(NOT PLASMA_NO_SOLID)
include_directories(${CMAKE_BINARY_DIR}/tier1/solid/)
include_directories(${CMAKE_SOURCE_DIR}/tier1/solid/)
set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${KDE4_SOLID_LIBS})
endif(NOT PLASMA_NO_SOLID)
if(NOT PLASMA_NO_PACKAGEKIT)
add_definitions(-DPLASMA_ENABLE_PACKAGEKIT_SUPPORT=1)
set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${QT_QTDBUS_LIBRARY})
endif(NOT PLASMA_NO_PACKAGEKIT)
if (NOT PLASMA_NO_KUTILS)
include_directories(${CMAKE_SOURCE_DIR}/kutils)
include_directories(${CMAKE_BINARY_DIR}/kutils)
set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${KDE4_KUTILS_LIBS})
endif(NOT PLASMA_NO_KUTILS)
if(QCA2_FOUND)
include_directories(${QCA2_INCLUDE_DIR})
set(ENABLE_REMOTE_WIDGETS TRUE)
endif(QCA2_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-plasma.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-plasma.h)
#FIXME: gpgme++ is in kdepimlibs, must move somewhere else!
include_directories(${KDEPIMLIBS_INCLUDE_DIRS} ${GPGME_INCLUDES})
add_subdirectory(tests)
add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1209)
########### next target ###############
set(plasma_LIB_SRCS
abstractrunner.cpp
${plasmagik_SRCS}
abstractdialogmanager.cpp
configloader.cpp
containmentactions.cpp
containmentactionspluginsconfig.cpp
datacontainer.cpp
dataengine.cpp
dataengineconsumer.cpp
package.cpp
packagestructure.cpp
paintutils.cpp
pluginloader.cpp
framesvg.cpp
plasma.cpp
pluginloader.cpp
private/associatedapplicationmanager.cpp
private/componentinstaller.cpp
private/datacontainer_p.cpp
private/dataenginemanager.cpp
private/dataengineservice.cpp
private/effects/halopainter.cpp
private/getsource.cpp
private/packages.cpp
private/packagejob.cpp
private/packagejobthread.cpp
private/plasmoidservice.cpp
private/remotedataengine.cpp
private/remoteservice.cpp
private/remoteservicejob.cpp
private/runnerjobs.cpp
private/serviceprovider.cpp
private/storage.cpp
private/storagethread.cpp
private/windowpreview.cpp
private/windowshadows.cpp
private/applet_p.cpp
private/containment_p.cpp
querymatch.cpp
remote/accessmanager.cpp
remote/accessappletjob.cpp
remote/authorizationinterface.cpp
remote/authorizationmanager.cpp
remote/authorizationrule.cpp
remote/clientpinrequest.cpp
remote/credentials.cpp
remote/denyallauthorization.cpp
remote/pinpairingauthorization.cpp
remote/pinpairingdialog.cpp
remote/serviceaccessjob.cpp
#remote/signing.cpp TODO: re-enable, needs gpgmepp though
remote/trustedonlyauthorization.cpp
runnercontext.cpp
runnermanager.cpp
runnersyntax.cpp
scripting/appletscript.cpp
scripting/dataenginescript.cpp
scripting/runnerscript.cpp
scripting/scriptengine.cpp
service.cpp
servicejob.cpp
svg.cpp
theme.cpp
version.cpp
#Temporary QtJolie branch
private/qtjolie-branch/qtjolie/abstractadaptor.cpp
private/qtjolie-branch/qtjolie/client.cpp
private/qtjolie-branch/qtjolie/clientthread.cpp
private/qtjolie-branch/qtjolie/value.cpp
private/qtjolie-branch/qtjolie/fault.cpp
private/qtjolie-branch/qtjolie/message.cpp
private/qtjolie-branch/qtjolie/metaservice.cpp
private/qtjolie-branch/qtjolie/pendingcall.cpp
private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp
private/qtjolie-branch/qtjolie/pendingreply.cpp
private/qtjolie-branch/qtjolie/server.cpp
private/qtjolie-branch/qtjolie/serverthread.cpp
applet.cpp
containment.cpp
corona.cpp
)
if (QT5_BUILD)
set(plasma_LIB_SRCS ${plasma_LIB_SRCS} private/effectwatcher.cpp)
endif()
kconfig_add_kcfg_files(plasma_LIB_SRCS data/kconfigxt/libplasma-theme-global.kcfgc)
kde4_add_ui_files(plasma_LIB_SRCS
remote/pinpairing.ui
private/publish.ui)
#NEPOMUK_GENERATE_FROM_ONTOLOGY(
# nwc.nrl
# ${metadata_test_BINARY_DIR}
# TEST_HEADERS
# TEST_SOURCES
# TEST_INCLUDES
#)
kde4_add_library(plasma ${LIBRARY_TYPE} ${plasma_LIB_SRCS})
target_link_libraries(plasma ${QT_QTUITOOLS_LIBRARY}
${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTSQL_LIBRARY}
${KDE4_KDEUI_LIBS} kdnssd threadweaver kauth kwindowsystem ${PLASMA_EXTRA_LIBS} kcoreaddons ki18n)
#FIXME gpgme++ is in kdepimlibs, neeeds to be elsewhere
target_link_libraries(plasma ${KDEPIMLIBS_GPGMEPP_LIBS} kdeclarative karchive)
if(QCA2_FOUND)
target_link_libraries(plasma ${QCA2_LIBRARIES})
endif(QCA2_FOUND)
if(X11_FOUND)
target_link_libraries(plasma ${X11_LIBRARIES})
endif(X11_FOUND)
if(DL_LIBRARY)
target_link_libraries(plasma ${DL_LIBRARY})
endif(DL_LIBRARY)
target_link_libraries(plasma LINK_INTERFACE_LIBRARIES kdeui kdecore kwindowsystem Qt5::Widgets)
#do NOT use GENERIC versioning -- the plasma team will take care of versioning
set_target_properties(plasma PROPERTIES
VERSION 4.0.0
SOVERSION 4
)
install(TARGETS plasma EXPORT kdelibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS})
########### install files ###############
generate_export_header(plasma)
set(plasma_LIB_INCLUDES
abstractdialogmanager.h
abstractrunner.h
applet.h
configloader.h
containment.h
containmentactions.h
containmentactionspluginsconfig.h
corona.h
datacontainer.h
dataengine.h
pluginloader.h
paintutils.h
framesvg.h
package.h
packagestructure.h
plasma.h
${CMAKE_CURRENT_BINARY_DIR}/plasma_export.h
querymatch.h
remote/accessappletjob.h
remote/accessmanager.h
remote/authorizationmanager.h
remote/authorizationrule.h
remote/authorizationinterface.h
remote/clientpinrequest.h
remote/credentials.h
remote/serviceaccessjob.h
runnercontext.h
runnermanager.h
runnersyntax.h
service.h
servicejob.h
svg.h
theme.h
version.h)
install(FILES
${plasma_LIB_INCLUDES}
DESTINATION ${INCLUDE_INSTALL_DIR}/plasma COMPONENT Devel)
install(FILES
scripting/appletscript.h
scripting/dataenginescript.h
scripting/runnerscript.h
scripting/scriptengine.h
DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/scripting COMPONENT Devel)
install(FILES
data/servicetypes/plasma-applet.desktop
data/servicetypes/plasma-containment.desktop
data/servicetypes/plasma-containmentactions.desktop
data/servicetypes/plasma-dataengine.desktop
data/servicetypes/plasma-packagestructure.desktop
data/servicetypes/plasma-runner.desktop
data/servicetypes/plasma-scriptengine.desktop
data/servicetypes/plasma-service.desktop
DESTINATION ${SERVICETYPES_INSTALL_DIR})
install(FILES
data/services/plasma.protocol
DESTINATION ${SERVICES_INSTALL_DIR})
install(FILES data/knewstuff/plasmoids.knsrc DESTINATION ${CONFIG_INSTALL_DIR})
install(FILES data/operations/dataengineservice.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services)
install(FILES data/operations/plasmoidservice.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services)
install(FILES data/operations/storage.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services)

100
plasma/Mainpage.dox Normal file
View File

@ -0,0 +1,100 @@
/** @mainpage Plasma libraries
libplasma is the core of the Plasma desktop. It provides a framework of graphical
widgets (Plasma::Applet) that can be organised into managed groupings
(Plasma::Containment), such as a desktop or panel. It also provides a data
abstraction layer (Plasma::DataEngine) and a corresponding service interaction
layer (Plasma::Service) to make implementing widgets easier and a
system of callouts (Plasma::AbstractRunner) that provide responses to queries,
from running an application to performing a quick calculation.
The <a href="http://doc.trolltech.com/latest/graphicsview.html">Qt Graphics View
framework</a> and the <a href="http://api.kde.org/4.x-api/kdelibs-apidocs/">KDE
libraries</a> provide the underpinning for libplasma. As a result, it should
work anywhere that Qt and KDE do.
Although libplasma is developed for the use of the Plasma desktop shell in
KDE 4, it is general enough to be useful in other applications.
<a href="http://amarok.kde.org">Amarok</a> is using it for its context
view, allowing for pluggable widgets to display and interact with the music
collection, such as "current track" and "tag cloud" widgets.
libplasma itself only provides a framework, and the widgets, containments,
data engines and runners are all implemented as plugins. However, the framework
is designed to make implementing these plugins as easy as possible, including
providing scripting support.
Other important classes are:
- Plasma::Corona: the canvas that containments are placed on
- Plasma::View: a QWidget for displaying a containment
- Plasma::Theme: provides theming support
- Plasma::Animator: provides animations for things like elements appearing
and disappearing
- Plasma::Delegate: provides an item delegate for Qt's
<a href="http://doc.trolltech.com/latest/model-view-programming.html">Model /
View framework</a> for menu items.
- Plasma::ToolTipManager: allows widgets have (themed) tooltips displayed when the
mouse is hovered over them
- Plasma::Dialog: displays a themed application dialog
- Plasma::Extender: provides detachable sections to Plasma::Applet
- Plasma::GLApplet: provides an OpenGL-rendered Plasma::Applet
- Plasma::Package: provides descriptions of packages containing plugins
for libplasma
- Plasma::PopupApplet: provides a simple way of implementing a Plasma::Applet
consisting of an icon that shows a popup when clicked
- Plasma::Svg and Plasma::FrameSvg: provides themable, cached SVGs
- Plasma::Wallpaper: provides pluggable backgrounds for containments
- Plasma::AppletScript, Plasma::DataEngineScript, Plasma::RunnerScript and
Plasma::ScriptEngine: provide scripting interfaces for plugins
- Various themed QGraphicsWidgets for use in creating a Plasma::Applet
The
<a href="http://techbase.kde.org/Development/Tutorials/Plasma">Plasma tutorials</a>
on TechBase provide a good introduction to writing plugins, such as widgets and
data engines, for libplasma-based applications.
@authors
Aaron Seigo \<aseigo@kde.org\><br>
Alessandro Diaferia \<alediaferia@gmail.com\><br>
Alex Merry \<kde@randomguy3.me.uk\><br>
Alexander Wiedenbruch \<wirr01@gmail.com\><br>
Alexis Ménard \<darktears31@gmail.com\><br>
André Duffeck \<andre@duffeck.de\><br>
Andrew Lake \<jamboarder@yahoo.com\><br>
Artur de Souza \<asouza@kde.org\><br>
Bertjan Broeksema \<b.broeksema@kdemail.net\><br>
Chani Armitage \<chanika@gmail.com\><br>
Davide Bettio \<davide.bettio@kdemail.net\><br>
Dan Meltzer \<hydrogen@notyetimplemented.com\><br>
Fredrik Höglund \<fredrik@kde.org\><br>
Ivan Cukic \<ivan.cukic+kde@gmail.com\><br>
John Tapsell \<tapsell@kde.org\><br>
Jordi Polo \<mumismo@gmail.com\><br>
Kevin Ottens \<ervin@kde.org\><br>
Montel Laurent \<montel@kde.org\><br>
Marco Martin \<notmart@gmail.com\><br>
Matt Broadstone \<mbroadst@gmail.com\><br>
Petri Damsten \<damu@iki.fi\><br>
Rafael Fernández López \<ereslibre@kde.org\><br>
Riccardo Iaconelli \<riccardo@kde.org\><br>
Richard J. Moore \<rich@kde.org\><br>
Rob Scheepmaker \<r.scheepmaker@student.utwente.nl\><br>
Robert Knight \<robertknight@gmail.com\><br>
Sebastian Kuegler \<sebas@kde.org\><br>
Siraj Razick \<siraj@kde.net\><br>
Zack Rusin \<zack@kde.org\>
@maintainers
Aaron Seigo \<aseigo@kde.org\>
@licenses
@lgpl
*/
// DOXYGEN_SET_PROJECT_NAME = Plasma
// DOXYGEN_SET_RECURSIVE = YES
// DOXYGEN_EXCLUDE_PATTERNS = *_p.h */private/* */tests/*
// vim:ts=4:sw=4:expandtab:filetype=doxygen

4
plasma/Messages.sh Normal file
View File

@ -0,0 +1,4 @@
#! /usr/bin/env bash
$EXTRACTRC private/*.ui >> rc.cpp
$XGETTEXT `ls *.cpp *.h */*.h */*.cpp | grep -v 'tests/'` -o $podir/libplasma.pot
rm -f *.ui

29
plasma/README Normal file
View File

@ -0,0 +1,29 @@
libplasma
This directory contains the classes making up libplasma, which provides the
core framework used by Plasma applications, such as the Plasma desktop shell
and its components. This includes applet and extension definitions and loading,
common GUI elements, data and service interaction, search system, etc.
Domain specific sets of functionality, e.g. for network awareness or sensors,
are not found here but as DataEngine, Service, Applet, Package, Wallpaper,
ContainmentActions, Containment and other plugins.
Commit Guidelines:
* If your patch is not an obvious or trivial bug fix, have it peer reviewed
by another Plasma developer; http://reviewboard.kde.org is your friend :)
* All code MUST follow the kdelibs coding style, as found at:
http://techbase.kde.org/Policies/Kdelibs_Coding_Style
* All new public API MUST have apidox written before committing and must go
through an API review with another Plasma developer. We have to maintain
binary compatibility, remember!
Unit tests are next to godliness. (Though as you can see, right now libplasma
is hellbound.)
Please refer to the Plasma website (http://plasma.kde.org) and Plasma wiki
(http://techbase.kde.org/Projects/Plasma) for API documentation and design
documents regarding this library.

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2010 Marco Martin <notmart@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "abstractdialogmanager.h"
#include "corona.h"
namespace Plasma
{
class AbstractDialogManagerPrivate
{
public:
AbstractDialogManagerPrivate()
{
}
};
AbstractDialogManager::AbstractDialogManager(Corona *parent)
: QObject(parent),
d(new AbstractDialogManagerPrivate)
{
}
AbstractDialogManager::~AbstractDialogManager()
{
delete d;
}
void AbstractDialogManager::showDialog(QWidget *widget, Plasma::Applet *applet)
{
Q_UNUSED(applet)
widget->show();
}
}
#include "moc_abstractdialogmanager.cpp"

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2010 Marco Martin <notmart@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DIALOGMANAGER_H
#define PLASMA_DIALOGMANAGER_H
#include <QtCore/QObject>
#include <plasma/plasma_export.h>
namespace Plasma
{
class Applet;
class Corona;
class AbstractDialogManagerPrivate;
/**
* @class AbstractDialogManager plasma/dialogmanager.h <Plasma/AbstractDialogManager>
*
* @short The AbstractDialogManager class shows the dialogs shown by applets and the rest of the shell.
* a AbstractDialogManager can manage aspects like positioning, sizing and widget style
* of dialogs sich as the applet configuration dialog.
* @since 4.5
*/
class PLASMA_EXPORT AbstractDialogManager : public QObject
{
Q_OBJECT
public:
explicit AbstractDialogManager(Plasma::Corona *parent=0);
~AbstractDialogManager();
public Q_SLOTS:
/**
* This fake virtual slot shows a dialog belonging to an applet.
* There is no guarantee how the implementation will show it
* @param widget the dialog widget
* @param applet the applet that owns the dialog
*/
void showDialog(QWidget *widget, Plasma::Applet *applet);
private:
AbstractDialogManagerPrivate * const d;
};
}
#endif

460
plasma/abstractrunner.cpp Normal file
View File

@ -0,0 +1,460 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "abstractrunner.h"
#include <QAction>
#include <QHash>
#include <QMenu>
#include <QMimeData>
#include <QMutex>
#include <QMutexLocker>
#include <QTimer>
#include <kdebug.h>
#include <kplugininfo.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#include <klocalizedstring.h>
#include <kiconloader.h>
#include <kglobal.h>
#include <qstandardpaths.h>
#include "package.h"
#include "pluginloader.h"
#include "private/abstractrunner_p.h"
#include "querymatch.h"
#include "runnercontext.h"
#include "scripting/runnerscript.h"
namespace Plasma
{
AbstractRunner::AbstractRunner(QObject *parent, const QString &path)
: QObject(parent),
d(new AbstractRunnerPrivate(this))
{
d->init(path);
}
AbstractRunner::AbstractRunner(const KService::Ptr service, QObject *parent)
: QObject(parent),
d(new AbstractRunnerPrivate(this))
{
d->init(service);
}
AbstractRunner::AbstractRunner(QObject *parent, const QVariantList &args)
: QObject(parent),
d(new AbstractRunnerPrivate(this))
{
if (args.count() > 0) {
KService::Ptr service = KService::serviceByStorageId(args[0].toString());
if (service) {
d->init(service);
}
}
}
AbstractRunner::~AbstractRunner()
{
delete d;
}
KConfigGroup AbstractRunner::config() const
{
QString group = id();
if (group.isEmpty()) {
group = "UnnamedRunner";
}
KConfigGroup runners(KSharedConfig::openConfig(), "Runners");
return KConfigGroup(&runners, group);
}
void AbstractRunner::reloadConfiguration()
{
if (d->script) {
emit d->script->reloadConfiguration();
}
}
void AbstractRunner::addSyntax(const RunnerSyntax &syntax)
{
d->syntaxes.append(syntax);
}
void AbstractRunner::setDefaultSyntax(const RunnerSyntax &syntax)
{
d->syntaxes.append(syntax);
d->defaultSyntax = &(d->syntaxes.last());
}
void AbstractRunner::setSyntaxes(const QList<RunnerSyntax> &syntaxes)
{
d->syntaxes = syntaxes;
}
QList<RunnerSyntax> AbstractRunner::syntaxes() const
{
return d->syntaxes;
}
RunnerSyntax *AbstractRunner::defaultSyntax() const
{
return d->defaultSyntax;
}
void AbstractRunner::performMatch(Plasma::RunnerContext &localContext)
{
static const int reasonableRunTime = 1500;
static const int fastEnoughTime = 250;
if (d->suspendMatching) {
return;
}
QTime time;
time.restart();
//The local copy is already obtained in the job
match(localContext);
// automatically rate limit runners that become slooow
const int runtime = time.elapsed();
bool slowed = speed() == SlowSpeed;
if (!slowed && runtime > reasonableRunTime) {
// we punish runners that return too slowly, even if they don't bring
// back matches
#ifndef NDEBUG
kDebug() << id() << "runner is too slow, putting it on the back burner.";
#endif
d->fastRuns = 0;
setSpeed(SlowSpeed);
}
if (slowed && runtime < fastEnoughTime && localContext.query().size() > 2) {
++d->fastRuns;
if (d->fastRuns > 2) {
// we reward slowed runners who bring back matches fast enough
// 3 times in a row
#ifndef NDEBUG
kDebug() << id() << "runner is faster than we thought, kicking it up a notch";
#endif
setSpeed(NormalSpeed);
}
}
}
QList<QAction*> AbstractRunner::actionsForMatch(const Plasma::QueryMatch &match)
{
Q_UNUSED(match)
QList<QAction*> ret;
if (d->script) {
emit d->script->actionsForMatch(match, &ret);
}
return ret;
}
QAction* AbstractRunner::addAction(const QString &id, const QIcon &icon, const QString &text)
{
QAction *a = new QAction(icon, text, this);
d->actions.insert(id, a);
return a;
}
void AbstractRunner::addAction(const QString &id, QAction *action)
{
d->actions.insert(id, action);
}
void AbstractRunner::removeAction(const QString &id)
{
QAction *a = d->actions.take(id);
delete a;
}
QAction* AbstractRunner::action(const QString &id) const
{
return d->actions.value(id);
}
QHash<QString, QAction*> AbstractRunner::actions() const
{
return d->actions;
}
void AbstractRunner::clearActions()
{
qDeleteAll(d->actions);
d->actions.clear();
}
QMimeData *AbstractRunner::mimeDataForMatch(const QueryMatch &match)
{
Q_UNUSED(match)
return 0;
}
bool AbstractRunner::hasRunOptions()
{
return d->hasRunOptions;
}
void AbstractRunner::setHasRunOptions(bool hasRunOptions)
{
d->hasRunOptions = hasRunOptions;
}
void AbstractRunner::createRunOptions(QWidget *parent)
{
if (d->script) {
emit d->script->createRunOptions(parent);
}
}
AbstractRunner::Speed AbstractRunner::speed() const
{
// the only time the read lock will fail is if we were slow are going to speed up
// or if we were fast and are going to slow down; so don't wait in this case, just
// say we're slow. we either will be soon or were just a moment ago and it doesn't
// hurt to do one more run the slow way
if (!d->speedLock.tryLockForRead()) {
return SlowSpeed;
}
Speed s = d->speed;
d->speedLock.unlock();
return s;
}
void AbstractRunner::setSpeed(Speed speed)
{
d->speedLock.lockForWrite();
d->speed = speed;
d->speedLock.unlock();
}
AbstractRunner::Priority AbstractRunner::priority() const
{
return d->priority;
}
void AbstractRunner::setPriority(Priority priority)
{
d->priority = priority;
}
RunnerContext::Types AbstractRunner::ignoredTypes() const
{
return d->blackListed;
}
void AbstractRunner::setIgnoredTypes(RunnerContext::Types types)
{
d->blackListed = types;
}
void AbstractRunner::run(const Plasma::RunnerContext &search, const Plasma::QueryMatch &action)
{
if (d->script) {
return d->script->run(search, action);
}
}
void AbstractRunner::match(Plasma::RunnerContext &search)
{
if (d->script) {
return d->script->match(search);
}
}
QString AbstractRunner::name() const
{
if (d->runnerDescription.isValid()) {
return d->runnerDescription.name();
}
return objectName();
}
QIcon AbstractRunner::icon() const
{
if (d->runnerDescription.isValid()) {
return KDE::icon(d->runnerDescription.icon());
}
return QIcon();
}
QString AbstractRunner::id() const
{
if (d->runnerDescription.isValid()) {
return d->runnerDescription.pluginName();
}
return objectName();
}
QString AbstractRunner::description() const
{
if (d->runnerDescription.isValid()) {
return d->runnerDescription.property("Comment").toString();
}
return objectName();
}
Package AbstractRunner::package() const
{
return d->package ? *d->package : Package();
}
void AbstractRunner::init()
{
if (d->script) {
d->setupScriptSupport();
d->script->init();
}
reloadConfiguration();
}
DataEngine *AbstractRunner::dataEngine(const QString &name) const
{
return d->dataEngine(name);
}
bool AbstractRunner::isMatchingSuspended() const
{
return d->suspendMatching;
}
void AbstractRunner::suspendMatching(bool suspend)
{
if (d->suspendMatching == suspend) {
return;
}
d->suspendMatching = suspend;
emit matchingSuspended(suspend);
}
AbstractRunnerPrivate::AbstractRunnerPrivate(AbstractRunner *r)
: priority(AbstractRunner::NormalPriority),
speed(AbstractRunner::NormalSpeed),
blackListed(0),
script(0),
runner(r),
fastRuns(0),
package(0),
defaultSyntax(0),
hasRunOptions(false),
suspendMatching(false)
{
}
AbstractRunnerPrivate::~AbstractRunnerPrivate()
{
delete script;
script = 0;
delete package;
package = 0;
}
void AbstractRunnerPrivate::init(const KService::Ptr service)
{
runnerDescription = KPluginInfo(service);
if (runnerDescription.isValid()) {
const QString api = runnerDescription.property("X-Plasma-API").toString();
if (!api.isEmpty()) {
const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "plasma/runners/" + runnerDescription.pluginName() + '/');
prepScripting(path, api);
if (!script) {
#ifndef NDEBUG
kDebug() << "Could not create a(n)" << api << "ScriptEngine for the" << runnerDescription.name() << "Runner.";
#endif
}
}
}
}
void AbstractRunnerPrivate::init(const QString &path)
{
runnerDescription = KPluginInfo(path + "/metadata.desktop");
const QString api = runnerDescription.property("X-Plasma-API").toString();
prepScripting(path, api);
}
void AbstractRunnerPrivate::prepScripting(const QString &path, const QString &api)
{
if (script) {
return;
}
delete package;
package = 0;
if (api.isEmpty()) {
return;
}
package = new Package(PluginLoader::self()->loadPackage("Plasma/Runner", api));
package->setPath(path);
if (!package->isValid()) {
#ifndef NDEBUG
kDebug() << "Invalid Runner package at" << path;
#endif
return;
}
script = Plasma::loadScriptEngine(api, runner);
if (!script) {
delete package;
package = 0;
}
}
// put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engine
void AbstractRunnerPrivate::setupScriptSupport()
{
if (!package) {
return;
}
#ifndef NDEBUG
kDebug() << "setting up script support, package is in" << package->path()
<< ", main script is" << package->filePath("mainscript");
#endif
const QString translationsPath = package->filePath("translations");
if (!translationsPath.isEmpty()) {
KGlobal::dirs()->addResourceDir("locale", translationsPath);
KLocalizedString::insertCatalog(runnerDescription.pluginName());
}
}
} // Plasma namespace
#include "moc_abstractrunner.cpp"

474
plasma/abstractrunner.h Normal file
View File

@ -0,0 +1,474 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_ABSTRACTRUNNER_H
#define PLASMA_ABSTRACTRUNNER_H
#include <QtCore/QObject>
#include <QtCore/QMutex>
#include <QtCore/QStringList>
#include <QIcon>
#include <kconfiggroup.h>
#include <kservice.h>
#include <plasma/plasma_export.h>
#include <plasma/querymatch.h>
#include <plasma/runnercontext.h>
#include <plasma/runnersyntax.h>
#include <plasma/version.h>
class QAction;
class QMimeData;
class KCompletion;
namespace Plasma
{
class DataEngine;
class Package;
class RunnerScript;
class QueryMatch;
class AbstractRunnerPrivate;
/**
* @class AbstractRunner plasma/abstractrunner.h <Plasma/AbstractRunner>
*
* @short An abstract base class for Plasma Runner plugins.
*
* Be aware that runners have to be thread-safe. This is due to the fact that
* each runner is executed in its own thread for each new term. Thus, a runner
* may be executed more than once at the same time. See match() for details.
* To let krunner expose a global shortcut for the single runner query mode, the runner
* must set the "X-Plasma-AdvertiseSingleRunnerMode" key to true in the .desktop file
* and set a default syntax. See setDefaultSyntax() for details.
*
*/
class PLASMA_EXPORT AbstractRunner : public QObject
{
Q_OBJECT
Q_PROPERTY(bool matchingSuspended READ isMatchingSuspended WRITE suspendMatching NOTIFY matchingSuspended)
Q_PROPERTY(QString id READ id)
Q_PROPERTY(QString description READ description)
Q_PROPERTY(QString name READ name)
Q_PROPERTY(QIcon icon READ icon)
public:
/** Specifies a nominal speed for the runner */
enum Speed {
SlowSpeed,
NormalSpeed
};
/** Specifies a priority for the runner */
enum Priority {
LowestPriority = 0,
LowPriority,
NormalPriority,
HighPriority,
HighestPriority
};
/** An ordered list of runners */
typedef QList<AbstractRunner*> List;
virtual ~AbstractRunner();
/**
* This is the main query method. It should trigger creation of
* QueryMatch instances through RunnerContext::addMatch and
* RunnerContext::addMatches. It is called internally by performMatch().
*
* If the runner can run precisely the requested term (RunnerContext::query()),
* it should create an exact match by setting the type to RunnerContext::ExactMatch.
* The first runner that creates a QueryMatch will be the
* default runner. Other runner's matches will be suggested in the
* interface. Non-exact matches should be offered via RunnerContext::PossibleMatch.
*
* The match will be activated via run() if the user selects it.
*
* Each runner is executed in its own thread. Whenever the user input changes this
* method is called again. Thus, it needs to be thread-safe. Also, all matches need
* to be reported once this method returns. Asynchronous runners therefore need
* to make use of a local event loop to wait for all matches.
*
* It is recommended to use local status data in async runners. The simplest way is
* to have a separate class doing all the work like so:
*
* \code
* void MyFancyAsyncRunner::match( RunnerContext& context )
* {
* QEventLoop loop;
* MyAsyncWorker worker( context );
* connect( &worker, SIGNAL(finished()),
* &loop, SLOT(quit()) );
* worker.work();
* loop.exec();
* }
* \endcode
*
* Here MyAsyncWorker creates all the matches and calls RunnerContext::addMatch
* in some internal slot. It emits the finished() signal once done which will
* quit the loop and make the match() method return. The local status is kept
* entirely in MyAsyncWorker which makes match() trivially thread-safe.
*
* If a particular match supports multiple actions, set up the corresponding
* actions in the actionsForMatch method. Do not call any of the action methods
* within this method!
*
* Execution of the correct action should be handled in the run method.
* @caution This method needs to be thread-safe since KRunner will simply
* start a new thread for each new term.
*
* @warning Returning from this method means to end execution of the runner.
*
* @sa run(), RunnerContext::addMatch, RunnerContext::addMatches, QueryMatch
*/
virtual void match(Plasma::RunnerContext &context);
/**
* Triggers a call to match. This will call match() internally.
*
* @param context the search context used in executing this match.
*/
void performMatch(Plasma::RunnerContext &context);
/**
* If the runner has options that the user can interact with to modify
* what happens when run or one of the actions created in match
* is called, the runner should return true
*/
bool hasRunOptions();
/**
* If hasRunOptions() returns true, this method may be called to get
* a widget displaying the options the user can interact with to modify
* the behaviour of what happens when a given match is selected.
*
* @param widget the parent of the options widgets.
*/
virtual void createRunOptions(QWidget *widget);
/**
* Called whenever an exact or possible match associated with this
* runner is triggered.
*
* @param context The context in which the match is triggered, i.e. for which
* the match was created.
* @param match The actual match to run/execute.
*/
virtual void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match);
/**
* The nominal speed of the runner.
* @see setSpeed
*/
Speed speed() const;
/**
* The priority of the runner.
* @see setPriority
*/
Priority priority() const;
/**
* Returns the OR'ed value of all the Information types (as defined in RunnerContext::Type)
* this runner is not interested in.
* @return OR'ed value of black listed types
*/
RunnerContext::Types ignoredTypes() const;
/**
* Sets the types this runner will ignore
* @param types OR'ed listed of ignored types
*/
void setIgnoredTypes(RunnerContext::Types types);
/**
* @return the user visible engine name for the Runner
*/
QString name() const;
/**
* @return an id string for the Runner
*/
QString id() const;
/**
* @return the description of this Runner
*/
QString description() const;
/**
* @return the icon for this Runner
*/
QIcon icon() const;
/**
* Accessor for the associated Package object if any.
*
* Note that the returned pointer is only valid for the lifetime of
* the runner.
*
* @return the Package object, which may be invalid
**/
Package package() const;
/**
* Signal runner to reload its configuration.
*/
virtual void reloadConfiguration();
/**
* @return the syntaxes the runner has registered that it accepts and understands
* @since 4.3
*/
QList<RunnerSyntax> syntaxes() const;
/**
* @return the default syntax for the runner or 0 if no default syntax has been defined
*
* @since 4.4
*/
RunnerSyntax *defaultSyntax() const;
/**
* @return true if the runner is currently busy with non-interuptable work, signaling that
* new threads should not be created for it at this time
* @since 4.6
*/
bool isMatchingSuspended() const;
Q_SIGNALS:
/**
* This signal is emitted when matching is about to commence, giving runners
* an opportunity to prepare themselves, e.g. loading data sets or preparing
* IPC or network connections. This method should be fast so as not to cause
* slow downs. Things that take longer or which should be loaded once and
* remain extant for the lifespan of the AbstractRunner should be done in init().
* @see init()
* @since 4.4
*/
void prepare();
/**
* This signal is emitted when a session of matches is complete, giving runners
* the opportunity to tear down anything set up as a result of the prepare()
* method.
* @since 4.4
*/
void teardown();
/**
* Emitted when the runner enters or exits match suspension
* @see matchingSuspended
* @since 4.6
*/
void matchingSuspended(bool suspended);
protected:
friend class RunnerManager;
friend class RunnerManagerPrivate;
explicit AbstractRunner(QObject *parent = 0, const QString &path = QString());
explicit AbstractRunner(const KService::Ptr service, QObject *parent = 0);
AbstractRunner(QObject *parent, const QVariantList &args);
/**
* Sets whether or not the runner is available for match requests. Useful to
* prevent more thread spawning when the thread is in a busy state.
*/
void suspendMatching(bool suspend);
/**
* Provides access to the runner's configuration object.
*/
KConfigGroup config() const;
/**
* Sets whether or not the runner has options for matches
*/
void setHasRunOptions(bool hasRunOptions);
/**
* Sets the nominal speed of the runner. Only slow runners need
* to call this within their constructor because the default
* speed is NormalSpeed. Runners that use DBUS should call
* this within their constructors.
*/
void setSpeed(Speed newSpeed);
/**
* Sets the priority of the runner. Lower priority runners are executed
* only after higher priority runners.
*/
void setPriority(Priority newPriority);
/**
* A given match can have more than action that can be performed on it.
* For example, a song match returned by a music player runner can be queued,
* added to the playlist, or played.
*
* Call this method to add actions that can be performed by the runner.
* Actions must first be added to the runner's action registry.
* Note: execution of correct action is left up to the runner.
*/
virtual QList<QAction*> actionsForMatch(const Plasma::QueryMatch &match);
/**
* Creates and then adds an action to the action registry.
* AbstractRunner assumes ownership of the created action.
*
* @param id A unique identifier string
* @param icon The icon to display
* @param text The text to display
* @return the created QAction
*/
QAction* addAction(const QString &id, const QIcon &icon, const QString &text);
/**
* Adds an action to the runner's action registry.
*
* The QAction must be created within the GUI thread;
* do not create it within the match method of AbstractRunner.
*
* @param id A unique identifier string
* @param action The QAction to be stored
*/
void addAction(const QString &id, QAction *action);
/**
* Removes the action from the action registry.
* AbstractRunner deletes the action once removed.
*
* @param id The id of the action to be removed
*/
void removeAction(const QString &id);
/**
* Returns the action associated with the id
*/
QAction* action(const QString &id) const;
/**
* Returns all registered actions
*/
QHash<QString, QAction*> actions() const;
/**
* Clears the action registry.
* The action pool deletes the actions.
*/
void clearActions();
/**
* Adds a registered syntax that this runner understands. This is used to
* display to the user what this runner can understand and how it can be
* used.
*
* @param syntax the syntax to register
* @since 4.3
*/
void addSyntax(const RunnerSyntax &syntax);
/**
* Set @p syntax as the default syntax for the runner; the default syntax will be
* substituted to the empty query in single runner mode. This is also used to
* display to the user what this runner can understand and how it can be
* used.
* The default syntax is automatically added to the list of registered syntaxes, there
* is no need to add it using addSyntax.
* Note that there can be only one default syntax; if called more than once, the last
* call will determine the default syntax.
* A default syntax (even trivial) is required to advertise single runner mode
*
* @param syntax the syntax to register and to set as default
* @since 4.4
**/
void setDefaultSyntax(const RunnerSyntax &syntax);
/**
* Sets the list of syntaxes; passing in an empty list effectively clears
* the syntaxes.
*
* @param the syntaxes to register for this runner
* @since 4.3
*/
void setSyntaxes(const QList<RunnerSyntax> &syns);
/**
* Loads the given DataEngine
*
* Tries to load the data engine given by @p name. Each engine is
* only loaded once, and that instance is re-used on all subsequent
* requests.
*
* If the data engine was not found, an invalid data engine is returned
* (see DataEngine::isValid()).
*
* Note that you should <em>not</em> delete the returned engine.
*
* @param name Name of the data engine to load
* @return pointer to the data engine if it was loaded,
* or an invalid data engine if the requested engine
* could not be loaded
*
* @since 4.4
*/
Q_INVOKABLE DataEngine *dataEngine(const QString &name) const;
/**
* Reimplement this slot to run any initialization routines on first load.
* By default, it calls reloadConfiguration(); for scripted Runners this
* method also sets up the ScriptEngine.
*/
virtual void init();
/**
* Reimplement this slot if you want your runner
* to support serialization and drag and drop
* @since 4.5
*/
virtual QMimeData *mimeDataForMatch(const Plasma::QueryMatch &match);
private:
friend class RunnerScript;
AbstractRunnerPrivate *const d;
};
} // Plasma namespace
#define K_EXPORT_PLASMA_RUNNER( libname, classname ) \
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN(factory("plasma_runner_" #libname)) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
/**
* These plugins are Used by the plugin selector dialog to show
* configuration options specific to this runner. These options
* must be runner global and not pertain to a specific match.
*/
#define K_EXPORT_RUNNER_CONFIG( name, classname ) \
K_PLUGIN_FACTORY(ConfigFactory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN(ConfigFactory("kcm_krunner_" #name)) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
#endif

1268
plasma/applet.cpp Normal file

File diff suppressed because it is too large Load Diff

900
plasma/applet.h Normal file
View File

@ -0,0 +1,900 @@
/*
* Copyright 2006-2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_APPLET_H
#define PLASMA_APPLET_H
#include <QObject>
#include <QIcon>
#include <kconfiggroup.h>
#include <kplugininfo.h>
#include <kshortcut.h>
#include <kurl.h>
#include <plasma/configloader.h>
#include <plasma/plasma.h>
#include <plasma/version.h>
#include <plasma/framesvg.h>
class QWidget;
class KConfigDialog;
class KActionCollection;
namespace Plasma
{
class AppletPrivate;
class Containment;
class DataEngine;
class Package;
/**
* @class Applet plasma/applet.h <Plasma/Applet>
*
* @short The base Applet class
*
* Applet provides several important roles for add-ons widgets in Plasma.
*
* First, it is the base class for the plugin system and therefore is the
* interface to applets for host applications. It also handles the life time
* management of data engines (e.g. all data engines accessed via
* Applet::dataEngine(const QString&) are properly deref'd on Applet
* destruction), background painting (allowing for consistent and complex
* look and feel in just one line of code for applets), loading and starting
* of scripting support for each applet, providing access to the associated
* plasmoid package (if any) and access to configuration data.
*
* See techbase.kde.org for tutorials on writing Applets using this class.
*/
class PLASMA_EXPORT Applet : public QObject
{
Q_OBJECT
Q_PROPERTY(bool hasConfigurationInterface READ hasConfigurationInterface)
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QString pluginName READ pluginName)
Q_PROPERTY(QString category READ category)
Q_PROPERTY(ImmutabilityType immutability READ immutability WRITE setImmutability)
Q_PROPERTY(bool hasFailedToLaunch READ hasFailedToLaunch WRITE setFailedToLaunch)
Q_PROPERTY(bool busy READ isBusy WRITE setBusy)
Q_PROPERTY(bool configurationRequired READ configurationRequired WRITE setConfigurationRequired)
Q_PROPERTY(bool shouldConserveResources READ shouldConserveResources)
Q_PROPERTY(uint id READ id)
Q_PROPERTY(BackgroundHints backgroundHints READ backgroundHints WRITE setBackgroundHints)
Q_PROPERTY(bool userConfiguring READ isUserConfiguring)
public:
typedef QList<Applet*> List;
typedef QHash<QString, Applet*> Dict;
~Applet();
/**
* @return the id of this applet
*/
uint id() const;
/**
* Returns the KConfigGroup to access the applets configuration.
*
* This config object will write to an instance
* specific config file named \<appletname\>\<instanceid\>rc
* in the Plasma appdata directory.
**/
KConfigGroup config() const;
/**
* Saves state information about this applet that will
* be accessed when next instantiated in the restore(KConfigGroup&) method.
*
* This method does not need to be reimplmented by Applet
* subclasses, but can be useful for Applet specializations
* (such as Containment) to do so.
*
* Applet subclasses may instead want to reimplement saveState().
**/
virtual void save(KConfigGroup &group) const;
/**
* Restores state information about this applet saved previously
* in save(KConfigGroup&).
*
* This method does not need to be reimplmented by Applet
* subclasses, but can be useful for Applet specializations
* (such as Containment) to do so.
**/
virtual void restore(KConfigGroup &group);
/**
* Returns a KConfigGroup object to be shared by all applets of this
* type.
*
* This config object will write to an applet-specific config object
* named plasma_\<appletname\>rc in the local config directory.
*/
KConfigGroup globalConfig() const;
/**
* Returns the config skeleton object from this applet's package,
* if any.
*
* @return config skeleton object, or 0 if none
**/
ConfigLoader *configScheme() const;
/**
* Loads the given DataEngine
*
* Tries to load the data engine given by @p name. Each engine is
* only loaded once, and that instance is re-used on all subsequent
* requests.
*
* If the data engine was not found, an invalid data engine is returned
* (see DataEngine::isValid()).
*
* Note that you should <em>not</em> delete the returned engine.
*
* @param name Name of the data engine to load
* @return pointer to the data engine if it was loaded,
* or an invalid data engine if the requested engine
* could not be loaded
*/
Q_INVOKABLE DataEngine *dataEngine(const QString &name) const;
/**
* Accessor for the associated Package object if any.
* Generally, only Plasmoids come in a Package.
*
* @return the Package object, or 0 if none
**/
Package package() const;
/**
* Reccomended position for a popup window like a menu or a tooltip
* given its size
* @param s size of the popup
* @returns reccomended position
*/
QPoint popupPosition(const QSize &s) const;
/**
* @since 4.4
* Reccomended position for a popup window like a menu or a tooltip
* given its size
* @param s size of the popup
* @param alignment alignment of the popup, valid flags are Qt::AlignLeft, Qt::AlignRight and Qt::AlignCenter
* @returns reccomended position
*/
QPoint popupPosition(const QSize &s, Qt::AlignmentFlag alignment) const;
/**
* Called when any of the geometry constraints have been updated.
* This method calls constraintsEvent, which may be reimplemented,
* once the Applet has been prepared for updating the constraints.
*
* @param constraints the type of constraints that were updated
*/
void updateConstraints(Plasma::Constraints constraints = Plasma::AllConstraints);
/**
* Returns the current form factor the applet is being displayed in.
*
* @see Plasma::FormFactor
*/
virtual FormFactor formFactor() const;
/**
* Returns the location of the scene which is displaying applet.
*
* @see Plasma::Location
*/
virtual Location location() const;
/**
* @return the preferred aspect ratio mode for placement and resizing
*/
Plasma::AspectRatioMode aspectRatioMode() const;
/**
* Sets the preferred aspect ratio mode for placement and resizing
*/
void setAspectRatioMode(Plasma::AspectRatioMode);
/**
* Returns a list of all known applets.
* This may skip applets based on security settings and ExcludeCategories in the application's config.
*
* @param category Only applets matchin this category will be returned.
* Useful in conjunction with knownCategories.
* If "Misc" is passed in, then applets without a
* Categories= entry are also returned.
* If an empty string is passed in, all applets are
* returned.
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of applets
**/
static KPluginInfo::List listAppletInfo(const QString &category = QString(),
const QString &parentApp = QString());
/**
* Returns a list of all known applets associated with a certain mimetype.
*
* @return list of applets
**/
static KPluginInfo::List listAppletInfoForMimeType(const QString &mimetype);
/**
* Returns a list of all known applets associated with a certain URL.
*
* @since 4.4
* @return list of applets
**/
static KPluginInfo::List listAppletInfoForUrl(const QUrl &url);
/**
* Returns a list of all the categories used by installed applets.
*
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of categories
* @param visibleOnly true if it should only return applets that are marked as visible
*/
static QStringList listCategories(const QString &parentApp = QString(),
bool visibleOnly = true);
/**
* Sets the list of custom categories that are used in addition to the default
* set of categories known to libplasma for Applets.
* @param categories a list of categories
* @since 4.3
*/
void setCustomCategories(const QStringList &categories);
/**
* @return the list of custom categories known to libplasma
* @since 4.3
*/
QStringList customCategories();
/**
* Attempts to load an applet from a package
*
* Returns a pointer to the applet if successful.
* The caller takes responsibility for the applet, including
* deleting it when no longer needed.
*
* @param path the path to the package
* @param appletId unique ID to assign the applet, or zero to have one
* assigned automatically.
* @param args to send the applet extra arguments
* @return a pointer to the loaded applet, or 0 on load failure
* @since 4.3
**/
static Applet *loadPlasmoid(const QString &path, uint appletId = 0,
const QVariantList &args = QVariantList());
/**
* Get the category of the given applet
*
* @param applet a KPluginInfo object for the applet
*/
static QString category(const KPluginInfo &applet);
/**
* Get the category of the given applet
*
* @param appletName the name of the applet
*/
static QString category(const QString &appletName);
/**
* Returns the user-visible name for the applet, as specified in the
* .desktop file. Can be changed with @see setName
*
* @return the user-visible name for the applet.
**/
QString name() const;
/**
* Sets a custom name for this instance of the applet. E.g. a clock might
* use the timezone as its name rather than the .desktop file
*/
void setName(const QString &name) const;
/**
* @return the font currently set for this widget
**/
QFont font() const;
/**
* Returns the plugin name for the applet
*/
QString pluginName() const;
/**
* Whether the applet should conserve resources. If true, try to avoid doing stuff which
* is computationally heavy. Try to conserve power and resources.
*
* @return true if it should conserve resources, false if it does not.
*/
bool shouldConserveResources() const;
/**
* Returns the icon related to this applet
**/
QString icon() const;
/**
* Returns the category the applet is in, as specified in the
* .desktop file.
*/
QString category() const;
/**
* @return The type of immutability of this applet
*/
ImmutabilityType immutability() const;
/**
* If for some reason, the applet fails to get up on its feet (the
* library couldn't be loaded, necessary hardware support wasn't found,
* etc..) this method returns true
**/
bool hasFailedToLaunch() const;
/**
* @return true if the applet is busy and is showing an indicator widget for that
*/
bool isBusy() const;
/**
* @return true if the applet currently needs to be configured,
* otherwise, false
*/
bool configurationRequired() const;
/**
* @return true if this plasmoid provides a GUI configuration
**/
bool hasConfigurationInterface() const;
/**
* Returns a list of context-related QAction instances.
*
* This is used e.g. within the \a DesktopView to display a
* contextmenu.
*
* @return A list of actions. The default implementation returns an
* empty list.
**/
virtual QList<QAction*> contextualActions();
/**
* Returns the QAction with the given name from our collection
*/
Q_INVOKABLE QAction *action(QString name) const;
/**
* Adds the action to our collection under the given name
*/
void addAction(QString name, QAction *action);
/**
* Sets the BackgroundHints for this applet @see BackgroundHint
*
* @param hints the BackgroundHint combination for this applet
*/
void setBackgroundHints(const Plasma::BackgroundHints hint);
/**
* @return BackgroundHints flags combination telling if the standard background is shown
* and if it has a drop shadow
*/
Plasma::BackgroundHints backgroundHints() const;
/**
* @return true if this Applet is currently being used as a Containment, false otherwise
*/
bool isContainment() const;
/**
* @return the Containment, if any, this applet belongs to
**/
Containment *containment() const;
/**
* Sets the global shorcut to associate with this widget.
*/
void setGlobalShortcut(const KShortcut &shortcut);
/**
* @return the global shortcut associated with this wiget, or
* an empty shortcut if no global shortcut is associated.
*/
KShortcut globalShortcut() const;
/**
* @return true is there is a popup assoiated with this Applet
* showing, such as the dialog of a PopupApplet. May be reimplemented
* for custom popup implementations.
*/
virtual bool isPopupShowing() const;
/**
* associate actions with this widget, including ones added after this call.
* needed to make keyboard shortcuts work.
*/
virtual void addAssociatedWidget(QWidget *widget);
/**
* un-associate actions from this widget, including ones added after this call.
* needed to make keyboard shortcuts work.
*/
virtual void removeAssociatedWidget(QWidget *widget);
/**
* @param parent the QObject this applet is parented to
* @param serviceId the name of the .desktop file containing the
* information about the widget
* @param appletId a unique id used to differentiate between multiple
* instances of the same Applet type
*/
explicit Applet(QObject *parent = 0, const QString &serviceId = QString(), uint appletId = 0);
/**
* @param parent the QObject this applet is parented to
* @param info the plugin information object for this Applet
* @param appletId a unique id used to differentiate between multiple
* instances of the same Applet type
* @since 4.6
*/
explicit Applet(const KPluginInfo &info, QObject *parent = 0, uint appletId = 0);
/**
* @param parent the QObject this applet is parented to
* @param serviceId the name of the .desktop file containing the
* information about the widget
* @param appletId a unique id used to differentiate between multiple
* instances of the same Applet type
* @param args a list of strings containing two entries: the service id
* and the applet id
* @since 4.3
*/
explicit Applet(QObject *parent, const QString &serviceId, uint appletId, const QVariantList &args);
/**
* @return true if destroy() was called; useful for Applets which should avoid
* certain tasks if they are about to be deleted permanently
*/
bool destroyed() const;
/**
* Reimplement this method so provide a configuration interface,
* parented to the supplied widget. Ownership of the widgets is passed
* to the parent widget.
*
* Typically one would add custom pages to the config dialog @p parent
* and then connect to the applyClicked() and okClicked() signals
* or @p parent to react on config changes:
*
* @code
* connect(parent, SIGNAL(applyClicked()), this, SLOT(myConfigAccepted()));
* connect(parent, SIGNAL(okClicked()), this, SLOT(myConfigAccepted()));
* @endcode
*
* With this approach it makes sense to store the custom pages in member
* variables to make their fields accessible from the myConfigAccepted()
* slot.
*
* Use config() to store your configuration.
*
* @param parent the dialog which is the parent of the configuration
* widgets
*/
virtual void createConfigurationInterface(KConfigDialog *parent);
/**
* Returns true if the applet is allowed to perform functions covered by the given constraint
* eg. hasAuthorization("FileDialog") returns true if applets are allowed to show filedialogs.
* @since 4.3
*/
bool hasAuthorization(const QString &constraint) const;
/**
* Sets an application associated to this applet, that will be
* regarded as a full view of what is represented in the applet
*
* @param string the name of the application. it can be
* \li a name understood by KService::serviceByDesktopName
* (e.g. "konqueror")
* \li a command in $PATH
* \li or an absolute path to an executable
* @since 4.4
*/
void setAssociatedApplication(const QString &string);
/**
* Sets a list of urls associated to this application,
* they will be used as parameters for the associated application
* @see setAssociatedApplication()
*
* @param urls
*/
void setAssociatedApplicationUrls(const QList<QUrl> &urls);
/**
* @return the application associated to this applet
* @since 4.4
*/
QString associatedApplication() const;
/**
* @return the urls associated to this applet
* @since 4.4
*/
QList<QUrl> associatedApplicationUrls() const;
/**
* @return true if the applet has a valid associated application or urls
* @since 4.4
*/
bool hasValidAssociatedApplication() const;
Q_SIGNALS:
/**
* This signal indicates that an application launch, window
* creation or window focus event was triggered. This is used, for instance,
* to ensure that the Dashboard view in Plasma Desktop hides when such an event is
* triggered by an item it is displaying.
*/
void releaseVisualFocus();
/**
* Emitted when the user completes a transformation of the applet.
*/
void appletTransformedByUser();
/**
* Emitted when the applet changes its own geometry or transform.
*/
void appletTransformedItself();
/**
* Emitted when an applet has changed values in its configuration
* and wishes for them to be saved at the next save point. As this implies
* disk activity, this signal should be used with care.
*
* @note This does not need to be emitted from saveState by individual
* applets.
*/
void configNeedsSaving();
/**
* Emitted when activation is requested due to, for example, a global
* keyboard shortcut. By default the wiget is given focus.
*/
void activate();
/**
* Emitted when the user clicked on a button of the message overlay
*
* @see showMessage
* @see Plasma::MessageButton
* @since 4.3
*/
void messageButtonPressed(const Plasma::MessageButton button);
/**
* Emitted when the applet is deleted
*/
void appletDeleted(Plasma::Applet *applet);
/**
* Emitted when the applet status changes
* @since 4.4
*/
void newStatus(Plasma::ItemStatus status);
/**
* Emitted when the immutability changes
* @since 4.4
*/
void immutabilityChanged(Plasma::ImmutabilityType immutable);
public Q_SLOTS:
/**
* Sets the immutability type for this applet (not immutable,
* user immutable or system immutable)
* @param immutable the new immutability type of this applet
*/
void setImmutability(const ImmutabilityType immutable);
/**
* Destroys the applet; it will be removed nicely and deleted.
* Its configuration will also be deleted.
*/
virtual void destroy();
/**
* Lets the user interact with the plasmoid options.
* Called when the user selects the configure entry
* from the context menu.
*
* Unless there is good reason for overriding this method,
* Applet subclasses should actually override createConfigurationInterface
* instead. A good example of when this isn't plausible is
* when using a dialog prepared by another library, such
* as KPropertiesDialog from libkfile.
* You probably want to call showConfigurationInterface(QWidget*)
* with the custom widget you created to actually show your interface
*/
virtual void showConfigurationInterface();
/**
* Actually show your custom configuration interface
* Use this only if you reimplemented showConfigurationInterface()
*
* @param widget the widget representing your configuration interface
*
* @since 4.5
*/
void showConfigurationInterface(QWidget *widget);
/**
* @return true when the configuration interface is being shown
* @since 4.5
*/
bool isUserConfiguring() const;
/**
* Sends all pending contraints updates to the applet. Will usually
* be called automatically, but can also be called manually if needed.
*/
void flushPendingConstraintsEvents();
/**
* This method is called once the applet is loaded and added to a Corona.
* If the applet requires a Scene or has an particularly intensive
* set of initialization routines to go through, consider implementing it
* in this method instead of the constructor.
*
* Note: paintInterface may get called before init() depending on initialization
* order. Painting is managed by the canvas (QGraphisScene), and may schedule a
* paint event prior to init() being called.
**/
virtual void init();
/**
* Called when applet configuration values have changed.
*/
virtual void configChanged();
/**
* Shows a busy indicator that overlays the applet
* @param busy show or hide the busy indicator
*/
void setBusy(bool busy);
/**
* @return the list of arguments which the applet was called with
* @since KDE4.3
*/
QVariantList startupArguments() const;
/**
* @return the status of the applet
* @since 4.4
*/
ItemStatus status() const;
/**
* sets the status for this applet
* @since 4.4
*/
void setStatus(const ItemStatus stat);
/**
* Publishes and optionally announces this applet on the network for remote access.
* @param methods the methods to use for announcing this applet.
* @param resourceName the name under which this applet will be published (has to be unique
* for each machine)
*/
void publish(Plasma::AnnouncementMethods methods, const QString &resourceName);
void unpublish();
bool isPublished() const;
/**
* Open the application associated to this applet, if it's not set
* but some urls are, open those urls with the proper application
* for their mimetype
* @see setAssociatedApplication()
* @see setAssociatedApplicationUrls()
* @since 4.4
*/
void runAssociatedApplication();
bool hasFocus() const;
void setFocus(Qt::FocusReason);
protected:
/**
* This constructor is to be used with the plugin loading systems
* found in KPluginInfo and KService. The argument list is expected
* to have two elements: the KService service ID for the desktop entry
* and an applet ID which must be a base 10 number.
*
* @param parent a QObject parent; you probably want to pass in 0
* @param args a list of strings containing two entries: the service id
* and the applet id
*/
Applet(QObject *parent, const QVariantList &args);
/**
* Call this method when the applet fails to launch properly. An
* optional reason can be provided.
*
* Not that all children items will be deleted when this method is
* called. If you have pointers to these items, you will need to
* reset them after calling this method.
*
* @param failed true when the applet failed, false when it succeeded
* @param reason an optional reason to show the user why the applet
* failed to launch
**/
void setFailedToLaunch(bool failed, const QString &reason = QString());
/**
* When called, the Applet should write any information needed as part
* of the Applet's running state to the configuration object in config()
* and/or globalConfig().
*
* Applets that always sync their settings/state with the config
* objects when these settings/states change do not need to reimplement
* this method.
**/
virtual void saveState(KConfigGroup &config) const;
/**
* Sets whether or not this applet provides a user interface for
* configuring the applet.
*
* It defaults to false, and if true is passed in you should
* also reimplement createConfigurationInterface()
*
* @param hasInterface whether or not there is a user interface available
**/
void setHasConfigurationInterface(bool hasInterface);
/**
* When the applet needs to be configured before being usable, this
* method can be called to show a standard interface prompting the user
* to configure the applet
*
* @param needsConfiguring true if the applet needs to be configured,
* or false if it doesn't
* @param reason a translated message for the user explaining that the
* applet needs configuring; this should note what needs
* to be configured
*/
void setConfigurationRequired(bool needsConfiguring, const QString &reason = QString());
/**
* Shows a message as an overlay of the applet: the message has an
* icon, text and (optional) buttons
*
* @param icon the icon that will be shown
* @param message the message string that will be shown.
* If the message is empty nothng will be shown
* and if there was a message already it will be hidden
* @param buttons an OR combination of all the buttons needed
*
* @see Plasma::MessageButtons
* @see messageButtonPressed
* @since 4.3
*/
void showMessage(const QIcon &icon, const QString &message, const Plasma::MessageButtons buttons);
/**
* Called when any of the constraints for the applet have been updated. These constraints
* range from notifying when the applet has officially "started up" to when geometry changes
* to when the form factor changes.
*
* Each constraint that has been changed is passed in the constraints flag.
* All of the constraints and how they work is documented in the @see Plasma::Constraints
* enumeration.
*
* On applet creation, this is always called prior to painting and can be used as an
* opportunity to layout the widget, calculate sizings, etc.
*
* Do not call update() from this method; an update() will be triggered
* at the appropriate time for the applet.
*
* @param constraints the type of constraints that were updated
* @property constraint
*/
virtual void constraintsEvent(Plasma::Constraints constraints);
/**
* Reimplemented from QObject
*/
void timerEvent (QTimerEvent *event);
private:
/**
* @internal This constructor is to be used with the Package loading system.
*
* @param parent a QObject parent; you probably want to pass in 0
* @param args a list of strings containing two entries: the service id
* and the applet id
* @since 4.3
*/
Applet(const QString &packagePath, uint appletId, const QVariantList &args);
Q_PRIVATE_SLOT(d, void cleanUpAndDelete())
Q_PRIVATE_SLOT(d, void configDialogFinished())
Q_PRIVATE_SLOT(d, void updateShortcuts())
Q_PRIVATE_SLOT(d, void publishCheckboxStateChanged(int state))
Q_PRIVATE_SLOT(d, void globalShortcutChanged())
Q_PRIVATE_SLOT(d, void propagateConfigChanged())
AppletPrivate *const d;
//Corona needs to access setFailedToLaunch and init
friend class Corona;
friend class CoronaPrivate;
friend class Containment;
friend class ContainmentPrivate;
friend class AppletScript;
friend class AppletHandle;
friend class AppletPrivate;
friend class AccessAppletJobPrivate;
friend class GraphicsViewAppletPrivate;
friend class PluginLoader;
friend class PopupApplet;
friend class PopupAppletPrivate;
friend class AssociatedApplicationManager;
};
} // Plasma namespace
/**
* Register an applet when it is contained in a loadable module
*/
#define K_EXPORT_PLASMA_APPLET(libname, classname) \
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN(factory("plasma_applet_" #libname)) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
#endif // multiple inclusion guard

View File

@ -0,0 +1,12 @@
#cmakedefine01 ENABLE_REMOTE_WIDGETS
#cmakedefine01 PLASMA_NO_KDEWEBKIT
#cmakedefine01 PLASMA_NO_SOLID
#cmakedefine01 PLASMA_NO_KIO
#cmakedefine01 PLASMA_NO_KUTILS
#cmakedefine01 PLASMA_NO_GLOBAL_SHORTCUTS
#cmakedefine01 HAVE_X11
/*FIXME: Only used in CMakeLists.txt, to be removed ?*/
#cmakedefine01 PLASMA_NO_KNEWSTUFF
#cmakedefine01 QCA2_FOUND

433
plasma/configloader.cpp Normal file
View File

@ -0,0 +1,433 @@
/*
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "configloader.h"
#include "private/configloader_p.h"
#include <QColor>
#include <QFont>
#include <QHash>
#include <QXmlContentHandler>
#include <QXmlInputSource>
#include <QXmlSimpleReader>
#include <QUrl>
#include <kdebug.h>
namespace Plasma
{
class ConfigLoaderHandler : public QXmlDefaultHandler
{
public:
ConfigLoaderHandler(ConfigLoader *config, ConfigLoaderPrivate *d);
bool startElement(const QString &namespaceURI, const QString &localName,
const QString &qName, const QXmlAttributes &atts);
bool endElement(const QString &namespaceURI, const QString &localName,
const QString &qName);
bool characters(const QString &ch);
private:
void addItem();
void resetState();
ConfigLoader *m_config;
ConfigLoaderPrivate *d;
int m_min;
int m_max;
QString m_name;
QString m_key;
QString m_type;
QString m_label;
QString m_default;
QString m_cdata;
QString m_whatsThis;
KConfigSkeleton::ItemEnum::Choice m_choice;
QList<KConfigSkeleton::ItemEnum::Choice> m_enumChoices;
bool m_haveMin;
bool m_haveMax;
bool m_inChoice;
};
void ConfigLoaderPrivate::parse(ConfigLoader *loader, QIODevice *xml)
{
QXmlInputSource source(xml);
QXmlSimpleReader reader;
ConfigLoaderHandler handler(loader, this);
reader.setContentHandler(&handler);
reader.parse(&source, false);
}
ConfigLoaderHandler::ConfigLoaderHandler(ConfigLoader *config, ConfigLoaderPrivate *d)
: QXmlDefaultHandler(),
m_config(config),
d(d)
{
resetState();
}
bool ConfigLoaderHandler::startElement(const QString &namespaceURI, const QString &localName,
const QString &qName, const QXmlAttributes &attrs)
{
Q_UNUSED(namespaceURI)
Q_UNUSED(qName)
// kDebug() << "ConfigLoaderHandler::startElement(" << localName << qName;
int numAttrs = attrs.count();
QString tag = localName.toLower();
if (tag == "group") {
QString group;
for (int i = 0; i < numAttrs; ++i) {
QString name = attrs.localName(i).toLower();
if (name == "name") {
//kDebug() << "set group to" << attrs.value(i);
group = attrs.value(i);
}
}
if (group.isEmpty()) {
group = d->baseGroup;
} else {
d->groups.append(group);
if (!d->baseGroup.isEmpty()) {
group = d->baseGroup + '\x1d' + group;
}
}
m_config->setCurrentGroup(group);
} else if (tag == "entry") {
for (int i = 0; i < numAttrs; ++i) {
QString name = attrs.localName(i).toLower();
if (name == "name") {
m_name = attrs.value(i).trimmed();
} else if (name == "type") {
m_type = attrs.value(i).toLower();
} else if (name == "key") {
m_key = attrs.value(i).trimmed();
}
}
} else if (tag == "choice") {
m_choice.name.clear();
m_choice.label.clear();
m_choice.whatsThis.clear();
for (int i = 0; i < numAttrs; ++i) {
QString name = attrs.localName(i).toLower();
if (name == "name") {
m_choice.name = attrs.value(i);
}
}
m_inChoice = true;
}
return true;
}
bool ConfigLoaderHandler::characters(const QString &ch)
{
m_cdata.append(ch);
return true;
}
bool ConfigLoaderHandler::endElement(const QString &namespaceURI,
const QString &localName, const QString &qName)
{
Q_UNUSED(namespaceURI)
Q_UNUSED(qName)
// kDebug() << "ConfigLoaderHandler::endElement(" << localName << qName;
const QString tag = localName.toLower();
if (tag == "entry") {
addItem();
resetState();
} else if (tag == "label") {
if (m_inChoice) {
m_choice.label = m_cdata.trimmed();
} else {
m_label = m_cdata.trimmed();
}
} else if (tag == "whatsthis") {
if (m_inChoice) {
m_choice.whatsThis = m_cdata.trimmed();
} else {
m_whatsThis = m_cdata.trimmed();
}
} else if (tag == "default") {
m_default = m_cdata.trimmed();
} else if (tag == "min") {
m_min = m_cdata.toInt(&m_haveMin);
} else if (tag == "max") {
m_max = m_cdata.toInt(&m_haveMax);
} else if (tag == "choice") {
m_enumChoices.append(m_choice);
m_inChoice = false;
}
m_cdata.clear();
return true;
}
void ConfigLoaderHandler::addItem()
{
if (m_name.isEmpty()) {
if (m_key.isEmpty()) {
return;
}
m_name = m_key;
}
m_name.remove(' ');
KConfigSkeletonItem *item = 0;
if (m_type == "bool") {
bool defaultValue = m_default.toLower() == "true";
item = m_config->addItemBool(m_name, *d->newBool(), defaultValue, m_key);
} else if (m_type == "color") {
item = m_config->addItemColor(m_name, *d->newColor(), QColor(m_default), m_key);
} else if (m_type == "datetime") {
item = m_config->addItemDateTime(m_name, *d->newDateTime(),
QDateTime::fromString(m_default), m_key);
} else if (m_type == "enum") {
m_key = (m_key.isEmpty()) ? m_name : m_key;
KConfigSkeleton::ItemEnum *enumItem =
new KConfigSkeleton::ItemEnum(m_config->currentGroup(),
m_key, *d->newInt(),
m_enumChoices,
m_default.toUInt());
m_config->addItem(enumItem, m_name);
item = enumItem;
} else if (m_type == "font") {
item = m_config->addItemFont(m_name, *d->newFont(), QFont(m_default), m_key);
} else if (m_type == "int") {
KConfigSkeleton::ItemInt *intItem = m_config->addItemInt(m_name, *d->newInt(),
m_default.toInt(), m_key);
if (m_haveMin) {
intItem->setMinValue(m_min);
}
if (m_haveMax) {
intItem->setMaxValue(m_max);
}
item = intItem;
} else if (m_type == "password") {
item = m_config->addItemPassword(m_name, *d->newString(), m_default, m_key);
} else if (m_type == "path") {
item = m_config->addItemPath(m_name, *d->newString(), m_default, m_key);
} else if (m_type == "string") {
item = m_config->addItemString(m_name, *d->newString(), m_default, m_key);
} else if (m_type == "stringlist") {
//FIXME: the split() is naive and will break on lists with ,'s in them
item = m_config->addItemStringList(m_name, *d->newStringList(),
m_default.split(','), m_key);
} else if (m_type == "uint") {
KConfigSkeleton::ItemUInt *uintItem =
m_config->addItemUInt(m_name, *d->newUint(), m_default.toUInt(), m_key);
if (m_haveMin) {
uintItem->setMinValue(m_min);
}
if (m_haveMax) {
uintItem->setMaxValue(m_max);
}
item = uintItem;
} else if (m_type == "url") {
m_key = (m_key.isEmpty()) ? m_name : m_key;
KConfigSkeleton::ItemUrl *urlItem =
new KConfigSkeleton::ItemUrl(m_config->currentGroup(),
m_key, *d->newUrl(),
QUrl::fromUserInput(m_default));
m_config->addItem(urlItem, m_name);
item = urlItem;
} else if (m_type == "double") {
KConfigSkeleton::ItemDouble *doubleItem = m_config->addItemDouble(m_name,
*d->newDouble(), m_default.toDouble(), m_key);
if (m_haveMin) {
doubleItem->setMinValue(m_min);
}
if (m_haveMax) {
doubleItem->setMaxValue(m_max);
}
item = doubleItem;
} else if (m_type == "intlist") {
QStringList tmpList = m_default.split(',');
QList<int> defaultList;
foreach (const QString &tmp, tmpList) {
defaultList.append(tmp.toInt());
}
item = m_config->addItemIntList(m_name, *d->newIntList(), defaultList, m_key);
} else if (m_type == "longlong") {
KConfigSkeleton::ItemLongLong *longlongItem = m_config->addItemLongLong(m_name,
*d->newLongLong(), m_default.toLongLong(), m_key);
if (m_haveMin) {
longlongItem->setMinValue(m_min);
}
if (m_haveMax) {
longlongItem->setMaxValue(m_max);
}
item = longlongItem;
/* No addItemPathList in KConfigSkeleton ?
} else if (m_type == "PathList") {
//FIXME: the split() is naive and will break on lists with ,'s in them
item = m_config->addItemPathList(m_name, *d->newStringList(), m_default.split(","), m_key);
*/
} else if (m_type == "point") {
QPoint defaultPoint;
QStringList tmpList = m_default.split(',');
if (tmpList.size() >= 2) {
defaultPoint.setX(tmpList[0].toInt());
defaultPoint.setY(tmpList[1].toInt());
}
item = m_config->addItemPoint(m_name, *d->newPoint(), defaultPoint, m_key);
} else if (m_type == "rect") {
QRect defaultRect;
QStringList tmpList = m_default.split(',');
if (tmpList.size() >= 4) {
defaultRect.setCoords(tmpList[0].toInt(), tmpList[1].toInt(),
tmpList[2].toInt(), tmpList[3].toInt());
}
item = m_config->addItemRect(m_name, *d->newRect(), defaultRect, m_key);
} else if (m_type == "size") {
QSize defaultSize;
QStringList tmpList = m_default.split(',');
if (tmpList.size() >= 2) {
defaultSize.setWidth(tmpList[0].toInt());
defaultSize.setHeight(tmpList[1].toInt());
}
item = m_config->addItemSize(m_name, *d->newSize(), defaultSize, m_key);
} else if (m_type == "ulonglong") {
KConfigSkeleton::ItemULongLong *ulonglongItem =
m_config->addItemULongLong(m_name, *d->newULongLong(), m_default.toULongLong(), m_key);
if (m_haveMin) {
ulonglongItem->setMinValue(m_min);
}
if (m_haveMax) {
ulonglongItem->setMaxValue(m_max);
}
item = ulonglongItem;
/* No addItemUrlList in KConfigSkeleton ?
} else if (m_type == "urllist") {
//FIXME: the split() is naive and will break on lists with ,'s in them
QStringList tmpList = m_default.split(",");
QList<QUrl> defaultList;
foreach (const QString& tmp, tmpList) {
defaultList.append(KUrl(tmp));
}
item = m_config->addItemUrlList(m_name, *d->newUrlList(), defaultList, m_key);*/
}
if (item) {
item->setLabel(m_label);
item->setWhatsThis(m_whatsThis);
d->keysToNames.insert(item->group() + item->key(), item->name());
}
}
void ConfigLoaderHandler::resetState()
{
m_haveMin = false;
m_min = 0;
m_haveMax = false;
m_max = 0;
m_name.clear();
m_type.clear();
m_label.clear();
m_default.clear();
m_key.clear();
m_whatsThis.clear();
m_enumChoices.clear();
m_inChoice = false;
}
ConfigLoader::ConfigLoader(const QString &configFile, QIODevice *xml, QObject *parent)
: KConfigSkeleton(configFile, parent),
d(new ConfigLoaderPrivate)
{
d->parse(this, xml);
}
ConfigLoader::ConfigLoader(KSharedConfigPtr config, QIODevice *xml, QObject *parent)
: KConfigSkeleton(config, parent),
d(new ConfigLoaderPrivate)
{
d->parse(this, xml);
}
//FIXME: obviously this is broken and should be using the group as the root,
// but KConfigSkeleton does not currently support this. it will eventually though,
// at which point this can be addressed properly
ConfigLoader::ConfigLoader(const KConfigGroup *config, QIODevice *xml, QObject *parent)
: KConfigSkeleton(KSharedConfig::openConfig(config->config()->name()), parent),
d(new ConfigLoaderPrivate)
{
KConfigGroup group = config->parent();
d->baseGroup = config->name();
while (group.isValid() && group.name() != "<default>") {
d->baseGroup = group.name() + '\x1d' + d->baseGroup;
group = group.parent();
}
d->parse(this, xml);
}
ConfigLoader::~ConfigLoader()
{
delete d;
}
KConfigSkeletonItem *ConfigLoader::findItem(const QString &group, const QString &key)
{
return KConfigSkeleton::findItem(d->keysToNames[group + key]);
}
KConfigSkeletonItem *ConfigLoader::findItemByName(const QString &name)
{
return KConfigSkeleton::findItem(name);
}
QVariant ConfigLoader::property(const QString &name)
{
KConfigSkeletonItem *item = KConfigSkeleton::findItem(name);
if (item) {
return item->property();
}
return QVariant();
}
bool ConfigLoader::hasGroup(const QString &group) const
{
return d->groups.contains(group);
}
QStringList ConfigLoader::groupList() const
{
return d->groups;
}
void ConfigLoader::usrWriteConfig()
{
if (d->saveDefaults) {
KConfigSkeletonItem::List itemList = items();
for(int i = 0; i < itemList.size(); i++) {
KConfigGroup cg(config(), itemList.at(i)->group());
cg.writeEntry(itemList.at(i)->key(), "");
}
}
}
} // Plasma namespace

154
plasma/configloader.h Normal file
View File

@ -0,0 +1,154 @@
/*
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CONFIGLOADER_H
#define PLASMA_CONFIGLOADER_H
#include <kconfiggroup.h>
#include <kconfigskeleton.h>
#include <ksharedconfig.h>
#include <plasma/plasma_export.h>
/**
* @class ConfigLoader plasma/configloader.h <Plasma/ConfigLoader>
*
* @short A KConfigSkeleton that populates itself based on KConfigXT XML
*
* This class allows one to ship an XML file and reconstitute it into a
* KConfigSkeleton object at runtime. Common usage might look like this:
*
* \code
* QFile file(xmlFilePath);
* Plasma::ConfigLoader appletConfig(configFilePath, &file);
* \endcode
*
* Alternatively, any QIODevice may be used in place of QFile in the
* example above.
*
* Currently the following data types are supported:
*
* @li bools
* @li colors
* @li datetimes
* @li enumerations
* @li fonts
* @li ints
* @li passwords
* @li paths
* @li strings
* @li stringlists
* @li uints
* @li urls
* @li doubles
* @li int lists
* @li longlongs
* @li path lists
* @li points
* @li rects
* @li sizes
* @li ulonglongs
* @li url lists
**/
namespace Plasma
{
class ConfigLoaderPrivate;
class PLASMA_EXPORT ConfigLoader : public KConfigSkeleton
{
public:
/**
* Creates a KConfigSkeleton populated using the definition found in
* the XML data passed in.
*
* @param configFile path to the configuration file to use
* @param xml the xml data; must be valid KConfigXT data
* @param parent optional QObject parent
**/
ConfigLoader(const QString &configFile, QIODevice *xml, QObject *parent = 0);
/**
* Creates a KConfigSkeleton populated using the definition found in
* the XML data passed in.
*
* @param config the configuration object to use
* @param xml the xml data; must be valid KConfigXT data
* @param parent optional QObject parent
**/
ConfigLoader(KSharedConfigPtr config, QIODevice *xml, QObject *parent = 0);
/**
* Creates a KConfigSkeleton populated using the definition found in
* the XML data passed in.
*
* @param config the group to use as the root for configuration items
* @param xml the xml data; must be valid KConfigXT data
* @param parent optional QObject parent
**/
ConfigLoader(const KConfigGroup *config, QIODevice *xml, QObject *parent = 0);
~ConfigLoader();
/**
* Finds the item for the given group and key.
*
* @param group the group in the config file to look in
* @param key the configuration key to find
* @return the associated KConfigSkeletonItem, or 0 if none
*/
KConfigSkeletonItem *findItem(const QString &group, const QString &key);
/**
* Finds an item by its name
*/
KConfigSkeletonItem *findItemByName(const QString &name);
/**
* Returns the property (variantized value) of the named item
*/
QVariant property(const QString &name);
/**
* Check to see if a group exists
*
* @param group the name of the group to check for
* @return true if the group exists, or false if it does not
*/
bool hasGroup(const QString &group) const;
/**
* @return the list of groups defined by the XML
*/
QStringList groupList() const;
protected:
/**
* Hack used to force writing when no default exists in config file.
*/
void usrWriteConfig();
private:
friend class Service;
ConfigLoaderPrivate * const d;
};
} // Plasma namespace
#endif //multiple inclusion guard

932
plasma/containment.cpp Normal file
View File

@ -0,0 +1,932 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* Copyright 2009 Chani Armitage <chani@kde.org>
* Copyright 2012 Marco Martin <notmart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "containment.h"
#include "private/containment_p.h"
#include "config-plasma.h"
#include <QApplication>
#include <QClipboard>
#include <QFile>
#include <QContextMenuEvent>
#include <QMimeData>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <qtemporaryfile.h>
#include <kaction.h>
#include <kcoreauthorized.h>
#include <kmenu.h>
#include <kmessagebox.h>
#include <qmimedatabase.h>
#include <kservicetypetrader.h>
#include <kwindowsystem.h>
#if !PLASMA_NO_KIO
#include "kio/jobclasses.h" // for KIO::JobFlags
#include "kio/job.h"
#include "kio/scheduler.h"
#endif
#include "containmentactions.h"
#include "containmentactionspluginsconfig.h"
#include "corona.h"
#include "pluginloader.h"
#include "svg.h"
#include "remote/accessappletjob.h"
#include "remote/accessmanager.h"
#include "private/applet_p.h"
#include "private/containmentactionspluginsconfig_p.h"
#include "plasma/plasma.h"
namespace Plasma
{
Containment::Containment(QObject *parent,
const QString &serviceId,
uint containmentId)
: Applet(parent, serviceId, containmentId),
d(new ContainmentPrivate(this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
setBackgroundHints(NoBackground);
setContainmentType(CustomContainment);
setHasConfigurationInterface(false);
}
Containment::Containment(QObject *parent, const QVariantList &args)
: Applet(parent, args),
d(new ContainmentPrivate(this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
setBackgroundHints(NoBackground);
setHasConfigurationInterface(false);
}
Containment::Containment(const QString &packagePath, uint appletId, const QVariantList &args)
: Applet(packagePath, appletId, args),
d(new ContainmentPrivate(this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
setBackgroundHints(NoBackground);
setHasConfigurationInterface(false);
}
Containment::~Containment()
{
// Applet touches our dptr if we are a containment and is the superclass (think of dtors)
// so we reset this as we exit the building
Applet::d->isContainment = false;
delete d;
}
void Containment::init()
{
Applet::init();
if (!isContainment()) {
return;
}
if (d->type == NoContainmentType) {
setContainmentType(DesktopContainment);
}
//connect actions
ContainmentPrivate::addDefaultActions(d->actions(), this);
bool unlocked = immutability() == Mutable;
//fix the text of the actions that need name()
//btw, do we really want to use name() when it's a desktopcontainment?
QAction *closeApplet = action("remove");
if (closeApplet) {
closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", name()));
}
QAction *configAction = action("configure");
if (configAction) {
configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", name()));
}
QAction *appletBrowserAction = action("add widgets");
if (appletBrowserAction) {
appletBrowserAction->setVisible(unlocked);
appletBrowserAction->setEnabled(unlocked);
connect(appletBrowserAction, SIGNAL(triggered()), this, SLOT(triggerShowAddWidgets()));
}
QAction *act = action("next applet");
if (act) {
connect(act, SIGNAL(triggered()), this, SLOT(focusNextApplet()));
}
act = action("previous applet");
if (act) {
connect(act, SIGNAL(triggered()), this, SLOT(focusPreviousApplet()));
}
if (immutability() != SystemImmutable && corona()) {
QAction *lockDesktopAction = corona()->action("lock widgets");
//keep a pointer so nobody notices it moved to corona
if (lockDesktopAction) {
d->actions()->addAction("lock widgets", lockDesktopAction);
}
}
if (d->type != PanelContainment && d->type != CustomPanelContainment) {
if (corona()) {
//FIXME this is just here because of the darn keyboard shortcut :/
act = corona()->action("manage activities");
if (act) {
d->actions()->addAction("manage activities", act);
}
//a stupid hack to make this one's keyboard shortcut work
act = corona()->action("configure shortcuts");
if (act) {
d->actions()->addAction("configure shortcuts", act);
}
}
if (d->type == DesktopContainment) {
addToolBoxAction(action("add widgets"));
//TODO: do we need some way to allow this be overridden?
// it's always available because shells rely on this
// to offer their own custom configuration as well
QAction *configureContainment = action("configure");
if (configureContainment) {
addToolBoxAction(configureContainment);
}
}
}
}
// helper function for sorting the list of applets
bool appletConfigLessThan(const KConfigGroup &c1, const KConfigGroup &c2)
{
QPointF p1 = c1.readEntry("geometry", QRectF()).topLeft();
QPointF p2 = c2.readEntry("geometry", QRectF()).topLeft();
if (!qFuzzyCompare(p1.x(), p2.x())) {
if (QApplication::layoutDirection() == Qt::RightToLeft) {
return p1.x() > p2.x();
}
return p1.x() < p2.x();
}
return qFuzzyCompare(p1.y(), p2.y()) || p1.y() < p2.y();
}
void Containment::restore(KConfigGroup &group)
{
/*
#ifndef NDEBUG
kDebug() << "!!!!!!!!!!!!initConstraints" << group.name() << d->type;
kDebug() << " location:" << group.readEntry("location", (int)d->location);
kDebug() << " geom:" << group.readEntry("geometry", geometry());
kDebug() << " formfactor:" << group.readEntry("formfactor", (int)d->formFactor);
kDebug() << " screen:" << group.readEntry("screen", d->screen);
#endif
*/
if (!isContainment()) {
Applet::restore(group);
return;
}
setLocation((Plasma::Location)group.readEntry("location", (int)d->location));
setFormFactor((Plasma::FormFactor)group.readEntry("formfactor", (int)d->formFactor));
//kDebug() << "setScreen from restore";
d->lastScreen = group.readEntry("lastScreen", d->lastScreen);
d->lastDesktop = group.readEntry("lastDesktop", d->lastDesktop);
d->setScreen(group.readEntry("screen", d->screen), group.readEntry("desktop", d->desktop), false);
d->activityId = group.readEntry("activityId", QString());
flushPendingConstraintsEvents();
restoreContents(group);
setImmutability((ImmutabilityType)group.readEntry("immutability", (int)Mutable));
setWallpaper(group.readEntry("wallpaperplugin", ContainmentPrivate::defaultWallpaper),
group.readEntry("wallpaperpluginmode", ContainmentPrivate::defaultWallpaperMode));
KConfigGroup cfg;
if (containmentType() == PanelContainment || containmentType() == CustomPanelContainment) {
//don't let global desktop actions conflict with panels
//this also prevents panels from sharing config with each other
//but the panels aren't configurable anyways, and I doubt that'll change.
d->containmentActionsSource = ContainmentPrivate::Local;
cfg = KConfigGroup(&group, "ActionPlugins");
} else {
const QString source = group.readEntry("ActionPluginsSource", QString());
if (source == "Global") {
cfg = KConfigGroup(corona()->config(), "ActionPlugins");
d->containmentActionsSource = ContainmentPrivate::Global;
} else if (source == "Activity") {
cfg = KConfigGroup(corona()->config(), "Activities");
cfg = KConfigGroup(&cfg, d->activityId);
cfg = KConfigGroup(&cfg, "ActionPlugins");
d->containmentActionsSource = ContainmentPrivate::Activity;
} else if (source == "Local") {
cfg = group;
d->containmentActionsSource = ContainmentPrivate::Local;
} else {
//default to global
//but, if there is no global config, try copying it from local.
cfg = KConfigGroup(corona()->config(), "ActionPlugins");
if (!cfg.exists()) {
cfg = KConfigGroup(&group, "ActionPlugins");
}
d->containmentActionsSource = ContainmentPrivate::Global;
group.writeEntry("ActionPluginsSource", "Global");
}
}
//kDebug() << cfg.keyList();
if (cfg.exists()) {
foreach (const QString &key, cfg.keyList()) {
//kDebug() << "loading" << key;
setContainmentActions(key, cfg.readEntry(key, QString()));
}
} else { //shell defaults
ContainmentActionsPluginsConfig conf = corona()->containmentActionsDefaults(d->type);
//steal the data directly, for efficiency
QHash<QString,QString> defaults = conf.d->plugins;
for (QHash<QString,QString>::const_iterator it = defaults.constBegin(),
end = defaults.constEnd(); it != end; ++it) {
setContainmentActions(it.key(), it.value());
}
}
/*
#ifndef NDEBUG
kDebug() << "Containment" << id() <<
#endif
"screen" << screen() <<
"geometry is" << geometry() <<
"wallpaper" << ((d->wallpaper) ? d->wallpaper->pluginName() : QString()) <<
"wallpaper mode" << wallpaperMode() <<
"config entries" << group.entryMap();
*/
}
void Containment::save(KConfigGroup &g) const
{
if (Applet::d->transient) {
return;
}
KConfigGroup group = g;
if (!group.isValid()) {
group = config();
}
// locking is saved in Applet::save
Applet::save(group);
if (!isContainment()) {
return;
}
group.writeEntry("screen", d->screen);
group.writeEntry("lastScreen", d->lastScreen);
group.writeEntry("desktop", d->desktop);
group.writeEntry("lastDesktop", d->lastDesktop);
group.writeEntry("formfactor", (int)d->formFactor);
group.writeEntry("location", (int)d->location);
group.writeEntry("activityId", d->activityId);
group.writeEntry("wallpaperplugin", d->wallpaper);
group.writeEntry("wallpaperpluginmode", d->wallpaperMode);
//TODO: the wallpaper implementation must know it has to save at this point
saveContents(group);
}
void Containment::saveContents(KConfigGroup &group) const
{
KConfigGroup applets(&group, "Applets");
foreach (const Applet *applet, d->applets) {
KConfigGroup appletConfig(&applets, QString::number(applet->id()));
applet->save(appletConfig);
}
}
void Containment::restoreContents(KConfigGroup &group)
{
KConfigGroup applets(&group, "Applets");
// Sort the applet configs in order of geometry to ensure that applets
// are added from left to right or top to bottom for a panel containment
QList<KConfigGroup> appletConfigs;
foreach (const QString &appletGroup, applets.groupList()) {
//kDebug() << "reading from applet group" << appletGroup;
KConfigGroup appletConfig(&applets, appletGroup);
appletConfigs.append(appletConfig);
}
qStableSort(appletConfigs.begin(), appletConfigs.end(), appletConfigLessThan);
QMutableListIterator<KConfigGroup> it(appletConfigs);
while (it.hasNext()) {
KConfigGroup &appletConfig = it.next();
int appId = appletConfig.name().toUInt();
QString plugin = appletConfig.readEntry("plugin", QString());
if (plugin.isEmpty()) {
continue;
}
d->addApplet(plugin, QVariantList(), appletConfig.readEntry("geometry", QRectF()), appId, true);
}
}
Containment::Type Containment::containmentType() const
{
return d->type;
}
void Containment::setContainmentType(Containment::Type type)
{
if (d->type == type) {
return;
}
d->type = type;
d->checkContainmentFurniture();
}
Corona *Containment::corona() const
{
return qobject_cast<Corona*>(parent());
}
void Containment::showDropZone(const QPoint pos)
{
Q_UNUSED(pos)
//Base implementation does nothing, don't put code here
}
void Containment::showContextMenu(const QPointF &containmentPos, const QPoint &screenPos)
{
//kDebug() << containmentPos << screenPos;
QContextMenuEvent gvevent(QContextMenuEvent::Mouse, screenPos);
//FIXME: do we need views here?
//gvevent.setWidget(view());
contextMenuEvent(&gvevent);
}
void Containment::contextMenuEvent(QContextMenuEvent *event)
{
if (!isContainment() || !KAuthorized::authorizeKAction("plasma/containment_context_menu")) {
return;
}
KMenu desktopMenu;
//TODO: port to the new containmentactions architecture
Applet *applet = 0;//d->appletAt(event->pos());
//kDebug() << "context menu event " << (QObject*)applet;
if (applet) {
d->addAppletActions(desktopMenu, applet, event);
} else {
d->addContainmentActions(desktopMenu, event);
}
//kDebug() << "executing at" << screenPos;
QMenu *menu = &desktopMenu;
//kDebug() << "showing menu, actions" << desktopMenu.actions().size() << desktopMenu.actions().first()->menu();
if (desktopMenu.actions().size() == 1 && desktopMenu.actions().first()->menu()) {
// we have a menu with a single top level menu; just show that top level menu instad.
menu = desktopMenu.actions().first()->menu();
}
if (!menu->isEmpty()) {
QPoint pos = event->globalPos();
if (applet && d->isPanelContainment()) {
menu->adjustSize();
pos = applet->popupPosition(menu->size());
if (event->reason() == QContextMenuEvent::Mouse) {
// if the menu pops up way away from the mouse press, then move it
// to the mouse press
if (d->formFactor == Vertical) {
if (pos.y() + menu->height() < event->globalPos().y()) {
pos.setY(event->globalPos().y());
}
} else if (d->formFactor == Horizontal) {
if (pos.x() + menu->width() < event->globalPos().x()) {
pos.setX(event->globalPos().x());
}
}
}
}
menu->exec(pos);
event->accept();
}
}
void Containment::setFormFactor(FormFactor formFactor)
{
if (d->formFactor == formFactor) {
return;
}
//kDebug() << "switching FF to " << formFactor;
d->formFactor = formFactor;
updateConstraints(Plasma::FormFactorConstraint);
KConfigGroup c = config();
c.writeEntry("formfactor", (int)formFactor);
emit configNeedsSaving();
}
void Containment::setLocation(Location location)
{
if (d->location == location) {
return;
}
d->location = location;
foreach (Applet *applet, d->applets) {
applet->updateConstraints(Plasma::LocationConstraint);
}
updateConstraints(Plasma::LocationConstraint);
KConfigGroup c = config();
c.writeEntry("location", (int)location);
emit configNeedsSaving();
}
void Containment::addSiblingContainment()
{
emit addSiblingContainment(this);
}
void Containment::clearApplets()
{
foreach (Applet *applet, d->applets) {
applet->d->cleanUpAndDelete();
}
d->applets.clear();
}
Applet *Containment::addApplet(const QString &name, const QVariantList &args,
const QRectF &appletGeometry)
{
return d->addApplet(name, args, appletGeometry);
}
void Containment::addApplet(Applet *applet, const QPointF &pos, bool delayInit)
{
if (!isContainment() || (!delayInit && immutability() != Mutable)) {
return;
}
if (!applet) {
#ifndef NDEBUG
kDebug() << "adding null applet!?!";
#endif
return;
}
if (d->applets.contains(applet)) {
#ifndef NDEBUG
kDebug() << "already have this applet!";
#endif
}
Containment *currentContainment = applet->containment();
if (d->type == PanelContainment) {
//panels don't want backgrounds, which is important when setting geometry
setBackgroundHints(NoBackground);
}
if (currentContainment && currentContainment != this) {
emit currentContainment->appletRemoved(applet);
disconnect(applet, 0, currentContainment, 0);
KConfigGroup oldConfig = applet->config();
currentContainment->d->applets.removeAll(applet);
applet->setParent(this);
// now move the old config to the new location
//FIXME: this doesn't seem to get the actual main config group containing plugin=, etc
KConfigGroup c = config().group("Applets").group(QString::number(applet->id()));
oldConfig.reparent(&c);
applet->d->resetConfigurationObject();
disconnect(applet, SIGNAL(activate()), currentContainment, SIGNAL(activate()));
} else {
applet->setParent(this);
}
d->applets << applet;
connect(applet, SIGNAL(configNeedsSaving()), this, SIGNAL(configNeedsSaving()));
connect(applet, SIGNAL(releaseVisualFocus()), this, SIGNAL(releaseVisualFocus()));
connect(applet, SIGNAL(appletDeleted(Plasma::Applet*)), this, SLOT(appletDestroyed(Plasma::Applet*)));
connect(applet, SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(checkStatus(Plasma::ItemStatus)));
connect(applet, SIGNAL(activate()), this, SIGNAL(activate()));
if (!delayInit && !currentContainment) {
applet->restore(*applet->d->mainConfigGroup());
applet->init();
//FIXME: an on-appear animation would be nice to have again
d->appletAppeared(applet);
}
applet->updateConstraints(Plasma::AllConstraints);
if (!delayInit) {
applet->flushPendingConstraintsEvents();
}
emit appletAdded(applet, pos);
if (!currentContainment) {
applet->updateConstraints(Plasma::StartupCompletedConstraint);
if (!delayInit) {
applet->flushPendingConstraintsEvents();
}
}
if (!delayInit) {
applet->d->scheduleModificationNotification();
}
}
Applet::List Containment::applets() const
{
return d->applets;
}
void Containment::setScreen(int newScreen, int newDesktop)
{
d->setScreen(newScreen, newDesktop);
}
int Containment::screen() const
{
return d->screen;
}
int Containment::lastScreen() const
{
return d->lastScreen;
}
int Containment::desktop() const
{
return d->desktop;
}
int Containment::lastDesktop() const
{
return d->lastDesktop;
}
KPluginInfo::List Containment::listContainments(const QString &category,
const QString &parentApp)
{
return listContainmentsOfType(QString(), category, parentApp);
}
KPluginInfo::List Containment::listContainmentsOfType(const QString &type,
const QString &category,
const QString &parentApp)
{
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
if (!type.isEmpty()) {
if (!constraint.isEmpty()) {
constraint.append(" and ");
}
constraint.append("'").append(type).append("' ~in [X-Plasma-ContainmentCategories]");
}
if (!category.isEmpty()) {
if (!constraint.isEmpty()) {
constraint.append(" and ");
}
constraint.append("[X-KDE-PluginInfo-Category] == '").append(category).append("'");
if (category == "Miscellaneous") {
constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
}
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
//kDebug() << "constraint was" << constraint << "which got us" << offers.count() << "matches";
return KPluginInfo::fromServices(offers);
}
KPluginInfo::List Containment::listContainmentsForMimeType(const QString &mimeType)
{
const QString constraint = QString("'%1' in [X-Plasma-DropMimeTypes]").arg(mimeType);
//kDebug() << mimeType << constraint;
const KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
return KPluginInfo::fromServices(offers);
}
QStringList Containment::listContainmentTypes()
{
KPluginInfo::List containmentInfos = listContainments();
QSet<QString> types;
foreach (const KPluginInfo &containmentInfo, containmentInfos) {
QStringList theseTypes = containmentInfo.service()->property("X-Plasma-ContainmentCategories").toStringList();
foreach (const QString &type, theseTypes) {
types.insert(type);
}
}
return types.toList();
}
void Containment::keyPressEvent(QKeyEvent *event)
{
//kDebug() << "keyPressEvent with" << event->key()
// << "and hoping and wishing for a" << Qt::Key_Tab;
if (event->key() == Qt::Key_Tab) { // && event->modifiers() == 0) {
if (!d->applets.isEmpty()) {
#ifndef NDEBUG
kDebug() << "let's give focus to...." << (QObject*)d->applets.first();
#endif
d->applets.first()->setFocus(Qt::TabFocusReason);
}
}
}
void Containment::wheelEvent(QWheelEvent *event)
{
event->ignore();
QString trigger = ContainmentActions::eventToString(event);
if (d->prepareContainmentActions(trigger, event->globalPos())) {
if (event->delta() > 0) {
d->actionPlugins()->value(trigger)->performNext();
} else {
d->actionPlugins()->value(trigger)->performPrevious();
}
event->accept();
}
}
void Containment::enableAction(const QString &name, bool enable)
{
QAction *action = this->action(name);
if (action) {
action->setEnabled(enable);
action->setVisible(enable);
}
}
void Containment::addToolBoxAction(QAction *action)
{
d->toolBoxActions << action;
}
void Containment::removeToolBoxAction(QAction *action)
{
d->toolBoxActions.removeAll(action);
}
void Containment::addAssociatedWidget(QWidget *widget)
{
//TODO: move this whole method in the c++ part of the QML implementation
Applet::addAssociatedWidget(widget);
/*if (d->focusedApplet) {
d->focusedApplet->addAssociatedWidget(widget);
}*/
foreach (const Applet *applet, d->applets) {
if (applet->d->activationAction) {
widget->addAction(applet->d->activationAction);
}
}
}
void Containment::removeAssociatedWidget(QWidget *widget)
{
//TODO: move this whole method in the c++ part of the QML implementation
Applet::removeAssociatedWidget(widget);
/*if (d->focusedApplet) {
d->focusedApplet->removeAssociatedWidget(widget);
}*/
foreach (const Applet *applet, d->applets) {
if (applet->d->activationAction) {
widget->removeAction(applet->d->activationAction);
}
}
}
void Containment::setDrawWallpaper(bool drawWallpaper)
{
d->drawWallpaper = drawWallpaper;
}
bool Containment::drawWallpaper()
{
return d->drawWallpaper;
}
void Containment::setWallpaper(const QString &pluginName, const QString &mode)
{
KConfigGroup cfg = config();
bool newPlugin = pluginName != d->wallpaper;
bool newMode = mode != d->wallpaperMode;
if (newPlugin || newMode) {
d->wallpaper = pluginName;
d->wallpaperMode = mode;
if (newMode) {
cfg.writeEntry("wallpaperpluginmode", mode);
}
if (newPlugin) {
cfg.writeEntry("wallpaperplugin", pluginName);
}
emit configNeedsSaving();
}
}
QString Containment::wallpaper() const
{
return d->wallpaper;
}
QString Containment::wallpaperMode() const
{
return d->wallpaperMode;
}
void Containment::setContainmentActions(const QString &trigger, const QString &pluginName)
{
KConfigGroup cfg = containmentActionsConfig();
ContainmentActions *plugin = 0;
if (d->actionPlugins()->contains(trigger)) {
plugin = d->actionPlugins()->value(trigger);
if (plugin->pluginName() != pluginName) {
d->actionPlugins()->remove(trigger);
delete plugin;
plugin = 0;
}
}
if (pluginName.isEmpty()) {
cfg.deleteEntry(trigger);
} else if (plugin) {
// it already existed, reset the containment so it wil reload config on next show
plugin->setContainment(0);
} else {
switch (d->containmentActionsSource) {
case ContainmentPrivate::Activity:
//FIXME
case ContainmentPrivate::Local:
plugin = PluginLoader::self()->loadContainmentActions(this, pluginName);
break;
default:
plugin = PluginLoader::self()->loadContainmentActions(0, pluginName);
}
if (plugin) {
cfg.writeEntry(trigger, pluginName);
d->actionPlugins()->insert(trigger, plugin);
} else {
//bad plugin... gets removed. is this a feature or a bug?
cfg.deleteEntry(trigger);
}
}
emit configNeedsSaving();
}
QStringList Containment::containmentActionsTriggers()
{
return d->actionPlugins()->keys();
}
QString Containment::containmentActions(const QString &trigger)
{
ContainmentActions *c = d->actionPlugins()->value(trigger);
return c ? c->pluginName() : QString();
}
void Containment::setActivity(const QString &activityId)
{
if (activityId.isEmpty()) {
return;
}
d->activityId = activityId;
KConfigGroup c = config();
c.writeEntry("activityId", activityId);
emit configNeedsSaving();
}
QString Containment::activity() const
{
return d->activityId;
}
void Containment::destroy()
{
destroy(true);
}
void Containment::showConfigurationInterface()
{
Applet::showConfigurationInterface();
}
void Containment::destroy(bool confirm)
{
if (immutability() != Mutable || Applet::d->transient) {
return;
}
if (isContainment() && confirm) {
//FIXME: should not be blocking
const QString title = i18nc("@title:window %1 is the name of the containment", "Remove %1", name());
KGuiItem remove = KStandardGuiItem::remove();
remove.setText(title);
//FIXME: make the view accessible?
if (KMessageBox::warningContinueCancel(0/*view()*/,
i18nc("%1 is the name of the containment", "Do you really want to remove this %1?", name()),
title, remove) != KMessageBox::Continue) {
return;
}
}
Applet::destroy();
}
KConfigGroup Containment::containmentActionsConfig()
{
KConfigGroup cfg;
switch (d->containmentActionsSource) {
case ContainmentPrivate::Local:
cfg = config();
cfg = KConfigGroup(&cfg, "ActionPlugins");
break;
case ContainmentPrivate::Activity:
cfg = KConfigGroup(corona()->config(), "Activities");
cfg = KConfigGroup(&cfg, d->activityId);
cfg = KConfigGroup(&cfg, "ActionPlugins");
break;
default:
cfg = KConfigGroup(corona()->config(), "ActionPlugins");
}
return cfg;
}
} // Plasma namespace
#include "moc_containment.cpp"

540
plasma/containment.h Normal file
View File

@ -0,0 +1,540 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CONTAINMENT_H
#define PLASMA_CONTAINMENT_H
#include <QObject>
#include <QWidget>
#include <kplugininfo.h>
#include <ksharedconfig.h>
#include <plasma/applet.h>
namespace Plasma
{
class AccessAppletJob;
class AppletHandle;
class DataEngine;
class Package;
class Corona;
class View;
class Wallpaper;
class ContainmentActions;
class ContainmentPrivate;
class AbstractToolBox;
/**
* @class Containment plasma/containment.h <Plasma/Containment>
*
* @short The base class for plugins that provide backgrounds and applet grouping containers
*
* Containment objects provide the means to group applets into functional sets.
* They also provide the following:
*
* creation of focussing event
* - drawing of the background image (which can be interactive)
* - form factors (e.g. panel, desktop, full screen, etc)
* - applet layout management
*
* Since containment is actually just a Plasma::Applet, all the techniques used
* for writing the visual presentation of Applets is applicable to Containtments.
* Containments are differentiated from Applets by being marked with the ServiceType
* of Plasma/Containment. Plugins registered with both the Applet and the Containment
* ServiceTypes can be loaded for us in either situation.
*
* See techbase.kde.org for a tutorial on writing Containments using this class.
*/
class PLASMA_EXPORT Containment : public Applet
{
Q_OBJECT
public:
enum Type {
NoContainmentType = -1, /**< @internal */
DesktopContainment = 0, /**< A desktop containment */
PanelContainment, /**< A desktop panel */
CustomContainment = 127, /**< A containment that is neither a desktop nor a panel
but something application specific */
CustomPanelContainment = 128 /**< A customized desktop panel */
};
enum ToolType {
AddTool = 0,
ConfigureTool = 100,
ControlTool = 200,
MiscTool = 300,
DestructiveTool = 400,
UserToolType = DestructiveTool + 1000
};
Q_ENUMS(ToolType)
/**
* @param parent the QObject this applet is parented to
* @param serviceId the name of the .desktop file containing the
* information about the widget
* @param containmentId a unique id used to differentiate between multiple
* instances of the same Applet type
*/
explicit Containment(QObject *parent = 0,
const QString &serviceId = QString(),
uint containmentId = 0);
/**
* This constructor is to be used with the plugin loading systems
* found in KPluginInfo and KService. The argument list is expected
* to have two elements: the KService service ID for the desktop entry
* and an applet ID which must be a base 10 number.
*
* @param parent a QObject parent; you probably want to pass in 0
* @param args a list of strings containing two entries: the service id
* and the applet id
*/
Containment(QObject *parent, const QVariantList &args);
~Containment();
/**
* Reimplemented from Applet
*/
void init();
/**
* Returns the type of containment
*/
Type containmentType() const;
/**
* Returns the Corona (if any) that this Containment is hosted by
*/
Corona *corona() const;
/**
* Returns a list of all known containments.
*
* @param category Only containments matching this category will be returned.
* Useful in conjunction with knownCategories.
* If "Miscellaneous" is passed in, then applets without a
* Categories= entry are also returned.
* If an empty string is passed in, all applets are
* returned.
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of applets
**/
static KPluginInfo::List listContainments(const QString &category = QString(),
const QString &parentApp = QString());
/**
* Returns a list of all known Containments that match the parameters.
*
* @param type Only Containments with this string in X-Plasma-ContainmentCategories
* in their .desktop files will be returned. Common values are panel and
* desktop
* @param category Only applets matchin this category will be returned.
* Useful in conjunction with knownCategories.
* If "Miscellaneous" is passed in, then applets without a
* Categories= entry are also returned.
* If an empty string is passed in, all applets are
* returned.
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of applets
**/
static KPluginInfo::List listContainmentsOfType(const QString &type,
const QString &category = QString(),
const QString &parentApp = QString());
/**
* @return a list of all known types of Containments on this system
*/
static QStringList listContainmentTypes();
/**
* Returns a list of all known applets associated with a certain MimeType
*
* @return list of applets
**/
static KPluginInfo::List listContainmentsForMimeType(const QString &mimeType);
/**
* Adds an applet to this Containment
*
* @param name the plugin name for the applet, as given by
* KPluginInfo::pluginName()
* @param args argument list to pass to the plasmoid
* @param geometry where to place the applet, or to auto-place it if an invalid
* is provided
*
* @return a pointer to the applet on success, or 0 on failure
*/
Applet *addApplet(const QString &name, const QVariantList &args = QVariantList(),
const QRectF &geometry = QRectF(-1, -1, -1, -1));
/**
* Add an existing applet to this Containment
*
* If dontInit is true, the pending constraints are not flushed either.
* So it is your responsibility to call both init() and
* flushPendingConstraints() on the applet.
*
* @param applet the applet that should be added
* @param pos the containment-relative position
* @param dontInit if true, init() will not be called on the applet
*/
void addApplet(Applet *applet, const QPointF &pos = QPointF(-1, -1), bool dontInit = true);
/**
* @return the applets currently in this Containment
*/
Applet::List applets() const;
/**
* Removes all applets from this Containment
*/
void clearApplets();
/**
* Sets the physical screen this Containment is associated with.
*
* @param screen the screen number this containment is the desktop for, or -1
* if it is not serving as the desktop for any screen
* @param desktop the virtual desktop to also associate this this screen with
*/
void setScreen(int screen, int desktop = -1);
/**
* @return the screen number this containment is serving as the desktop for
* or -1 if none
*/
int screen() const;
/**
* @return the last screen number this containment had
* only returns -1 if it's never ever been on a screen
* @since 4.5
*/
int lastScreen() const;
/**
* @return the viewport (e.g. virtual desktop) this Containment is associated with.
*/
int desktop() const;
/**
* @return the viewport (e.g. virtual desktop) this Containment was associated with
* last time it had a screen
* @since 4.5
*/
int lastDesktop() const;
/**
* @reimp
* @sa Applet::save(KConfigGroup &)
*/
void save(KConfigGroup &group) const;
/**
* @reimp
* @sa Applet::restore(KConfigGroup &)
*/
void restore(KConfigGroup &group);
/**
* convenience function - enables or disables an action by name
*
* @param name the name of the action in our collection
* @param enable true to enable, false to disable
*/
void enableAction(const QString &name, bool enable);
/**
* Add an action to the toolbox
*/
void addToolBoxAction(QAction *action);
/**
* Remove an action from the toolbox
*/
void removeToolBoxAction(QAction *action);
/**
* associate actions with this widget, including ones added after this call.
* needed to make keyboard shortcuts work.
*/
void addAssociatedWidget(QWidget *widget);
/**
* un-associate actions from this widget, including ones added after this call.
* needed to make keyboard shortcuts work.
*/
void removeAssociatedWidget(QWidget *widget);
/**
* Return whether wallpaper is painted or not.
*/
bool drawWallpaper();
/**
* Sets wallpaper plugin.
*
* @param pluginName the name of the wallpaper to attempt to load
* @param mode optional mode or the wallpaper plugin (e.g. "Slideshow").
* These values are pugin specific and enumerated in the plugin's
* .desktop file.
*/
void setWallpaper(const QString &pluginName, const QString &mode = QString());
/**
* Return wallpaper plugin.
*/
QString wallpaper() const;
/**
* Return wallpaper rendering mode.
*/
QString wallpaperMode() const;
/**
* Sets the current activity by id
*
* @param activity the id of the activity
*/
void setActivity(const QString &activityId);
/**
* @return the current activity id associated with this containment
*/
QString activity() const;
/**
* Shows the context menu for the containment directly, bypassing Applets
* altogether.
*/
void showContextMenu(const QPointF &containmentPos, const QPoint &screenPos);
/**
* Shows a visual clue for drag and drop
* The default implementation does nothing,
* reimplement in containments that need it
*
* @param pos point where to show the drop target; if an invalid point is passed in
* the drop zone should not be shown
*/
virtual void showDropZone(const QPoint pos);
/**
* Sets a containmentactions plugin.
*
* @param trigger the mouse button (and optional modifier) to associate the plugin with
* @param pluginName the name of the plugin to attempt to load. blank = set no plugin.
* @since 4.4
*/
void setContainmentActions(const QString &trigger, const QString &pluginName);
/**
* @return a list of all triggers that have a containmentactions plugin associated
* @since 4.4
*/
QStringList containmentActionsTriggers();
/**
* @return the plugin name for the given trigger
* @since 4.4
*/
QString containmentActions(const QString &trigger);
/**
* @return the config group that containmentactions plugins go in
* @since 4.6
*/
KConfigGroup containmentActionsConfig();
Q_SIGNALS:
/**
* This signal is emitted when a new applet is created by the containment
*/
void appletAdded(Plasma::Applet *applet, const QPointF &pos);
/**
* This signal is emitted when an applet is destroyed
*/
void appletRemoved(Plasma::Applet *applet);
/**
* Emitted when the user clicks on the toolbox
*/
void toolBoxToggled();
/**
* Emitted when the toolbox is hidden or shown
* @since 4.3
*/
void toolBoxVisibilityChanged(bool);
/**
* Emitted when the containment wants a new containment to be created.
* Usually only used for desktop containments.
*/
void addSiblingContainment(Plasma::Containment *);
/**
* Emitted when the containment requests an add widgets dialog is shown.
* Usually only used for desktop containments.
*
* @param pos where in the containment this request was made from, or
* an invalid position (QPointF()) is not location specific
*/
void showAddWidgetsInterface(const QPointF &pos);
/**
* This signal indicates that a containment has been newly
* associated (or dissociated) with a physical screen.
*
* @param wasScreen the screen it was associated with
* @param isScreen the screen it is now associated with
* @param containment the containment switching screens
*/
void screenChanged(int wasScreen, int isScreen, Plasma::Containment *containment);
/**
* Emitted when the user wants to configure/change containment.
*/
void configureRequested(Plasma::Containment *containment);
public Q_SLOTS:
/**
* Informs the Corona as to what position it is in. This is informational
* only, as the Corona doesn't change its actual location. This is,
* however, passed on to Applets that may be managed by this Corona.
*
* @param location the new location of this Corona
*/
void setLocation(Plasma::Location location);
/**
* Sets the form factor for this Containment. This may cause changes in both
* the arrangement of Applets as well as the display choices of individual
* Applets.
*/
void setFormFactor(Plasma::FormFactor formFactor);
/**
* Tells the corona to create a new desktop containment
*/
void addSiblingContainment();
/**
* Destroys this containment and all its applets (after a confirmation dialog);
* it will be removed nicely and deleted.
* Its configuration will also be deleted.
*/
void destroy();
/**
* Destroys this containment and all its applets (after a confirmation dialog);
* it will be removed nicely and deleted.
* Its configuration will also be deleted.
*
* @param confirm whether or not confirmation from the user should be requested
*/
void destroy(bool confirm);
/**
* @reimp
* @sa Applet::showConfigurationInterface()
*/
void showConfigurationInterface();
/**
* Sets the type of this containment.
*/
void setContainmentType(Containment::Type type);
/**
* Sets whether wallpaper is painted or not.
*/
void setDrawWallpaper(bool drawWallpaper);
protected:
/**
* Called when the contents of the containment should be saved. By default this saves
* all loaded Applets
*
* @param group the KConfigGroup to save settings under
*/
virtual void saveContents(KConfigGroup &group) const;
/**
* Called when the contents of the containment should be loaded. By default this loads
* all previously saved Applets
*
* @param group the KConfigGroup to save settings under
*/
virtual void restoreContents(KConfigGroup &group);
//FIXME: events should go away
void contextMenuEvent(QContextMenuEvent *event);
void keyPressEvent(QKeyEvent *event);
void wheelEvent(QWheelEvent *event);
private:
/**
* @internal This constructor is to be used with the Package loading system.
*
* @param parent a QObject parent; you probably want to pass in 0
* @param args a list of strings containing two entries: the service id
* and the applet id
* @since 4.3
*/
Containment(const QString &packagePath, uint appletId, const QVariantList &args);
Q_PRIVATE_SLOT(d, void appletDeleted(Plasma::Applet*))
Q_PRIVATE_SLOT(d, void triggerShowAddWidgets())
Q_PRIVATE_SLOT(d, void requestConfiguration())
Q_PRIVATE_SLOT(d, void checkStatus(Plasma::ItemStatus))
friend class Applet;
friend class AppletPrivate;
friend class CoronaPrivate;
friend class CoronaBasePrivate;
friend class ContainmentPrivate;
friend class ContainmentActions;
friend class PopupApplet;
friend class View;
ContainmentPrivate *const d;
};
} // Plasma namespace
#endif // multiple inclusion guard

View File

@ -0,0 +1,221 @@
/*
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "containmentactions.h"
#include "containment.h"
#include "private/packages_p.h"
#include "private/containmentactions_p.h"
#include "private/containment_p.h"
#include <QMetaEnum>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QContextMenuEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <kdebug.h>
#include <klocalizedstring.h>
#include <kservicetypetrader.h>
#include "dataengineconsumer.h"
#include "version.h"
namespace Plasma
{
ContainmentActions::ContainmentActions(QObject * parentObject)
: d(new ContainmentActionsPrivate(KService::serviceByStorageId(QString()), this))
{
setParent(parentObject);
}
ContainmentActions::ContainmentActions(QObject *parentObject, const QVariantList &args)
: d(new ContainmentActionsPrivate(KService::serviceByStorageId(args.count() > 0 ?
args[0].toString() : QString()), this))
{
// now remove first item since those are managed by Wallpaper and subclasses shouldn't
// need to worry about them. yes, it violates the constness of this var, but it lets us add
// or remove items later while applets can just pretend that their args always start at 0
QVariantList &mutableArgs = const_cast<QVariantList &>(args);
if (!mutableArgs.isEmpty()) {
mutableArgs.removeFirst();
}
setParent(parentObject);
}
ContainmentActions::~ContainmentActions()
{
delete d;
}
Containment *ContainmentActions::containment()
{
if (d->containment) {
return d->containment;
}
return qobject_cast<Containment*>(parent());
}
QString ContainmentActions::name() const
{
if (!d->containmentActionsDescription.isValid()) {
return i18n("Unknown ContainmentActions");
}
return d->containmentActionsDescription.name();
}
QString ContainmentActions::icon() const
{
if (!d->containmentActionsDescription.isValid()) {
return QString();
}
return d->containmentActionsDescription.icon();
}
QString ContainmentActions::pluginName() const
{
if (!d->containmentActionsDescription.isValid()) {
return QString();
}
return d->containmentActionsDescription.pluginName();
}
void ContainmentActions::restore(const KConfigGroup &config)
{
init(config);
}
void ContainmentActions::init(const KConfigGroup &config)
{
Q_UNUSED(config);
}
void ContainmentActions::save(KConfigGroup &config)
{
Q_UNUSED(config);
}
QWidget *ContainmentActions::createConfigurationInterface(QWidget *parent)
{
Q_UNUSED(parent);
return 0;
}
void ContainmentActions::configurationAccepted()
{
//do nothing by default
}
QAction *ContainmentActions::triggerableContextAction()
{
return 0;
}
void ContainmentActions::performNext()
{
}
void ContainmentActions::performPrevious()
{
}
QList<QAction*> ContainmentActions::contextualActions()
{
return QList<QAction*>();
}
DataEngine *ContainmentActions::dataEngine(const QString &name) const
{
return d->dataEngine(name);
}
bool ContainmentActions::configurationRequired() const
{
return d->needsConfig;
}
void ContainmentActions::setConfigurationRequired(bool needsConfig)
{
if (d->needsConfig != needsConfig) {
d->needsConfig = needsConfig;
emit configurationRequiredChanged();
}
}
QString ContainmentActions::eventToString(QEvent *event)
{
QString trigger;
Qt::KeyboardModifiers modifiers;
switch (event->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
{
QMouseEvent *e = static_cast<QMouseEvent*>(event);
int m = QObject::staticQtMetaObject.indexOfEnumerator("MouseButtons");
QMetaEnum mouse = QObject::staticQtMetaObject.enumerator(m);
trigger += mouse.valueToKey(e->button());
modifiers = e->modifiers();
break;
}
case QEvent::Wheel:
{
QWheelEvent *e = static_cast<QWheelEvent*>(event);
int o = QObject::staticQtMetaObject.indexOfEnumerator("Orientations");
QMetaEnum orient = QObject::staticQtMetaObject.enumerator(o);
trigger = "wheel:";
trigger += orient.valueToKey(e->orientation());
modifiers = e->modifiers();
break;
}
case QEvent::ContextMenu:
{
int m = QObject::staticQtMetaObject.indexOfEnumerator("MouseButtons");
QMetaEnum mouse = QObject::staticQtMetaObject.enumerator(m);
trigger = mouse.valueToKey(Qt::RightButton);
modifiers = Qt::NoModifier;
break;
}
default:
return QString();
}
int k = QObject::staticQtMetaObject.indexOfEnumerator("KeyboardModifiers");
QMetaEnum kbd = QObject::staticQtMetaObject.enumerator(k);
trigger += ';';
trigger += kbd.valueToKeys(modifiers);
return trigger;
}
void ContainmentActions::setContainment(Containment *newContainment) {
d->containment = newContainment;
}
} // Plasma namespace
#include "moc_containmentactions.cpp"

234
plasma/containmentactions.h Normal file
View File

@ -0,0 +1,234 @@
/*
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CONTAINMENTACTIONS_H
#define PLASMA_CONTAINMENTACTIONS_H
#include <QList>
#include <kplugininfo.h>
#include <plasma/plasma.h>
#include <plasma/version.h>
class QAction;
namespace Plasma
{
class DataEngine;
class Containment;
class ContainmentActionsPrivate;
/**
* @class ContainmentActions plasma/containmentactions.h <Plasma/ContainmentActions>
*
* @short The base ContainmentActions class
*
* "ContainmentActions" are components that provide actions (usually displaying a contextmenu) in
* response to an event with a position (usually a mouse event).
*
* ContainmentActions plugins are registered using .desktop files. These files should be
* named using the following naming scheme:
*
* plasma-containmentactions-\<pluginname\>.desktop
*
*/
class PLASMA_EXPORT ContainmentActions : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString pluginName READ pluginName CONSTANT)
Q_PROPERTY(QString icon READ icon CONSTANT)
Q_PROPERTY(bool configurationRequired READ configurationRequired NOTIFY configurationRequiredChanged)
public:
/**
* Default constructor for an empty or null containmentactions
*/
explicit ContainmentActions(QObject * parent = 0);
~ContainmentActions();
/**
* Returns the user-visible name for the containmentactions, as specified in the
* .desktop file.
*
* @return the user-visible name for the containmentactions.
**/
QString name() const;
/**
* Returns the plugin name for the containmentactions
*/
QString pluginName() const;
/**
* Returns the icon related to this containmentactions
**/
QString icon() const;
/**
* This method should be called once the plugin is loaded or settings are changed.
* @param config Config group to load settings
* @see init
**/
void restore(const KConfigGroup &config);
/**
* This method is called when settings need to be saved.
* @param config Config group to save settings
**/
virtual void save(KConfigGroup &config);
/**
* Returns the widget used in the configuration dialog.
* Add the configuration interface of the containmentactions to this widget.
*/
virtual QWidget *createConfigurationInterface(QWidget *parent);
/**
* This method is called when the user's configuration changes are accepted
*/
virtual void configurationAccepted();
/**
* @return the action that is to be immediately triggered when this plugin is
* activated for a context action, or NULL if there is no such action
* @see contextualActions
*/
virtual QAction *triggerableContextAction();
/**
* Called when a "next" action is triggered (e.g. by mouse wheel scroll). This
* can be used to scroll through a list of items this plugin manages such as
* windows, virtual desktops, activities, etc.
* @see performPrevious
*/
virtual void performNext();
/**
* Called when a "previous" action is triggered (e.g. by mouse wheel scroll). This
* can be used to scroll through a list of items this plugin manages such as
* windows, virtual desktops, activities, etc.
* @see performNext
*/
virtual void performPrevious();
/**
* Implement this to provide a list of actions that can be added to another menu
* for example, when right-clicking an applet, the "Activity Options" submenu is populated
* with this.
*/
Q_INVOKABLE virtual QList<QAction*> contextualActions();
/**
* Loads the given DataEngine
*
* Tries to load the data engine given by @p name. Each engine is
* only loaded once, and that instance is re-used on all subsequent
* requests.
*
* If the data engine was not found, an invalid data engine is returned
* (see DataEngine::isValid()).
*
* Note that you should <em>not</em> delete the returned engine.
*
* @param name Name of the data engine to load
* @return pointer to the data engine if it was loaded,
* or an invalid data engine if the requested engine
* could not be loaded
*
*/
DataEngine *dataEngine(const QString &name) const;
/**
* @return true if the containmentactions currently needs to be configured,
* otherwise, false
*/
bool configurationRequired() const;
/**
* Turns a mouse or wheel event into a string suitable for a ContainmentActions
* @return the string representation of the event
*/
static QString eventToString(QEvent *event);
/**
* @p newContainment the containment the plugin should be associated with.
* @since 4.6
*/
void setContainment(Containment *newContainment);
/**
* @return the containment the plugin is associated with.
*/
Containment *containment();
Q_SIGNALS:
/**
* Emitted when @see configurationRequired() changes
*/
void configurationRequiredChanged();
protected:
/**
* This constructor is to be used with the plugin loading systems
* found in KPluginInfo and KService. The argument list is expected
* to have one element: the KService service ID for the desktop entry.
*
* @param parent a QObject parent; you probably want to pass in 0
* @param args a list of strings containing one entry: the service id
*/
ContainmentActions(QObject *parent, const QVariantList &args);
/**
* This method is called once the containmentactions is loaded or settings are changed.
*
* @param config Config group to load settings
**/
virtual void init(const KConfigGroup &config);
/**
* When the containmentactions needs to be configured before being usable, this
* method can be called to denote that action is required
*
* @param needsConfiguring true if the applet needs to be configured,
* or false if it doesn't
*/
void setConfigurationRequired(bool needsConfiguring = true);
private:
friend class ContainmentActionsPackage;
friend class ContainmentActionsPrivate;
ContainmentActionsPrivate *const d;
};
} // Plasma namespace
/**
* Register a containmentactions when it is contained in a loadable module
*/
#define K_EXPORT_PLASMA_CONTAINMENTACTIONS(libname, classname) \
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN(factory("plasma_containmentactions_" #libname)) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
#endif // PLASMA_CONTAINMENTACTIONS_H

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "containmentactionspluginsconfig.h"
#include "private/containmentactionspluginsconfig_p.h"
#include <QHash>
#include <QEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QString>
#include <kdebug.h>
#include "containmentactions.h"
using namespace Plasma;
namespace Plasma
{
ContainmentActionsPluginsConfig::ContainmentActionsPluginsConfig()
: d(new ContainmentActionsPluginsConfigPrivate(this))
{
}
ContainmentActionsPluginsConfig::ContainmentActionsPluginsConfig(const ContainmentActionsPluginsConfig &other)
: d(new ContainmentActionsPluginsConfigPrivate(this))
{
d->plugins = other.d->plugins;
}
ContainmentActionsPluginsConfig& ContainmentActionsPluginsConfig::operator=(const ContainmentActionsPluginsConfig &other)
{
d->plugins = other.d->plugins;
return *this;
}
ContainmentActionsPluginsConfig::~ContainmentActionsPluginsConfig()
{
delete d;
}
void ContainmentActionsPluginsConfig::clear()
{
d->plugins.clear();
}
void ContainmentActionsPluginsConfig::remove(QEvent *trigger)
{
QString s = ContainmentActions::eventToString(trigger);
d->plugins.remove(s);
}
void ContainmentActionsPluginsConfig::addPlugin(QEvent *trigger, const QString &name)
{
QString s = ContainmentActions::eventToString(trigger);
d->plugins.insert(s, name);
}
void ContainmentActionsPluginsConfig::addPlugin(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, const QString &name)
{
QMouseEvent event(QEvent::MouseButtonPress, QPoint(), button, button, modifiers);
QString s = ContainmentActions::eventToString(&event);
d->plugins.insert(s, name);
}
void ContainmentActionsPluginsConfig::addPlugin(Qt::KeyboardModifiers modifiers, Qt::Orientation wheelDirection, const QString &name)
{
//most of those parameters are just fillers
QWheelEvent event(QPoint(0,0), 0, Qt::NoButton, modifiers, wheelDirection);
QString s = ContainmentActions::eventToString(&event);
d->plugins.insert(s, name);
}
} // namespace Plasma

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CONTAINMENTACTIONSPLUGINSCONFIG_H
#define PLASMA_CONTAINMENTACTIONSPLUGINSCONFIG_H
#include <plasma/plasma_export.h>
#include <Qt>
class QString;
class QEvent;
namespace Plasma
{
class ContainmentActionsPluginsConfigPrivate;
/**
* @class ContainmentActionsPluginsConfig plasma/containmentactionspluginsconfig.h <Plasma/ContainmentActionsPluginsConfig>
*
* @short A class that holds a map of triggers to plugin names
* @since 4.4
*/
class PLASMA_EXPORT ContainmentActionsPluginsConfig
{
public:
ContainmentActionsPluginsConfig();
ContainmentActionsPluginsConfig(const ContainmentActionsPluginsConfig &other);
~ContainmentActionsPluginsConfig();
ContainmentActionsPluginsConfig& operator=(const ContainmentActionsPluginsConfig &other);
/**
* clears everything
*/
void clear();
/**
* removes @p trigger
* @see addPlugin for an explanation of the @p trigger
*/
void remove(QEvent *trigger);
/**
* Sets @p trigger to plugin @p name
* if you're passing the trigger as an event, the following events are currently understood:
* -mouse press and release events: button and modifiers
* -mouse wheel events: direction and modifiers
* both traditional and graphicsscene events are supported.
*/
void addPlugin(QEvent *trigger, const QString &name);
/**
* Sets trigger described by @p modifiers and @p button to plugin @p name
*/
void addPlugin(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, const QString &name);
/**
* Sets trigger described by @p modifiers and @p wheelDirection to plugin @p name
*/
void addPlugin(Qt::KeyboardModifiers modifiers, Qt::Orientation wheelDirection, const QString &name);
private:
ContainmentActionsPluginsConfigPrivate *const d;
friend class ContainmentActionsPluginsConfigPrivate;
friend class Containment;
};
} // namespace Plasma
#endif

742
plasma/corona.cpp Normal file
View File

@ -0,0 +1,742 @@
/*
* Copyright 2007 Matt Broadstone <mbroadst@gmail.com>
* Copyright 2007-2011 Aaron Seigo <aseigo@kde.org>
* Copyright 2007 Riccardo Iaconelli <riccardo@kde.org>
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "corona.h"
#include "private/corona_p.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QGraphicsGridLayout>
#include <QMimeData>
#include <QPainter>
#include <QTimer>
#include <cmath>
#include <kaction.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klocalizedstring.h>
#include <kshortcutsdialog.h>
#include <kwindowsystem.h>
#include "abstractdialogmanager.h"
#include "containment.h"
#include "containmentactionspluginsconfig.h"
#include "pluginloader.h"
#include "private/applet_p.h"
#include "private/containment_p.h"
using namespace Plasma;
namespace Plasma
{
bool CoronaPrivate::s_positioningContainments = false;
Corona::Corona(QObject *parent)
: QObject(parent),
d(new CoronaPrivate(this))
{
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Corona ctor start";
#endif
d->init();
//setViewport(new QGLWidget(QGLFormat(QGL::StencilBuffer | QGL::AlphaChannel)));
}
Corona::~Corona()
{
KConfigGroup trans(KSharedConfig::openConfig(), "PlasmaTransientsConfig");
trans.deleteGroup();
delete d;
}
void Corona::setAppletMimeType(const QString &type)
{
d->mimetype = type;
}
QString Corona::appletMimeType()
{
return d->mimetype;
}
void Corona::setDefaultContainmentPlugin(const QString &name)
{
// we could check if it is in:
// Containment::listContainments().contains(name) ||
// Containment::listContainments(QString(), QCoreApplication::instance()->applicationName()).contains(name)
// but that seems like overkill
d->defaultContainmentPlugin = name;
}
QString Corona::defaultContainmentPlugin() const
{
return d->defaultContainmentPlugin;
}
void Corona::saveLayout(const QString &configName) const
{
KSharedConfigPtr c;
if (configName.isEmpty() || configName == d->configName) {
c = config();
} else {
c = KSharedConfig::openConfig(configName, KConfig::SimpleConfig);
}
d->saveLayout(c);
}
void Corona::exportLayout(KConfigGroup &config, QList<Containment*> containments)
{
foreach (const QString &group, config.groupList()) {
KConfigGroup cg(&config, group);
cg.deleteGroup();
}
//temporarily unlock so that removal works
ImmutabilityType oldImm = immutability();
d->immutability = Mutable;
KConfigGroup dest(&config, "Containments");
KConfigGroup dummy;
foreach (Plasma::Containment *c, containments) {
c->save(dummy);
c->config().reparent(&dest);
//ensure the containment is unlocked
//this is done directly because we have to bypass any SystemImmutable checks
c->Applet::d->immutability = Mutable;
foreach (Applet *a, c->applets()) {
a->d->immutability = Mutable;
}
c->destroy(false);
}
//restore immutability
d->immutability = oldImm;
config.sync();
}
void Corona::requestConfigSync()
{
// constant controlling how long between requesting a configuration sync
// and one happening should occur. currently 10 seconds
static const int CONFIG_SYNC_TIMEOUT = 10000;
// TODO: should we check into our immutability before doing this?
//NOTE: this is a pretty simplistic model: we simply save no more than CONFIG_SYNC_TIMEOUT
// after the first time this is called. not much of a heuristic for save points, but
// it should at least compress these activities a bit and provide a way for applet
// authors to ween themselves from the sync() disease. A more interesting/dynamic
// algorithm for determining when to actually sync() to disk might be better, though.
if (!d->configSyncTimer->isActive()) {
d->configSyncTimer->start(CONFIG_SYNC_TIMEOUT);
}
}
void Corona::requireConfigSync()
{
d->syncConfig();
}
void Corona::initializeLayout(const QString &configName)
{
clearContainments();
loadLayout(configName);
if (d->containments.isEmpty()) {
loadDefaultLayout();
if (!d->containments.isEmpty()) {
requestConfigSync();
}
}
if (config()->isImmutable()) {
setImmutability(SystemImmutable);
} else {
KConfigGroup coronaConfig(config(), "General");
setImmutability((ImmutabilityType)coronaConfig.readEntry("immutability", (int)Mutable));
}
}
void Corona::loadLayout(const QString &configName)
{
if (!configName.isEmpty() && configName != d->configName) {
// if we have a new config name passed in, then use that as the config file for this Corona
d->config = 0;
d->configName = configName;
}
KConfigGroup conf(config(), QString());
d->importLayout(conf, false);
}
QList<Plasma::Containment *> Corona::importLayout(const KConfigGroup &conf)
{
return d->importLayout(conf, true);
}
Containment *Corona::containmentForScreen(int screen, int desktop) const
{
foreach (Containment *containment, d->containments) {
if (containment->screen() == screen &&
(desktop < 0 || containment->desktop() == desktop) &&
(containment->containmentType() == Containment::DesktopContainment ||
containment->containmentType() == Containment::CustomContainment)) {
return containment;
}
}
return 0;
}
Containment *Corona::containmentForScreen(int screen, int desktop,
const QString &defaultPluginIfNonExistent, const QVariantList &defaultArgs)
{
Containment *containment = containmentForScreen(screen, desktop);
if (!containment && !defaultPluginIfNonExistent.isEmpty()) {
// screen requests are allowed to bypass immutability
if (screen >= 0 && screen < numScreens() &&
desktop >= -1 && desktop < KWindowSystem::numberOfDesktops()) {
containment = d->addContainment(defaultPluginIfNonExistent, defaultArgs, 0);
if (containment) {
containment->setScreen(screen, desktop);
}
}
}
return containment;
}
QList<Containment*> Corona::containments() const
{
return d->containments;
}
void Corona::clearContainments()
{
foreach (Containment *containment, d->containments) {
containment->clearApplets();
}
}
KSharedConfigPtr Corona::config() const
{
if (!d->config) {
d->config = KSharedConfig::openConfig(d->configName, KConfig::SimpleConfig);
}
return d->config;
}
Containment *Corona::addContainment(const QString &name, const QVariantList &args)
{
if (d->immutability == Mutable) {
return d->addContainment(name, args, 0);
}
return 0;
}
int Corona::numScreens() const
{
return 1;
}
QRect Corona::screenGeometry(int id) const
{
return qApp->desktop()->screenGeometry(id);
}
QRegion Corona::availableScreenRegion(int id) const
{
return QRegion(screenGeometry(id));
}
void Corona::loadDefaultLayout()
{
}
void Corona::setPreferredToolBoxPlugin(const Containment::Type type, const QString &plugin)
{
d->toolBoxPlugins[type] = plugin;
}
QString Corona::preferredToolBoxPlugin(const Containment::Type type) const
{
return d->toolBoxPlugins.value(type);
}
ImmutabilityType Corona::immutability() const
{
return d->immutability;
}
void Corona::setImmutability(const ImmutabilityType immutable)
{
if (d->immutability == immutable || d->immutability == SystemImmutable) {
return;
}
#ifndef NDEBUG
kDebug() << "setting immutability to" << immutable;
#endif
d->immutability = immutable;
d->updateContainmentImmutability();
//tell non-containments that might care (like plasmaapp or a custom corona)
emit immutabilityChanged(immutable);
//update our actions
QAction *action = d->actions.action("lock widgets");
if (action) {
if (d->immutability == SystemImmutable) {
action->setEnabled(false);
action->setVisible(false);
} else {
bool unlocked = d->immutability == Mutable;
action->setText(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets"));
action->setIcon(KDE::icon(unlocked ? "object-locked" : "object-unlocked"));
action->setEnabled(true);
action->setVisible(true);
}
}
if (d->immutability != SystemImmutable) {
KConfigGroup cg(config(), "General");
// we call the dptr member directly for locked since isImmutable()
// also checks kiosk and parent containers
cg.writeEntry("immutability", (int)d->immutability);
requestConfigSync();
}
}
QList<Plasma::Location> Corona::freeEdges(int screen) const
{
QList<Plasma::Location> freeEdges;
freeEdges << Plasma::TopEdge << Plasma::BottomEdge
<< Plasma::LeftEdge << Plasma::RightEdge;
foreach (Containment *containment, containments()) {
if (containment->screen() == screen &&
freeEdges.contains(containment->location())) {
freeEdges.removeAll(containment->location());
}
}
return freeEdges;
}
QAction *Corona::action(QString name) const
{
return d->actions.action(name);
}
void Corona::addAction(QString name, QAction *action)
{
d->actions.addAction(name, action);
}
KAction* Corona::addAction(QString name)
{
return d->actions.addAction(name);
}
QList<QAction*> Corona::actions() const
{
return d->actions.actions();
}
void Corona::enableAction(const QString &name, bool enable)
{
QAction *action = d->actions.action(name);
if (action) {
action->setEnabled(enable);
action->setVisible(enable);
}
}
void Corona::updateShortcuts()
{
QMutableListIterator<QWeakPointer<KActionCollection> > it(d->actionCollections);
while (it.hasNext()) {
it.next();
KActionCollection *collection = it.value().data();
if (!collection) {
// get rid of KActionCollections that have been deleted behind our backs
it.remove();
continue;
}
collection->readSettings();
if (d->shortcutsDlg) {
d->shortcutsDlg.data()->addCollection(collection);
}
}
}
void Corona::addShortcuts(KActionCollection *newShortcuts)
{
d->actionCollections << newShortcuts;
if (d->shortcutsDlg) {
d->shortcutsDlg.data()->addCollection(newShortcuts);
}
}
void Corona::setContainmentActionsDefaults(Containment::Type containmentType, const ContainmentActionsPluginsConfig &config)
{
d->containmentActionsDefaults.insert(containmentType, config);
}
ContainmentActionsPluginsConfig Corona::containmentActionsDefaults(Containment::Type containmentType)
{
return d->containmentActionsDefaults.value(containmentType);
}
void Corona::setDialogManager(AbstractDialogManager *dialogManager)
{
d->dialogManager = dialogManager;
}
AbstractDialogManager *Corona::dialogManager()
{
return d->dialogManager.data();
}
CoronaPrivate::CoronaPrivate(Corona *corona)
: q(corona),
immutability(Mutable),
mimetype("text/x-plasmoidservicename"),
defaultContainmentPlugin("desktop"),
config(0),
configSyncTimer(new QTimer(corona)),
delayedInitTimer(new QTimer(corona)),
actions(corona)
{
if (QCoreApplication::instance()) {
configName = QCoreApplication::instance()->applicationName() + "-appletsrc";
} else {
configName = "plasma-appletsrc";
}
}
CoronaPrivate::~CoronaPrivate()
{
qDeleteAll(containments);
}
void CoronaPrivate::init()
{
delayedInitTimer->setInterval(100);
delayedInitTimer->setSingleShot(true);
QObject::connect(delayedInitTimer, SIGNAL(timeout()), q, SLOT(delayedContainmentInit()));
configSyncTimer->setSingleShot(true);
QObject::connect(configSyncTimer, SIGNAL(timeout()), q, SLOT(syncConfig()));
//some common actions
actions.setConfigGroup("Shortcuts");
KAction *lockAction = actions.addAction("lock widgets");
QObject::connect(lockAction, SIGNAL(triggered(bool)), q, SLOT(toggleImmutability()));
lockAction->setText(i18n("Lock Widgets"));
lockAction->setAutoRepeat(true);
lockAction->setIcon(KDE::icon("object-locked"));
lockAction->setData(Containment::ControlTool);
lockAction->setShortcut(KShortcut("alt+d, l"));
lockAction->setShortcutContext(Qt::ApplicationShortcut);
//FIXME this doesn't really belong here. desktop KCM maybe?
//but should the shortcuts be per-app or really-global?
//I don't know how to make kactioncollections use plasmarc
KAction *action = actions.addAction("configure shortcuts");
QObject::connect(action, SIGNAL(triggered()), q, SLOT(showShortcutConfig()));
action->setText(i18n("Shortcut Settings"));
action->setIcon(KDE::icon("configure-shortcuts"));
action->setAutoRepeat(false);
action->setData(Containment::ConfigureTool);
//action->setShortcut(KShortcut("ctrl+h"));
action->setShortcutContext(Qt::ApplicationShortcut);
//fake containment/applet actions
KActionCollection *containmentActions = AppletPrivate::defaultActions(q); //containment has to start with applet stuff
ContainmentPrivate::addDefaultActions(containmentActions); //now it's really containment
actionCollections << &actions << AppletPrivate::defaultActions(q) << containmentActions;
q->updateShortcuts();
}
void CoronaPrivate::showShortcutConfig()
{
//show a kshortcutsdialog with the actions
KShortcutsDialog *dlg = shortcutsDlg.data();
if (!dlg) {
dlg = new KShortcutsDialog();
dlg->setModal(false);
dlg->setAttribute(Qt::WA_DeleteOnClose, true);
QObject::connect(dlg, SIGNAL(saved()), q, SIGNAL(shortcutsChanged()));
dlg->addCollection(&actions);
QMutableListIterator<QWeakPointer<KActionCollection> > it(actionCollections);
while (it.hasNext()) {
it.next();
KActionCollection *collection = it.value().data();
if (!collection) {
// get rid of KActionCollections that have been deleted behind our backs
it.remove();
continue;
}
dlg->addCollection(collection);
}
}
KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
dlg->configure();
dlg->raise();
}
void CoronaPrivate::toggleImmutability()
{
if (immutability == Mutable) {
q->setImmutability(UserImmutable);
} else {
q->setImmutability(Mutable);
}
}
void CoronaPrivate::saveLayout(KSharedConfigPtr cg) const
{
KConfigGroup containmentsGroup(cg, "Containments");
foreach (const Containment *containment, containments) {
QString cid = QString::number(containment->id());
KConfigGroup containmentConfig(&containmentsGroup, cid);
containment->save(containmentConfig);
}
}
void CoronaPrivate::updateContainmentImmutability()
{
foreach (Containment *c, containments) {
// we need to tell each containment that immutability has been altered
c->updateConstraints(ImmutableConstraint);
}
}
void CoronaPrivate::containmentDestroyed(QObject *obj)
{
// we do a static_cast here since it really isn't an Containment by this
// point anymore since we are in the qobject dtor. we don't actually
// try and do anything with it, we just need the value of the pointer
// so this unsafe looking code is actually just fine.
Containment* containment = static_cast<Plasma::Containment*>(obj);
int index = containments.indexOf(containment);
if (index > -1) {
containments.removeAt(index);
q->requestConfigSync();
}
}
void CoronaPrivate::syncConfig()
{
q->config()->sync();
emit q->configSynced();
}
Containment *CoronaPrivate::addContainment(const QString &name, const QVariantList &args, uint id)
{
QString pluginName = name;
Containment *containment = 0;
Applet *applet = 0;
//kDebug() << "Loading" << name << args << id;
if (pluginName.isEmpty() || pluginName == "default") {
// default to the desktop containment
pluginName = defaultContainmentPlugin;
}
bool loadingNull = pluginName == "null";
if (!loadingNull) {
applet = PluginLoader::self()->loadApplet(pluginName, id, args);
containment = dynamic_cast<Containment*>(applet);
if (containment) {
containment->setParent(q);
}
}
if (!containment) {
if (!loadingNull) {
#ifndef NDEBUG
kDebug() << "loading of containment" << name << "failed.";
#endif
}
// in case we got a non-Containment from Applet::loadApplet or
// a null containment was requested
if (applet) {
// the applet probably doesn't know what's hit it, so let's pretend it can be
// initialized to make assumptions in the applet's dtor safer
applet->init();
delete applet;
}
applet = containment = new Containment(q, 0, id);
if (loadingNull) {
containment->setDrawWallpaper(false);
} else {
containment->setFailedToLaunch(false);
}
// we want to provide something and don't care about the failure to launch
containment->setFormFactor(Plasma::Planar);
}
// if this is a new containment, we need to ensure that there are no stale
// configuration data around
if (id == 0) {
KConfigGroup conf(q->config(), "Containments");
conf = KConfigGroup(&conf, QString::number(containment->id()));
conf.deleteGroup();
}
applet->d->isContainment = true;
applet->d->setIsContainment(true, true);
containments.append(containment);
containmentsNeedingInit.append(containment);
delayedInitTimer->start();
QObject::connect(containment, SIGNAL(destroyed(QObject*)),
q, SLOT(containmentDestroyed(QObject*)));
QObject::connect(containment, SIGNAL(configNeedsSaving()),
q, SLOT(requestConfigSync()));
QObject::connect(containment, SIGNAL(releaseVisualFocus()),
q, SIGNAL(releaseVisualFocus()));
QObject::connect(containment, SIGNAL(screenChanged(int,int,Plasma::Containment*)),
q, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)));
return containment;
}
void CoronaPrivate::delayedContainmentInit()
{
foreach (QWeakPointer<Containment> c, containmentsNeedingInit) {
Containment *containment = c.data();
if (!containment) {
continue;
}
containment->init();
KConfigGroup cg = containment->config();
containment->restore(cg);
containment->updateConstraints(Plasma::StartupCompletedConstraint);
containment->save(cg);
q->requestConfigSync();
containment->flushPendingConstraintsEvents();
emit q->containmentAdded(containment);
}
containmentsNeedingInit.clear();
}
QList<Plasma::Containment *> CoronaPrivate::importLayout(const KConfigGroup &conf, bool mergeConfig)
{
if (!conf.isValid()) {
return QList<Containment *>();
}
QList<Plasma::Containment *> newContainments;
QSet<uint> containmentsIds;
foreach (Containment *containment, containments) {
containmentsIds.insert(containment->id());
}
KConfigGroup containmentsGroup(&conf, "Containments");
foreach (const QString &group, containmentsGroup.groupList()) {
KConfigGroup containmentConfig(&containmentsGroup, group);
if (containmentConfig.entryMap().isEmpty()) {
continue;
}
uint cid = group.toUInt();
if (containmentsIds.contains(cid)) {
cid = ++AppletPrivate::s_maxAppletId;
} else if (cid > AppletPrivate::s_maxAppletId) {
AppletPrivate::s_maxAppletId = cid;
}
if (mergeConfig) {
KConfigGroup realConf(q->config(), "Containments");
realConf = KConfigGroup(&realConf, QString::number(cid));
// in case something was there before us
realConf.deleteGroup();
containmentConfig.copyTo(&realConf);
}
//kDebug() << "got a containment in the config, trying to make a" << containmentConfig.readEntry("plugin", QString()) << "from" << group;
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Adding Containment" << containmentConfig.readEntry("plugin", QString());
#endif
Containment *c = addContainment(containmentConfig.readEntry("plugin", QString()), QVariantList(), cid);
if (!c) {
continue;
}
newContainments.append(c);
containmentsIds.insert(c->id());
c->init();
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Init Containment" << c->pluginName();
#endif
c->restore(containmentConfig);
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Restored Containment" << c->pluginName();
#endif
}
foreach (Containment *containment, newContainments) {
containment->updateConstraints(Plasma::StartupCompletedConstraint);
containment->d->initApplets();
emit q->containmentAdded(containment);
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Containment" << containment->name();
#endif
}
return newContainments;
}
} // namespace Plasma
#include "moc_corona.cpp"

404
plasma/corona.h Normal file
View File

@ -0,0 +1,404 @@
/*
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
* Copyright 2007 Matt Broadstone <mbroadst@gmail.com>
* Copyright 2012 Marco MArtin <mart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CORONABASE_H
#define PLASMA_CORONABASE_H
#include <plasma/containment.h>
#include <plasma/plasma.h>
#include <plasma/plasma_export.h>
class QAction;
class KAction;
namespace Plasma
{
class CoronaPrivate;
class ContainmentActionsPluginsConfig;
class AbstractDialogManager;
/**
* @class CoronaBase plasma/CoronaBase.h <Plasma/CoronaBase>
*
* @short A bookkeeping Scene for Plasma::Applets
*/
class PLASMA_EXPORT Corona : public QObject
{
Q_OBJECT
public:
explicit Corona(QObject * parent = 0);
~Corona();
/**
* Sets the mimetype of Drag/Drop items. Default is
* text/x-plasmoidservicename
*/
void setAppletMimeType(const QString &mimetype);
/**
* The current mime type of Drag/Drop items.
*/
QString appletMimeType();
/**
* @return the default containment plugin type
* @since 4.7
*/
QString defaultContainmentPlugin() const;
/**
* @return all containments on this CoronaBase
*/
QList<Containment*> containments() const;
/**
* Clear the CoronaBase from all applets.
*/
void clearContainments();
/**
* Returns the config file used to store the configuration for this CoronaBase
*/
KSharedConfig::Ptr config() const;
/**
* Adds a Containment to the CoronaBase
*
* @param name the plugin name for the containment, as given by
* KPluginInfo::pluginName(). If an empty string is passed in, the default
* containment plugin will be used (usually DesktopContainment). If the
* string literal "null" is passed in, then no plugin will be loaded and
* a simple Containment object will be created instead.
* @param args argument list to pass to the containment
*
* @return a pointer to the containment on success, or 0 on failure. Failure can be
* caused by too restrictive of an Immutability type, as containments cannot be added
* when widgets are locked, or if the requested containment plugin can not be located
* or successfully loaded.
*/
Containment *addContainment(const QString &name, const QVariantList &args = QVariantList());
/**
* Returns the Containment, if any, for a given physical screen and desktop
*
* @param screen number of the physical screen to locate
* @param desktop the virtual desktop) to locate; if < 0 then it will
* simply return the first Containment associated with screen
*/
Containment *containmentForScreen(int screen, int desktop = -1) const;
/**
* Returns the Containment for a given physical screen and desktop, creating one
* if none exists
*
* @param screen number of the physical screen to locate
* @param desktop the virtual desktop) to locate; if < 0 then it will
* simply return the first Containment associated with screen
* @param defaultPluginIfNonExistent the plugin to load by default; "null" is an empty
* Containment and "default" creates the default plugin
* @param defaultArgs optional arguments to pass in when creating a Containment if needed
* @since 4.6
*/
Containment *containmentForScreen(int screen, int desktop,
const QString &defaultPluginIfNonExistent,
const QVariantList &defaultArgs = QVariantList());
/**
* Returns the number of screens available to plasma.
* Subclasses should override this method as the default
* implementation returns a meaningless value.
*/
virtual int numScreens() const;
/**
* Returns the geometry of a given screen.
* Valid screen ids are 0 to numScreen()-1, or -1 for the full desktop geometry.
* Subclasses should override this method as the default
* implementation returns a meaningless value.
*/
virtual QRect screenGeometry(int id) const;
/**
* Returns the available region for a given screen.
* The available region excludes panels and similar windows.
* Valid screen ids are 0 to numScreens()-1.
* By default this method returns a rectangular region
* equal to screenGeometry(id); subclasses that need another
* behavior should override this method.
*/
virtual QRegion availableScreenRegion(int id) const;
/**
* This method is useful in order to retrieve the list of available
* screen edges for panel type containments.
* @param screen the id of the screen to look for free edges.
* @returns a list of free edges not filled with panel type containments.
*/
QList<Plasma::Location> freeEdges(int screen) const;
/**
* Returns the QAction with the given name from our collection
*/
QAction *action(QString name) const;
/**
* Adds the action to our collection under the given name
*/
void addAction(QString name, QAction *action);
/**
* Returns all the actions in our collection
*/
QList<QAction*> actions() const;
/**
* convenience function - enables or disables an action by name
*
* @param name the name of the action in our collection
* @param enable true to enable, false to disable
*/
void enableAction(const QString &name, bool enable);
/**
* @since 4.3
* Updates keyboard shortcuts for all the CoronaBase's actions.
* If you've added actions to the CoronaBase you'll need to
* call this for them to be configurable.
*/
void updateShortcuts();
/**
* @since 4.3
* Adds a set of actions to the shortcut config dialog.
* don't use this on actions in the CoronaBase's own actioncollection,
* those are handled automatically. this is for stuff outside of that.
*/
void addShortcuts(KActionCollection *newShortcuts);
/**
* @since 4.3
* Creates an action in our collection under the given name
* @return the new action
* FIXME I'm wrapping so much of kactioncollection API now, maybe I should just expose the
* collection itself :P
*/
KAction* addAction(QString name);
/**
* @since 4.4
* Sets the default containmentactions plugins for the given containment type
*/
void setContainmentActionsDefaults(Containment::Type containmentType, const ContainmentActionsPluginsConfig &config);
/**
* @since 4.4
* Returns the default containmentactions plugins for the given containment type
*/
ContainmentActionsPluginsConfig containmentActionsDefaults(Containment::Type containmentType);
/**
* @param the AbstractDialogManager implementaion
*
* @since 4.5
*/
void setDialogManager(AbstractDialogManager *manager);
/**
* @return the AbstractDialogManager that will show dialogs used by applets, like configuration dialogs
*
* @since 4.5
*/
AbstractDialogManager *dialogManager();
/**
* Returns the name of the preferred plugin to be used as containment toolboxes.
* CustomContainments and CustomPanelContainments can still override it as their liking. It's also not guaranteed that the plugin will actually exist.
*
* @param type the containment type of which we want to know the associated toolbox plugin
* @since 4.6
*/
QString preferredToolBoxPlugin(const Containment::Type type) const;
/**
* Imports an applet layout from a config file. The results will be added to the
* current set of Containments.
*
* @param config the name of the config file to load from,
* or the default config file if QString()
* @return the list of containments that were loaded
* @since 4.6
*/
QList<Plasma::Containment *> importLayout(const KConfigGroup &config);
/**
* Exports a set of containments to a config file.
*
* @param config the config group to save to
* @param containments the list of containments to save
* @since 4.6
*/
void exportLayout(KConfigGroup &config, QList<Containment*> containments);
public Q_SLOTS:
/**
* Initializes the layout from a config file. This will first clear any existing
* Containments, load a layout from the requested configuration file, request the
* default layout if needed and update immutability.
*
* @param config the name of the config file to load from,
* or the default config file if QString()
*/
void initializeLayout(const QString &config = QString());
/**
* Load applet layout from a config file. The results will be added to the
* current set of Containments.
*
* @param config the name of the config file to load from,
* or the default config file if QString()
*/
void loadLayout(const QString &config = QString());
/**
* Save applets layout to file
* @param config the file to save to, or the default config file if QString()
*/
void saveLayout(const QString &config = QString()) const;
/**
* @return The type of immutability of this CoronaBase
*/
ImmutabilityType immutability() const;
/**
* Sets the immutability type for this CoronaBase (not immutable,
* user immutable or system immutable)
* @param immutable the new immutability type of this applet
*/
void setImmutability(const ImmutabilityType immutable);
/**
* Schedules a flush-to-disk synchronization of the configuration state
* at the next convenient moment.
*/
void requestConfigSync();
/**
* Schedules a time sensitive flush-to-disk synchronization of the
* configuration state. Since this method does not provide any sort of
* event compression, it should only be used when an *immediate* disk
* sync is *absolutely* required. Otherwise, use @see requestConfigSync()
* which does do event compression.
*/
void requireConfigSync();
Q_SIGNALS:
/**
* This signal indicates a new containment has been added to
* the CoronaBase
*/
void containmentAdded(Plasma::Containment *containment);
/**
* This signal indicates that a containment has been newly
* associated (or dissociated) with a physical screen.
*
* @param wasScreen the screen it was associated with
* @param isScreen the screen it is now associated with
* @param containment the containment switching screens
*/
void screenOwnerChanged(int wasScreen, int isScreen, Plasma::Containment *containment);
/**
* This signal indicates that an application launch, window
* creation or window focus event was triggered. This is used, for instance,
* to ensure that the Dashboard view in Plasma hides when such an event is
* triggered by an item it is displaying.
*/
void releaseVisualFocus();
/**
* This signal indicates that the configuration file was flushed to disc.
*/
void configSynced();
/**
* This signal inicates that a change in available screen goemetry occurred.
*/
void availableScreenRegionChanged();
/**
* emitted when immutability changes.
* this is for use by things that don't get contraints events, like plasmaapp.
* it's NOT for containments or applets or any of the other stuff on the scene.
* if your code's not in shells/ it probably shouldn't be using it.
*/
void immutabilityChanged(Plasma::ImmutabilityType immutability);
/**
* @since 4.3
* emitted when the user changes keyboard shortcut settings
* connect to this if you've put some extra shortcuts in your app
* that are NOT in CoronaBase's actioncollection.
* if your code's not in shells/ it probably shouldn't be using this function.
* @see addShortcuts
*/
void shortcutsChanged();
protected:
/**
* Loads the default (system wide) layout for this user
**/
virtual void loadDefaultLayout();
/**
* @return The preferred toolbox plugin name for a given containment type.
* @param type the containment type of which we want to know the preferred toolbox plugin.
* @param plugin the toolbox plugin name
* @since 4.6
*/
void setPreferredToolBoxPlugin(const Containment::Type type, const QString &plugin);
/**
* Sets the default containment plugin to try and load
* @since 4.7
*/
void setDefaultContainmentPlugin(const QString &name);
private:
CoronaPrivate *const d;
Q_PRIVATE_SLOT(d, void containmentDestroyed(QObject*))
Q_PRIVATE_SLOT(d, void syncConfig())
Q_PRIVATE_SLOT(d, void toggleImmutability())
Q_PRIVATE_SLOT(d, void showShortcutConfig())
friend class CoronaPrivate;
friend class View;
};
} // namespace Plasma
#endif

0
plasma/coronabase.h Normal file
View File

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="plasmarc" />
<group name="CachePolicies">
<entry key="CacheTheme" type="Bool">
<label>Whether or not to create an on-disk cache for the theme.</label>
<default>true</default>
</entry>
<entry key="ThemeCacheKb" type="Int">
<label>The maximum size of the on-disk Theme cache in kilobytes. Note that these files are sparse files, so the maximum size may not be used. Setting a larger size is therefore often quite safe.</label>
<default>81920</default>
</entry>
</group>
</kcfg>

View File

@ -0,0 +1,4 @@
File=libplasma-theme-global.kcfg
ClassName=ThemeConfig
Singleton=false
Mutators=false

View File

@ -0,0 +1,6 @@
[KNewStuff3]
ProvidersUrl=http://download.kde.org/ocs/providers.xml
Categories=Plasmoid Script
StandardResource=tmp
InstallationCommand=plasmapkg -i %f
UninstallCommand=plasmapkg -r %f

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kcfg SYSTEM
"http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfg>
<group name="GetSource">
<entry name="SourceName" type="String">
<label>The name of the desired datasource.</label>
</entry>
<entry name="UUID" type="String">
<label>Specify a UUID here.</label>
</entry>
</group>
<group name="ServiceForSource">
<entry name="SourceName" type="String">
<label>The name of the desired datasource's service.</label>
</entry>
</group>
<group name="GetSourceNames" />
</kcfg>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kcfg SYSTEM
"http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfg>
<group name="GetPackage" />
<group name="GetMetaData" />
<group name="DataEngine">
<entry name="EngineName" type="String">
<label>The name of the engine we want to obtain.</label>
</entry>
</group>
</kcfg>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kcfg SYSTEM
"http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfg>
<group name="save">
<entry name="group" type="String">
<label>Group the key/value saved belongs to</label>
</entry>
<entry name="key" type="String">
<label>The key that indicizes the value in the storage</label>
</entry>
<entry name="data" type="Int">
<label>The actual data to be stored.</label>
</entry>
<entry name="data" type="String">
<label>The actual data to be stored.</label>
</entry>
<entry name="data" type="StringList">
<label>The actual data to be stored.</label>
</entry>
</group>
<group name="retrieve">
<entry name="group" type="String">
<label>Group the key/value saved belongs to</label>
</entry>
<entry name="key" type="String">
<label>The key that indicizes the value in the storage. If empty all group will be retrieved.</label>
</entry>
</group>
<group name="delete">
<entry name="group" type="String">
<label>Group the key/value saved belongs to</label>
</entry>
<entry name="key" type="String">
<label>The key that indicizes the value in the storage. If empty all group will be deleted</label>
</entry>
</group>
<group name="expire">
<entry name="group" type="String">
<label>Group the key/value saved belongs to. If empty all ntries will be checked for expiration.</label>
</entry>
<entry name="age" type="UInt">
<label>Set the age the stored data will expire in seconds. Default is 4 days.</label>
<default>345600</default>
</entry>
</group>
</kcfg>

View File

@ -0,0 +1,66 @@
[Protocol]
protocol=plasma
exec=plasma-remote-helper %u
input=none
output=none
Icon=plasma
Description=A protocol for Plasma services
Description[ar]=ميفاق لخدمات بلازما
Description[bg]=Протокол за услуги Plasma
Description[bs]=Protokol Plazma usluga
Description[ca]=Un protocol pels serveis del Plasma
Description[ca@valencia]=Un protocol pels serveis del Plasma
Description[cs]=Protokol pro služby Plasma
Description[da]=En protokol til Plasma-tjenester
Description[de]=Ein Protokoll für Plasma-Dienste
Description[el]=Ένα πρωτόκολλο υπηρεσιών Plasma
Description[es]=Un protocolo para los servicios de Plasma
Description[et]=Plasma teenuste protokoll
Description[eu]=Plasma zerbitzuentzako protokolo bat
Description[fi]=Plasma-palvelujen yhteyskäytäntö
Description[fr]=Un protocole pour les services Plasma
Description[ga]=Prótacal le haghaidh seirbhísí Plasma
Description[gl]=Un protocolo para servizos do Plasma
Description[he]=פרוטוקול עבור הרכיבים של Plasma
Description[hr]=Protokol za servise u Plasmi
Description[hu]=Protokoll a Plazma-szolgáltatáshoz
Description[ia]=un protocollo per servicios de Plasma
Description[is]=Samskiptamáti fyrir Plasma-þjónustur
Description[it]=Un protocollo per servizi plasma
Description[ja]=Plasma サービスのためのプロトコル
Description[kk]=Plasma қызметінің протоколы
Description[km]=ពិធីការ​សម្រាប់​សេវា​កម្ម​ប្លាស្មា
Description[ko]=Plasma 서비스 프로토콜
Description[lv]=Plasma servisu protokols
Description[mr]=प्लाज्मा सेवांसाठी शिष्टाचार
Description[nb]=En protokoll for plasma-tjenester
Description[nds]=En Protokoll för Plasma-Deensten
Description[nl]=Een protocol voor Plasma-services
Description[pa]=ਪਲਾਜ਼ਮਾ ਸਰਵਿਸ ਲਈ ਪਰੋਟੋਕਾਲ
Description[pl]=Protokół dla usług Plazmy
Description[pt]=Um protocolo para os serviços do Plasma
Description[pt_BR]=Protocolo para os serviços do Plasma
Description[ro]=Un protocol pentru servicii Plasma
Description[ru]=Протокол для служб Plasma
Description[se]=Protokolla Plasma-bálvalusaid várás
Description[sk]=Protokol pre Plasma služby
Description[sl]=Protokol za storitve Plasme
Description[sr]=Протокол за плазма сервисе
Description[sr@ijekavian]=Протокол за плазма сервисе
Description[sr@ijekavianlatin]=Protokol za plasma servise
Description[sr@latin]=Protokol za plasma servise
Description[sv]=Ett protokoll för Plasma-tjänster
Description[tg]=Протоколи хидматҳои Plasma
Description[tr]=Plasma servisleri için bir protokol
Description[tt]=Plasma хезмәте өчен беркетмә
Description[ug]=پلازما(Plasma) مۇلازىمىتىنىڭ كېلىشىمى
Description[uk]=Протокол для служб Плазми
Description[vi]=Một giao thức cho các dịch vụ Plasma
Description[x-test]=xxA protocol for Plasma servicesxx
Description[zh_CN]=Plasma 服务协议
Description[zh_TW]=Plasma 服務協定
helper=true
Class=:internet

View File

@ -0,0 +1,95 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/Applet
Comment=Plasma applet
Comment[ar]=بريمج بلازما
Comment[as]=Plasma
Comment[ast]=Miniaplicación Plasma
Comment[be@latin]=Aplet Plasma
Comment[bg]=Аплет за Plasma
Comment[bn]=
Comment[bn_IN]=Plasma
Comment[bs]=Plazma aplet
Comment[ca]=Miniaplicació del Plasma
Comment[ca@valencia]=Miniaplicació del Plasma
Comment[cs]=Plasma applet
Comment[da]=Plasma-applet
Comment[de]=Plasma-Miniprogramm
Comment[el]=Μικροεφαρμογή plasma
Comment[en_GB]=Plasma applet
Comment[eo]=Plasma apleto
Comment[es]=Miniaplicación para Plasma
Comment[et]=Plasma aplett
Comment[eu]=Plasma appleta
Comment[fi]=Plasma-sovelma
Comment[fr]=Applet Plasma
Comment[fy]=Plasma Applet
Comment[ga]=Feidhmchláirín Plasma
Comment[gl]=Applet de Plasma
Comment[gu]=
Comment[he]=יישומון של Plasma
Comment[hi]=
Comment[hne]=
Comment[hr]=Plasma applet
Comment[hsb]=Plasma applet
Comment[hu]=Plasma-kisalkalmazás
Comment[ia]=Applet Plasma
Comment[id]=Applet Plasma
Comment[is]=Plasma smáforrit
Comment[it]=Applet Plasma
Comment[ja]=Plasma
Comment[kk]=Plasma апплеті
Comment[km]=
Comment[kn]= ()
Comment[ko]=Plasma 릿
Comment[ku]=Sepanoka Plasma
Comment[lt]=Plasma įskiepis
Comment[lv]=Plasma aplets
Comment[mai]=
Comment[ml]=
Comment[mr]=
Comment[nb]=Plasma miniprogram
Comment[nds]=Plasma-Lüttprogramm
Comment[nl]=Plasma-applet
Comment[nn]=Plasma-element
Comment[pa]= ਿ
Comment[pl]=Aplet Plazmy
Comment[pt]='Applet' do Plasma
Comment[pt_BR]=Miniaplicativo do Plasma
Comment[ro]=Miniaplicație Plasma
Comment[ru]=Виджет Plasma
Comment[se]=Plasma-prográmmaš
Comment[si]=Plasma
Comment[sk]=Plasma aplet
Comment[sl]=Plasma programček
Comment[sr]=Плазма аплет
Comment[sr@ijekavian]=Плазма аплет
Comment[sr@ijekavianlatin]=Plasma aplet
Comment[sr@latin]=Plasma aplet
Comment[sv]=Plasma-miniprogram
Comment[ta]=ி
Comment[tg]=Барномаи Plasma
Comment[th]=
Comment[tr]=Plasma programcığı
Comment[tt]=Plasma кушымтасы
Comment[ug]=Plasma قوللانچاق
Comment[uk]=Аплет Плазми
Comment[vi]=Tiu dng Plasma
Comment[wa]=Aplikete di Plasma
Comment[x-test]=xxPlasma appletxx
Comment[zh_CN]=Plasma
Comment[zh_TW]=Plasma
[PropertyDef::X-Plasma-API]
Type=QString
[PropertyDef::X-Plasma-DropMimeTypes]
Type=QStringList
[PropertyDef::X-Plasma-DropUrlPatterns]
Type=QStringList
[PropertyDef::X-Plasma-DefaultSize]
Type=QSize

View File

@ -0,0 +1,83 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/Containment
Comment=Plasma applet container and background painter
Comment[ar]=حاوية بريمج بلازما ورسام خلفية
Comment[as]=Plasma ি ি
Comment[ast]=Contenedor de miniaplicación Plasma y pintor del fondu
Comment[be@latin]=Schovišča dla apletaŭ Plasma j malar fonu
Comment[bg]=Контейнер за аплети на Plasma и рисуване на фона
Comment[bs]=Sadržalac plazma apletâ i iscrtavač pozadine
Comment[ca]=Contenidor de miniaplicació del Plasma i pintor de fons
Comment[ca@valencia]=Contenidor de miniaplicació del Plasma i pintor de fons
Comment[cs]=Kontejner apletů a vykreslovač pozadí Plasma
Comment[da]=Beholder og baggrundstegning til Plasma-applets
Comment[de]=Plasma-Programmcontainer und Hintergrund-Zeichnung
Comment[el]=Υποδοχέας μικροεφαρμογών Plasma και σχεδιαστής του φόντου
Comment[en_GB]=Plasma applet container and background painter
Comment[eo]=Plasma apletujo kaj fonpentrilo
Comment[es]=Contenedor de miniaplicaciones para Plasma y pintor del fondo
Comment[et]=Plasma apleti konteiner ja tausta joonistaja
Comment[eu]=Plasma appletaren edukiontzia eta hondoa margotzekoa
Comment[fi]=Plasma sovelmasisällyttäjä ja taustapiirtäjä
Comment[fr]=Conteneur d'applet Plasma et affichage d'arrière-plan
Comment[fy]=Plasma applet container en eftergrûn skilder
Comment[ga]=Coimeádán feidhmchláiríní Plasma agus péintéir cúlra
Comment[gl]=Un contedor de applet de Plasma e pintor do fondo
Comment[gu]=
Comment[he]=תוחם של יישומון Plasma וצובע הרקע
Comment[hne]= ि
Comment[hr]=Spremnik za Plasmin applet i crtač pozadine
Comment[hsb]=Plasma-container za applet a molowadło pozadka
Comment[hu]=Tartóelem és háttérrajzoló Plasma-kisalkalmazásokhoz
Comment[ia]=Receptaculo applet Plasma e pictor de fundo
Comment[id]=Applet pengisi dan penggambar latar belakang Plasma
Comment[is]=Grunnur fyrir Plasma smáforrit og bakgrunnslitun
Comment[it]=Contenitore applet Plasma e disegnatore dello sfondo
Comment[ja]=Plasma
Comment[kk]=Plasma апплет контейнері және ая боятқышы
Comment[km]=
Comment[kn]= () () ಿ (ಿ)
Comment[ko]=Plasma 릿
Comment[ku]=Embarvanê sepanoka Plasma û nexşevanê rûerdê
Comment[lt]=Plasma įskiepio dėklas ir fono paišiklis
Comment[lv]=Plasma sīkrīku konteiners un fona zīmētājs
Comment[mai]= ि
Comment[ml]= ി
Comment[mr]=
Comment[nb]=Plasma beholder for miniprogram og bakgrunnsopptegner
Comment[nds]=Plasma-Gelaats för Lüttprogrammen un Achtergrundpleger
Comment[nl]=Container voor plasma-applets en achtergrondinvulling
Comment[nn]=Plasma-behaldar og bakgrunnsmålar
Comment[pa]= ਿ
Comment[pl]=Kontener apletu Plazmy i rysowanie tła
Comment[pt]=Contentor de 'applets' do Plasma e pintor do fundo
Comment[pt_BR]=Recipiente de miniaplicativos do Plasma e pintor de plano de fundo
Comment[ro]=Container de miniaplicații Plasma și desenator de fundal
Comment[ru]=Контейнер и модуль отрисовки виджета Plasma
Comment[se]=Plasma-prográmmašlihtti ja -duogášmálejeaddji
Comment[si]=Plasma
Comment[sk]=Kontajner apletu a vykresľovanie pozadia Plasma
Comment[sl]=Vsebnik programčkov in izrisovalnik ozadja za Plasmo
Comment[sr]=Садржалац плазма аплетâ и исцртавач позадине
Comment[sr@ijekavian]=Садржалац плазма аплетâ и исцртавач позадине
Comment[sr@ijekavianlatin]=Sadržalac plasma apletâ i iscrtavač pozadine
Comment[sr@latin]=Sadržalac plasma apletâ i iscrtavač pozadine
Comment[sv]=Plasmaminiprogram-omgivning och bakgrundsuppritning
Comment[ta]=ி ி ிி ி
Comment[tg]=Системаи захиракунӣ ва тасвирии Plasma
Comment[th]=
Comment[tr]=Plasma programcık içerici ve arkaplan oluşturucu
Comment[tt]=Plasma кушымтаның контейнеры һәм сүрәтләү модуле
Comment[ug]=Plasma قاچا ھەرىكىتى ۋە تەگلىك سىزغۇچ
Comment[uk]=Контейнер аплетів плазми і малювання тла
Comment[wa]=Contneu d' aplikete eyet pondeu do fond di plasma
Comment[x-test]=xxPlasma applet container and background painterxx
Comment[zh_CN]=Plasma
Comment[zh_TW]=Plasma
[PropertyDef::X-Plasma-ContainmentCategories]
Type=QStringList

View File

@ -0,0 +1,70 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/ContainmentActions
Comment=Plasma ContainmentActions
Comment[ar]=Plasma ContainmentActions
Comment[bg]=Действия за контейнера на Plasma
Comment[bs]=Plazma radnje sadržalaca
Comment[ca]=ContainmentActions del Plasma
Comment[ca@valencia]=ContainmentActions del Plasma
Comment[cs]=Akce plasma kontejneru
Comment[da]=Plasma ContainmentActions
Comment[de]=Plasma-Container-Aktionen
Comment[el]=Ενέργειες Υποδοχέα Plasma
Comment[en_GB]=Plasma ContainmentActions
Comment[es]=ContainmentActions de Plasma
Comment[et]=Plasma konteineritoimingud
Comment[eu]=Plasma ContainmentActions
Comment[fi]=Plasma ContainmentActions
Comment[fr]=Plasma d'actions contenantes
Comment[ga]=Gníomhartha Coimeádán Plasma
Comment[gl]=ContainmentActions de Plasma
Comment[he]=Plasma ContainmentActions
Comment[hr]=Plasma ContainmentActions
Comment[hu]=Plasma tartóműveletek
Comment[ia]=Actiones de continemento Plasma
Comment[id]=Plasma Aksi Berisi
Comment[is]=Plasma ContainmentActions
Comment[it]=ContainmentActions di Plasma
Comment[ja]=Plasma
Comment[kk]=Plasma контейнер әрекеті
Comment[km]= ContainmentActions
Comment[ko]=Plasma ContainmentActions
Comment[ku]=Plasma ContainmentActions
Comment[lt]=Plasma konteinerių veiksmai
Comment[lv]=Plasma ietvara darbības
Comment[mr]=
Comment[nb]=Plasma ContainmentActions
Comment[nds]=Plasma-Gelaatsakschonen
Comment[nl]=Plasma Containeracties
Comment[nn]=Plasma behaldarhandlingar
Comment[pa]=
Comment[pl]=Kontener Plazmy: akcje
Comment[pt]=Acções do Contentor do Plasma
Comment[pt_BR]=Ações do contêiner do Plasma
Comment[ro]=AcțiuniContainer Plasma
Comment[ru]=Действия для контейнеров Plasma
Comment[se]=Plasma ContainmentActions
Comment[sk]=Akcie Plasma
Comment[sl]=Dejanja za vsebnik za Plasmo
Comment[sr]=Плазма радње садржалаца
Comment[sr@ijekavian]=Плазма радње садржалаца
Comment[sr@ijekavianlatin]=Plasma radnje sadržalaca
Comment[sr@latin]=Plasma radnje sadržalaca
Comment[sv]=Plasma omgivningsåtgärder
Comment[ta]=ி ContainmentActions
Comment[tg]=Plasma ContainmentActions
Comment[th]=
Comment[tr]=Plasma İçerici Eylemleri
Comment[tt]=Plasma контейнеры гамәлләре
Comment[ug]=Plasma قاچا ھەرىكىتى
Comment[uk]=Дії контейнерів Плазми
Comment[wa]=Contneu d' accions di Plasma
Comment[x-test]=xxPlasma ContainmentActionsxx
Comment[zh_CN]=Plasma
Comment[zh_TW]=Plasma
[PropertyDef::X-Plasma-HasConfigurationInterface]
Type=bool

View File

@ -0,0 +1,83 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/DataEngine
Comment=Plasma Data Engine
Comment[ar]=محرك بيانات بلازما
Comment[as]=Plasma Data Engine
Comment[ast]=Motor de datos Plasma
Comment[be@latin]=Systema dostupu da źviestak Plasma
Comment[bg]=Ядро за данни на Plasma
Comment[bn]= ি
Comment[bn_IN]=Plasma ি
Comment[bs]=Plazma datomotor
Comment[ca]=Motor de dades del Plasma
Comment[ca@valencia]=Motor de dades del Plasma
Comment[cs]=Datový nástroj plasma
Comment[da]=Plasma datamotor
Comment[de]=Plasma-Daten-Treiber
Comment[el]=Μηχανή δεδομένων Plasma
Comment[en_GB]=Plasma Data Engine
Comment[eo]=Plasma Datuma Motoro
Comment[es]=Motor de datos para Plasma
Comment[et]=Plasma andmemootor
Comment[eu]=Plasmaren datu motorra
Comment[fi]=Plasma-tietomoottori
Comment[fr]=Moteur de données Plasma
Comment[fy]=Plasma gegevensmotor
Comment[ga]=Inneall Sonraí Plasma
Comment[gl]=Motor de datos de plasma
Comment[gu]= િ િ
Comment[he]=מנוע מידע עבור Plasma
Comment[hne]= ि
Comment[hr]=Plasmin podaktovni mehanizam
Comment[hsb]=Datowa engine za Plasma
Comment[hu]=Plasma adatkezelő
Comment[ia]=Motor de datos de Plasma
Comment[id]=Mesin Data Plasma
Comment[is]=Plasma gagnavél
Comment[it]=Motore dati Plasma
Comment[ja]=Plasma
Comment[kk]=Plasma деректер тетігі
Comment[km]=
Comment[kn]=
Comment[ko]=Plasma
Comment[ku]=Motora Dane ya Plasma
Comment[lt]=Plasma duomenų varikliukas
Comment[lv]=Plasma datu dzinējs
Comment[mai]=
Comment[ml]= ി
Comment[mr]= ि
Comment[nb]=Plasma datamotor
Comment[nds]=Plasma-Datenkarn
Comment[nl]=Plasma-gegevensengine
Comment[nn]=Plasma-datamotor
Comment[pa]=
Comment[pl]=Silnik danych Plazmy
Comment[pt]=Motor de Dados do Plasma
Comment[pt_BR]=Mecanismo de dados do Plasma
Comment[ro]=Motor de date Plasma
Comment[ru]=Источник данных Plasma
Comment[se]=Plasma-dáhtamohtor
Comment[si]=Plasma
Comment[sk]=Dátový nástroj Plasma
Comment[sl]=Podatkovni pogon za Plasmo
Comment[sq]=Motor të Dhënash Plasma
Comment[sr]=Плазма датомотор
Comment[sr@ijekavian]=Плазма датомотор
Comment[sr@ijekavianlatin]=Plasma datomotor
Comment[sr@latin]=Plasma datomotor
Comment[sv]=Plasma datagränssnitt
Comment[ta]=ி ி
Comment[tg]=Системаи маълумотии Plasma
Comment[th]=
Comment[tr]=Plasma Veri Motoru
Comment[tt]=Plasma мәгълүмат коралы
Comment[ug]=Plasma سانلىق-مەلۇمات ماتورى
Comment[uk]=Рушій даних Плазми
Comment[vi]=Cơ chế d liu Plasma
Comment[wa]=Moteur di dnêyes di Plasma
Comment[x-test]=xxPlasma Data Enginexx
Comment[zh_CN]=Plasma
Comment[zh_TW]=Plasma

View File

@ -0,0 +1,86 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/PackageStructure
Comment=Plasma package structure definition
Comment[ar]=تعريف بنية حزمة بلازما
Comment[as]=Plasma
Comment[ast]=Definición d'estructura de paquete Plasma
Comment[be@latin]=Aznačeńnie struktury pakunka Plasma
Comment[bg]=Структурно определение на пакет на Plasma
Comment[bs]=Definicija strukture plazma paketa
Comment[ca]=Definició de l'estructura d'un paquet Plasma
Comment[ca@valencia]=Definició de l'estructura d'un paquet Plasma
Comment[cs]=Definice struktury Plasma balíčku
Comment[da]=Definition af pakkestruktur til Plasma
Comment[de]=Plasma-Paket-Struktur-Definition
Comment[el]=Ορισμός δομής πακέτου του Plasma
Comment[en_GB]=Plasma package structure definition
Comment[es]=Definición de estructura de paquete para Plasma
Comment[et]=Plasma paketi struktuuri definitsioon
Comment[eu]=Plasma paketearen egituraren definizioa
Comment[fi]=Plasma-pakettirakenteen määritelmä
Comment[fr]=Définition de la structure des paquetages Plasma
Comment[fy]=Plasma pakket sstruktuer defenysje
Comment[ga]=Sainmhíniú ar struchtúr pacáiste Plasma
Comment[gl]=Definición da estrutura do paquete de Plasma
Comment[gu]=
Comment[he]=הגדרת מבנה של חבילת Plasma
Comment[hne]= ि
Comment[hr]=Plasmina definicija strukture paketa
Comment[hsb]=Strukturna definicija Plasma-pakćika
Comment[hu]=Struktúraleíró Plasma-csomagokhoz
Comment[ia]=Definition del structura de pacchetto de Plasma
Comment[id]=Definisi struktur paket Plasma
Comment[is]=Skilgreiningar Plasma pakkauppbyggingar
Comment[it]=Definizione struttura pacchetto Plasma
Comment[ja]=Plasma
Comment[kk]=Plasma дестесінің құрамынын анықтауы
Comment[km]=
Comment[kn]= () (ಿ)
Comment[ko]=Plasma
Comment[ku]=Daxuyaniya çêbûna pakêta Plasma
Comment[lt]=Plasma paketo struktūros aprašymas
Comment[lv]=Plasma pakotņu struktūras definīcija
Comment[mai]= ि
Comment[ml]= ി
Comment[mr]=
Comment[nb]=Definisjon av Plasma pakkestruktur
Comment[nds]=Paketstruktuur-Fastleggen vun Plasma
Comment[nl]=Structuurdefinitie van plasmapakket
Comment[nn]=Pakkestrukturdefinisjon for Plasma
Comment[pa]= ਿ
Comment[pl]=Definicja struktury pakietu Plazmy
Comment[pt]=Definição da estrutura de pacotes do Plasma
Comment[pt_BR]=Definição de estrutura de pacote do Plasma
Comment[ro]=Definiție de structură a pachetului Plasma
Comment[ru]=Определение структуры пакета Plasma
Comment[se]=Plasma-páhkkaráhkadusdefinišuvdna
Comment[sk]=Definícia štruktúry Plasma balíčkov
Comment[sl]=Definicija strukture paketa za Plasmo
Comment[sr]=Дефиниција структуре плазма пакета
Comment[sr@ijekavian]=Дефиниција структуре плазма пакета
Comment[sr@ijekavianlatin]=Definicija strukture plasma paketa
Comment[sr@latin]=Definicija strukture plasma paketa
Comment[sv]=Strukturdefinition av Plasma-paket
Comment[ta]=ி ி ி
Comment[tg]=Барномаи муайянкунии сохтори Plasma
Comment[th]=
Comment[tr]=Plasma paketi yapı tanımlaması
Comment[tt]=Plasma төргәк төзелешен билгеләү
Comment[ug]=Plasma بوغچا قۇرۇلما ئېنىقلىمىسى
Comment[uk]=Опис структури пакунка плазми
Comment[vi]=Đnh nghĩa cu trúc gói Plasma
Comment[wa]=Definixha del sitructeure do pacaedje di Plasma
Comment[x-test]=xxPlasma package structure definitionxx
Comment[zh_CN]=Plasma
Comment[zh_TW]=Plasma
[PropertyDef::X-Plasma-PackageFileFilter]
Type=QString
[PropertyDef::X-Plasma-PackageFileMimetypes]
Type=QStringList
[PropertyDef::X-Plasma-ProvidesWidgetBrowser]
Type=bool

View File

@ -0,0 +1,94 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/Runner
Comment=KRunner plugin
Comment[ar]=ملحق KRunner
Comment[as]=KRunner -
Comment[ast]=Complementu KRunner
Comment[be@latin]=Plugin dla KRunner
Comment[bg]=Приставка за KRunner
Comment[bn]=- -
Comment[bn_IN]=KRunner -
Comment[bs]=Priključak za Kizvođač
Comment[ca]=Connector del KRunner
Comment[ca@valencia]=Connector del KRunner
Comment[cs]=KRunner modul
Comment[csb]=Wtëkôcz KRunner
Comment[da]=KRunner-plugin
Comment[de]=KRunner-Modul
Comment[el]=Πρόσθετο του KRunner
Comment[en_GB]=KRunner plugin
Comment[es]=Complemento para KRunner
Comment[et]=KRunneri plugin
Comment[eu]=KRnner plugin-a
Comment[fa]=وصله KRunner
Comment[fi]=KRunner-liitännäinen
Comment[fr]=Module KRunner
Comment[fy]=KRunner plugin
Comment[ga]=Breiseán KRunner
Comment[gl]=Complemento KFileWrite
Comment[gu]=KRunner
Comment[he]=תוסף KRunner
Comment[hi]=
Comment[hne]=-
Comment[hr]=Priključak Krunner
Comment[hsb]=KRunner plugin
Comment[hu]=KRunner-bővítmény
Comment[ia]=Plugin KRunner
Comment[id]=Plguin KRunner
Comment[is]=KRunner íforrit
Comment[it]=Plugin KRunner
Comment[ja]=KRunner
Comment[kk]=KRunner плагині
Comment[km]= KRunner
Comment[kn]= ಿಿ (ಿ)
Comment[ko]=KRunner
Comment[ku]=Pêveka KAjoker
Comment[lt]=KRunner priedas
Comment[lv]=KRunner spraudnis
Comment[mai]=
Comment[ml]=
Comment[mr]=KRunner
Comment[nb]=KRunner-programtillegg
Comment[nds]=KRunner-Moduul
Comment[nl]=KRunner-plugin
Comment[nn]=KRunner-tillegg
Comment[pa]=
Comment[pl]=Wtyczka KRunnera
Comment[pt]='Plugin' do KRunner
Comment[pt_BR]=Plugin do KRunner
Comment[ro]=Modul KRunner
Comment[ru]=Расширение KRunner
Comment[se]=KRunner-lassemodula
Comment[si]=KRunner
Comment[sk]=KRunner modul
Comment[sl]=Vstavek za KRunner
Comment[sq]=KRunner plugin
Comment[sr]=Прикључак за Кизвођач
Comment[sr@ijekavian]=Прикључак за Кизвођач
Comment[sr@ijekavianlatin]=Priključak za Kizvođač
Comment[sr@latin]=Priključak za Kizvođač
Comment[sv]=Krunner-insticksprogram
Comment[ta]= ி
Comment[tg]=Васлкунаки KRunner
Comment[th]= KRunner
Comment[tr]=KRunner eklentisi
Comment[tt]=KRunner өстәмәсе
Comment[ug]=KRunner قىستۇرما
Comment[uk]=Додаток до KRunner
Comment[vi]=Phn b sung KRunner
Comment[wa]=Tchôke-divins KRunner
Comment[x-test]=xxKRunner pluginxx
Comment[zh_CN]=KRunner
Comment[zh_TW]=KRunner
[PropertyDef::X-Plasma-AdvertiseSingleRunnerQueryMode]
Type=bool
[PropertyDef::TryExec]
Type=QString
[PropertyDef::X-Plasma-Args]
Type=QStringList

View File

@ -0,0 +1,86 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/ScriptEngine
Comment=Scripting language extension for Plasma
Comment[ar]=امتداد لغة سكربت لبلازما
Comment[as]=Plasma িি
Comment[ast]=Estensión de llinguaxe de guiones pa Plasma
Comment[be@latin]=Pašyreńnie skryptavaj movy dla systemy Plasma
Comment[bg]=Разширение на Plasma за скриптов език
Comment[bs]=Proširenje Plazme za skriptne jezike
Comment[ca]=Extensió de llenguatge d'script per al Plasma
Comment[ca@valencia]=Extensió de llenguatge d'script per al Plasma
Comment[cs]=Rozšíření pro skriptovací jazyky Plasma
Comment[da]=Scriptsprog-udvidelse til Plasma
Comment[de]=Skriptsprachen-Erweiterung für Plasma
Comment[el]=Επέκταση γλώσσας σεναρίων για το Plasma
Comment[en_GB]=Scripting language extension for Plasma
Comment[eo]=Skriptlingva etendaĵo por Plasma
Comment[es]=Extensión de lenguaje de script para Plasma
Comment[et]=Skriptikeele laiendus Plasmale
Comment[eu]=Plasmarako script lengoaien gehigarria
Comment[fi]=Skriptauskielituki Plasmalle
Comment[fr]=Langage de script d'extension pour Plasma
Comment[fy]=Scripting taal taheaksel foar Plasma
Comment[ga]=Eisínteacht teanga scriptithe le haghaidh Plasma
Comment[gl]=Extensión de linguaxe de scripts para o Plasma
Comment[gu]= િ
Comment[he]=הרחבת שפת תסריטים של Plasma
Comment[hne]= िि
Comment[hr]=Proširenje Plasme za skriptne jezike
Comment[hsb]=Skriptowa rěč jako Plasma-ekstensija
Comment[hu]=Szkriptkezelő bővítmény a Plasmához
Comment[ia]=Extension del language de script de Plasma
Comment[id]=Tambahan bahasa skrip untuk Plasma
Comment[is]=Framlenging á skriftunarmál fyrir Plasma
Comment[it]=Estensione linguaggio scripting per Plasma
Comment[ja]=Plasma
Comment[kk]=Plasma-ның скрипт тілі
Comment[km]=
Comment[kn]= ಿಿ (ಿ) ಿ
Comment[ko]=Plasma
Comment[ku]=Pêveka zimanê skrîpt kirinê ji bo Plasma
Comment[lt]=Scenarijų kalbos praplėtimas, skirtas Plasma
Comment[lv]=Skriptēšanas valodu Plasma paplašinājums
Comment[mai]= िि ि
Comment[ml]= ിി
Comment[mr]= ि
Comment[nb]=Skriptspråk-utvidelse for Plasma
Comment[nds]=Skriptspraak-Verwiedern för Plasma
Comment[nl]=Scripttaalextensie voor Plasma
Comment[nn]=Skriptspråkutviding for Plasma
Comment[pa]= ਿਿ
Comment[pl]=Rozszerzenie języka skryptów dla Plazmy
Comment[pt]=Extensão de linguagens de programação para o Plasma
Comment[pt_BR]=Extensão de linguagem de script do Plasma
Comment[ro]=Extensie de limbaj pentru scripturi Plasma
Comment[ru]=Поддержка языков сценариев для Plasma
Comment[se]=Skriptagiellaviiddádus Plasmai
Comment[si]=Plasma
Comment[sk]=Rozšírenie pre skriptovacie jazyky Plasma
Comment[sl]=Razširitev s skriptnim jezikom za Plasmo
Comment[sr]=Проширење Плазме за скриптне језике
Comment[sr@ijekavian]=Проширење Плазме за скриптне језике
Comment[sr@ijekavianlatin]=Proširenje Plasme za skriptne jezike
Comment[sr@latin]=Proširenje Plasme za skriptne jezike
Comment[sv]=Skriptspråksutökning för Plasma
Comment[ta]=ிி ி ி ிி
Comment[tg]=Скрипти забонҳои иловагӣ барои Plasma
Comment[th]=
Comment[tr]=Plasma için betik dili eklentisi
Comment[tt]=Plasma өчен скрипт телләр өстәмәсе
Comment[ug]=Plasma نىڭ قوليازما تىل كېڭەيتىلمىسى
Comment[uk]=Розширення скриптових мов для Плазми
Comment[vi]=Phn m rng ngôn ng lnh cho Plasma
Comment[wa]=Rawete di lingaedje di scriptaedje po Plasma
Comment[x-test]=xxScripting language extension for Plasmaxx
Comment[zh_CN]=Plasma
Comment[zh_TW]=Plasma 稿
[PropertyDef::X-Plasma-ComponentTypes]
Type=QStringList
[PropertyDef::X-Plasma-PackageFormat]
Type=QString

View File

@ -0,0 +1,66 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/Service
Comment=Plasma service
Comment[ar]=خدمة بلازما
Comment[bg]=Услуга Plasma
Comment[bs]=Plazma usluga
Comment[ca]=Servei del Plasma
Comment[ca@valencia]=Servei del Plasma
Comment[cs]=Služba Plasma
Comment[da]=Plasma-tjeneste
Comment[de]=Plasma-Dienst
Comment[el]=Υπηρεσία plasma
Comment[en_GB]=Plasma service
Comment[es]=Servicio de Plasma
Comment[et]=Plasma teenus
Comment[eu]=Plasma zerbitzua
Comment[fi]=Plasma-palvelu
Comment[fr]=Service Plasma
Comment[ga]=Seirbhís Plasma
Comment[gl]=Servizo do Plasma
Comment[he]=שירות של Plasma
Comment[hi]=
Comment[hr]=Servis u Plasmi
Comment[hu]=Plazma-szolgáltatás
Comment[ia]=Servicio de Plasma
Comment[is]=Plasma-þjónusta
Comment[it]=Servizio plasma
Comment[ja]=Plasma
Comment[kk]=Plasma қызметі
Comment[km]=
Comment[ko]=Plasma
Comment[lt]=Plasma tarnyba
Comment[lv]=Plasma serviss
Comment[mr]=
Comment[nb]=Plasma-tjeneste
Comment[nds]=Plasma-Deenst
Comment[nl]=Plasma-service
Comment[pa]= ਿ
Comment[pl]=Usługa Plazmy
Comment[pt]=Serviço do Plasma
Comment[pt_BR]=Serviço do Plasma
Comment[ro]=Servicu Plasma
Comment[ru]=Служба Plasma
Comment[se]=Plasma-bálvalus
Comment[si]=
Comment[sk]=Služba Plasma
Comment[sl]=Storitev Plasme
Comment[sq]=Shërbimi plazma
Comment[sr]=Плазма сервис
Comment[sr@ijekavian]=Плазма сервис
Comment[sr@ijekavianlatin]=Plasma servis
Comment[sr@latin]=Plasma servis
Comment[sv]=Plasma-tjänst
Comment[tg]=Хидматҳои Plasma
Comment[th]=
Comment[tr]=Plasma servisi
Comment[tt]=Plasma хезмәте
Comment[ug]=Plasma مۇلازىمىتى
Comment[uk]=Служба Плазми
Comment[vi]=Dch v Plasma
Comment[wa]=Siervice di Plasma
Comment[x-test]=xxPlasma servicexx
Comment[zh_CN]=Plasma
Comment[zh_TW]=Plasma

View File

@ -0,0 +1,67 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Plasma/ToolBox
Comment=Plasma toolbox
Comment[ar]=صندوق أدوات بلازما
Comment[bg]=Инструменти за Plasma
Comment[bs]=Plazma alatna traka
Comment[ca]=Caixa d'eines del Plasma
Comment[ca@valencia]=Caixa d'eines del Plasma
Comment[cs]=Plasma toolbox
Comment[da]=Plasma værktøjskasse
Comment[de]=Plasma-Werkzeugkasten
Comment[el]=Εργαλειοθήκη Plasma
Comment[en_GB]=Plasma toolbox
Comment[es]=Caja de herramientas de Plasma
Comment[et]=Plasma tööriistakast
Comment[eu]=Plasma tresna-kutxa
Comment[fi]=Plasma-työkalurivi
Comment[fr]=Boîte à outils Plasma
Comment[ga]=Bosca uirlisí Plasma
Comment[gl]=Barra de ferramentas do Plasma
Comment[he]=ארגז כלים של Plasma
Comment[hi]=
Comment[hr]=Plasma alatni okvir
Comment[hu]=Plazma-eszközkészlet
Comment[ia]=Instrumentario de Plasma
Comment[is]=Plasma verkfærasafn
Comment[it]=Barra degli strumenti plasma
Comment[ja]=Plasma
Comment[kk]=Plasma құралдары
Comment[km]=
Comment[ko]=Plasma
Comment[ku]=Qutiya amûrên Plasma
Comment[lt]=Pasma įrankinė
Comment[lv]=Plasma rīkkopa
Comment[mr]=
Comment[nb]=Plasma-verktøykasse
Comment[nds]=Plasma-Warktüüchkist
Comment[nl]=Plasma-hulpmiddelen
Comment[pa]=
Comment[pl]=Przybornik Plazmy
Comment[pt]=Barra de ferramentas do Plasma
Comment[pt_BR]=Barra de ferramentas do Plasma
Comment[ro]=Cutie de unelte Plasma
Comment[ru]=Панель инструментов Plasma
Comment[se]=Plasma-reaidoboksa
Comment[si]=
Comment[sk]=Nástroje Plasma
Comment[sl]=Orodjana v Plasmi
Comment[sr]=Плазма алатница
Comment[sr@ijekavian]=Плазма алатница
Comment[sr@ijekavianlatin]=Plasma alatnica
Comment[sr@latin]=Plasma alatnica
Comment[sv]=Plasma verktygslåda
Comment[ta]=ி ிி
Comment[tg]=Лавҳаи воситаҳои Plasma
Comment[th]=
Comment[tr]=Plasma araç kutusu
Comment[tt]=Plasma корал панеле
Comment[ug]=Plasma قورال ساندۇقى
Comment[uk]=Набір інструментів Плазми
Comment[vi]=Hp công c Plasma
Comment[wa]=Boesse ås usteyes di Plasma
Comment[x-test]=xxPlasma toolboxxx
Comment[zh_CN]=Plasma
Comment[zh_TW]=Plasma

360
plasma/datacontainer.cpp Normal file
View File

@ -0,0 +1,360 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "datacontainer.h"
#include "private/datacontainer_p.h"
#include "private/storage_p.h"
#include <kdebug.h>
#include "plasma.h"
namespace Plasma
{
DataContainer::DataContainer(QObject *parent)
: QObject(parent),
d(new DataContainerPrivate(this))
{
}
DataContainer::~DataContainer()
{
delete d;
}
const DataEngine::Data DataContainer::data() const
{
return d->data;
}
void DataContainer::setData(const QString &key, const QVariant &value)
{
if (!value.isValid()) {
d->data.remove(key);
} else {
d->data.insert(key, value);
}
d->dirty = true;
d->updateTs.start();
//check if storage is enabled and if storage is needed.
//If it is not set to be stored,then this is the first
//setData() since the last time it was stored. This
//gives us only one singleShot timer.
if (isStorageEnabled() || !needsToBeStored()) {
d->storageTimer.start(180000, this);
}
setNeedsToBeStored(true);
}
void DataContainer::removeAllData()
{
if (d->data.isEmpty()) {
// avoid an update if we don't have any data anyways
return;
}
d->data.clear();
d->dirty = true;
d->updateTs.start();
}
bool DataContainer::visualizationIsConnected(QObject *visualization) const
{
return d->relayObjects.contains(visualization);
}
void DataContainer::connectVisualization(QObject *visualization, uint pollingInterval,
Plasma::IntervalAlignment alignment)
{
//kDebug() << "connecting visualization" << visualization << "at interval of"
// << pollingInterval << "to" << objectName();
QMap<QObject *, SignalRelay *>::iterator objIt = d->relayObjects.find(visualization);
bool connected = objIt != d->relayObjects.end();
if (connected) {
// this visualization is already connected. just adjust the update
// frequency if necessary
SignalRelay *relay = objIt.value();
if (relay) {
// connected to a relay
//kDebug() << " already connected, but to a relay";
if (relay->m_interval == pollingInterval) {
//kDebug() << " already connected to a relay of the same interval of"
// << pollingInterval << ", nothing to do";
return;
}
if (relay->receiverCount() == 1) {
//kDebug() << " removing relay, as it is now unused";
d->relays.remove(relay->m_interval);
delete relay;
} else {
disconnect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
//relay->isUnused();
}
} else if (pollingInterval < 1) {
// the visualization was connected already, but not to a relay
// and it still doesn't want to connect to a relay, so we have
// nothing to do!
//kDebug() << " already connected, nothing to do";
return;
} else {
disconnect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
}
} else {
connect(visualization, SIGNAL(destroyed(QObject*)),
this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection);
}
if (pollingInterval < 1) {
//kDebug() << " connecting directly";
d->relayObjects[visualization] = 0;
connect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
} else {
//kDebug() << " connecting to a relay";
// we only want to do an imediate update if this is not the first object to connect to us
// if it is the first visualization, then the source will already have been populated
// engine's sourceRequested method
bool immediateUpdate = connected || d->relayObjects.count() > 1;
SignalRelay *relay = d->signalRelay(this, visualization, pollingInterval,
alignment, immediateUpdate);
connect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
}
}
void DataContainer::setStorageEnabled(bool store)
{
QTime time = QTime::currentTime();
qsrand((uint)time.msec());
d->enableStorage = store;
if (store) {
QTimer::singleShot(qrand() % (2000 + 1) , this, SLOT(retrieve()));
}
}
bool DataContainer::isStorageEnabled() const
{
return d->enableStorage;
}
bool DataContainer::needsToBeStored() const
{
return !d->isStored;
}
void DataContainer::setNeedsToBeStored(bool store)
{
d->isStored = !store;
}
DataEngine* DataContainer::getDataEngine()
{
QObject *o = this;
DataEngine *de = NULL;
while (de == NULL)
{
o = dynamic_cast<QObject *> (o->parent());
if (o == NULL) {
return NULL;
}
de = dynamic_cast<DataEngine *> (o);
}
return de;
}
void DataContainerPrivate::store()
{
if (!q->needsToBeStored() || !q->isStorageEnabled()) {
return;
}
DataEngine* de = q->getDataEngine();
if (!de) {
return;
}
q->setNeedsToBeStored(false);
if (!storage) {
storage = new Storage(q);
}
KConfigGroup op = storage->operationDescription("save");
op.writeEntry("group", q->objectName());
StorageJob *job = static_cast<StorageJob *>(storage->startOperationCall(op));
job->setData(data);
storageCount++;
QObject::connect(job, SIGNAL(finished(KJob*)), q, SLOT(storeJobFinished(KJob*)));
}
void DataContainerPrivate::storeJobFinished(KJob* )
{
--storageCount;
if (storageCount < 1) {
storage->deleteLater();
storage = 0;
}
}
void DataContainerPrivate::retrieve()
{
DataEngine* de = q->getDataEngine();
if (de == NULL) {
return;
}
if (!storage) {
storage = new Storage(q);
}
KConfigGroup retrieveGroup = storage->operationDescription("retrieve");
retrieveGroup.writeEntry("group", q->objectName());
ServiceJob* retrieveJob = storage->startOperationCall(retrieveGroup);
QObject::connect(retrieveJob, SIGNAL(result(KJob*)), q,
SLOT(populateFromStoredData(KJob*)));
}
void DataContainerPrivate::populateFromStoredData(KJob *job)
{
if (job->error()) {
return;
}
StorageJob *ret = dynamic_cast<StorageJob*>(job);
if (!ret) {
return;
}
// Only fill the source with old stored
// data if it is not already populated with new data.
if (data.isEmpty() && !ret->data().isEmpty()) {
data = ret->data();
dirty = true;
q->forceImmediateUpdate();
}
KConfigGroup expireGroup = storage->operationDescription("expire");
//expire things older than 4 days
expireGroup.writeEntry("age", 345600);
storage->startOperationCall(expireGroup);
}
void DataContainer::disconnectVisualization(QObject *visualization)
{
QMap<QObject *, SignalRelay *>::iterator objIt = d->relayObjects.find(visualization);
disconnect(visualization, SIGNAL(destroyed(QObject*)),
this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection);
if (objIt == d->relayObjects.end() || !objIt.value()) {
// it is connected directly to the DataContainer itself
disconnect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
} else {
SignalRelay *relay = objIt.value();
if (relay->receiverCount() == 1) {
d->relays.remove(relay->m_interval);
delete relay;
} else {
disconnect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
}
}
d->relayObjects.erase(objIt);
d->checkUsage();
}
void DataContainer::checkForUpdate()
{
//kDebug() << objectName() << d->dirty;
if (d->dirty) {
emit dataUpdated(objectName(), d->data);
foreach (SignalRelay *relay, d->relays) {
relay->checkQueueing();
}
d->dirty = false;
}
}
void DataContainer::forceImmediateUpdate()
{
if (d->dirty) {
d->dirty = false;
emit dataUpdated(objectName(), d->data);
}
foreach (SignalRelay *relay, d->relays) {
relay->forceImmediateUpdate();
}
}
uint DataContainer::timeSinceLastUpdate() const
{
//FIXME: we still assume it's been <24h
//and ignore possible daylight savings changes
return d->updateTs.elapsed();
}
void DataContainer::setNeedsUpdate(bool update)
{
d->cached = update;
}
bool DataContainer::isUsed() const
{
return !d->relays.isEmpty() &&
receivers(SIGNAL(dataUpdated(QString, Plasma::DataEngine::Data))) > 0;
}
void DataContainerPrivate::checkUsage()
{
if (!checkUsageTimer.isActive()) {
checkUsageTimer.start(10, q);
}
}
void DataContainer::timerEvent(QTimerEvent * event)
{
if (event->timerId() == d->checkUsageTimer.timerId()) {
if (!isUsed()) {
// DO NOT CALL ANYTHING AFTER THIS LINE AS IT MAY GET DELETED!
//kDebug() << objectName() << "is unused";
emit becameUnused(objectName());
}
d->checkUsageTimer.stop();
} else if (event->timerId() == d->storageTimer.timerId()) {
d->store();
d->storageTimer.stop();
}
}
} // Plasma namespace
#include "moc_datacontainer.cpp"

261
plasma/datacontainer.h Normal file
View File

@ -0,0 +1,261 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DATACONTAINER_H
#define PLASMA_DATACONTAINER_H
#include <QtCore/QHash>
#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <kjob.h>
#include <plasma/plasma_export.h>
#include <plasma/dataengine.h>
namespace Plasma
{
class DataContainerPrivate;
/**
* @class DataContainer plasma/datacontainer.h <Plasma/DataContainer>
*
* @brief A set of data exported via a DataEngine
*
* Plasma::DataContainer wraps the data exported by a DataEngine
* implementation, providing a generic wrapper for the data.
*
* A DataContainer may have zero or more associated pieces of data which
* are keyed by strings. The data itself is stored as QVariants. This allows
* easy and flexible retrieval of the information associated with this object
* without writing DataContainer or DataEngine specific code in visualizations.
*
* If you are creating your own DataContainer objects (and are passing them to
* DataEngine::addSource()), you normally just need to listen to the
* updateRequested() signal (as well as any other methods you might have of
* being notified of new data) and call setData() to actually update the data.
* Then you need to either trigger the scheduleSourcesUpdated signal of the
* parent DataEngine or call checkForUpdate() on the DataContainer.
*
* You also need to set a suitable name for the source with setObjectName().
* See DataEngine::addSource() for more information.
*
* Note that there is normally no need to subclass DataContainer, except as
* a way of encapsulating the data retrieval for a source, since all notifications
* are done via signals rather than virtual methods.
**/
class PLASMA_EXPORT DataContainer : public QObject
{
friend class DataEngine;
friend class DataEnginePrivate;
Q_OBJECT
public:
/**
* Constructs a default DataContainer that has no name or data
* associated with it
**/
explicit DataContainer(QObject *parent = 0);
virtual ~DataContainer();
/**
* Returns the data for this DataContainer
**/
const DataEngine::Data data() const;
/**
* Set a value for a key.
*
* This also marks this source as needing to signal an update.
*
* If you call setData() directly on a DataContainer, you need to
* either trigger the scheduleSourcesUpdated() slot for the
* data engine it belongs to or call checkForUpdate() on the
* DataContainer.
*
* @param key a string used as the key for the data
* @param value a QVariant holding the actual data. If a invalid
* QVariant is passed in and the key currently exists in the
* data, then the data entry is removed
**/
void setData(const QString &key, const QVariant &value);
/**
* Removes all data currently associated with this source
*
* If you call removeAllData() on a DataContainer, you need to
* either trigger the scheduleSourcesUpdated() slot for the
* data engine it belongs to or call checkForUpdate() on the
* DataContainer.
**/
void removeAllData();
/**
* @return true if the visualization is currently connected
*/
bool visualizationIsConnected(QObject *visualization) const;
/**
* Connects an object to this DataContainer.
*
* May be called repeatedly for the same visualization without
* side effects
*
* @param visualization the object to connect to this DataContainer
* @param pollingInterval the time in milliseconds between updates
* @param alignment the clock position to align updates to
**/
void connectVisualization(QObject *visualization, uint pollingInterval,
Plasma::IntervalAlignment alignment);
/**
* sets this data container to be automatically stored.
* @param whether this data container should be stored
* @since 4.6
*/
void setStorageEnabled(bool store);
/**
* @return true if the data container has been marked for storage
* @since 4.6
*/
bool isStorageEnabled() const;
/**
* @return true if the data container has been updated, but not stored
*/
bool needsToBeStored() const;
/**
* sets that the data container needs to be stored or not.
* @param whether the data container needs to be stored
*/
void setNeedsToBeStored(bool store);
/**
* @return the DataEngine that the DataContainer is
* a child of.
*/
DataEngine* getDataEngine();
/**
* @return true if one or more visualizations is connected to this DataContainer
*/
bool isUsed() const;
public Q_SLOTS:
/**
* Disconnects an object from this DataContainer.
*
* Note that if this source was created by DataEngine::sourceRequestEvent(),
* it will be deleted by DataEngine once control returns to the event loop.
**/
void disconnectVisualization(QObject *visualization);
/**
* Forces immediate update signals to all visualizations
* @since 4.4
*/
void forceImmediateUpdate();
Q_SIGNALS:
/**
* Emitted when the data has been updated, allowing visualizations to
* reflect the new data.
*
* Note that you should not normally emit this directly. Instead, use
* checkForUpdate() or the DataEngine::scheduleSourcesUpdated() slot.
*
* @param source the objectName() of the DataContainer (and hence the name
* of the source) that updated its data
* @param data the updated data
**/
void dataUpdated(const QString &source, const Plasma::DataEngine::Data &data);
/**
* Emitted when the last visualization is disconnected.
*
* Note that if this source was created by DataEngine::sourceRequestEvent(),
* it will be deleted by DataEngine once control returns to the event loop
* after this signal is emitted.
*
* @param source the name of the source that became unused
**/
void becameUnused(const QString &source);
/**
* Emitted when an update is requested.
*
* If a polling interval was passed connectVisualization(), this signal
* will be emitted every time the interval expires.
*
* Note that if you create your own DataContainer (and pass it to
* DataEngine::addSource()), you will need to listen to this signal
* and refresh the data when it is triggered.
*
* @param source the datacontainer the update was requested for. Useful
* for classes that update the data for several containers.
**/
void updateRequested(DataContainer *source);
protected:
/**
* Checks whether any data has changed and, if so, emits dataUpdated().
**/
void checkForUpdate();
/**
* Returns how long ago, in msecs, that the data in this container was last updated.
*
* This is used by DataEngine to compress updates that happen more quickly than the
* minimum polling interval by calling setNeedsUpdate() instead of calling
* updateSourceEvent() immediately.
**/
uint timeSinceLastUpdate() const;
/**
* Indicates that the data should be treated as dirty the next time hasUpdates() is called.
*
* This is needed for the case where updateRequested() is triggered but we don't want to
* update the data immediately because it has just been updated. The second request won't
* be fulfilled in this case, because we never updated the data and so never called
* checkForUpdate(). So we claim it needs an update anyway.
**/
void setNeedsUpdate(bool update = true);
protected Q_SLOTS:
/**
* @reimp from QObject
*/
void timerEvent(QTimerEvent * event);
private:
friend class SignalRelay;
friend class DataContainerPrivate;
friend class DataEngineManager;
DataContainerPrivate *const d;
Q_PRIVATE_SLOT(d, void storeJobFinished(KJob *job))
Q_PRIVATE_SLOT(d, void populateFromStoredData(KJob *job))
Q_PRIVATE_SLOT(d, void retrieve())
};
} // Plasma namespace
#endif // multiple inclusion guard

759
plasma/dataengine.cpp Normal file
View File

@ -0,0 +1,759 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "dataengine.h"
#include "private/dataengine_p.h"
#include "private/datacontainer_p.h"
#include <QQueue>
#include <QTimer>
#include <QTime>
#include <QTimerEvent>
#include <QVariant>
#include <kdebug.h>
#include <kplugininfo.h>
#include <kglobal.h>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#include <klocalizedstring.h>
#include "datacontainer.h"
#include "package.h"
#include "pluginloader.h"
#include "remote/authorizationmanager.h"
#include "remote/authorizationmanager_p.h"
#include "service.h"
#include "scripting/dataenginescript.h"
#include "private/datacontainer_p.h"
#include "private/dataengineservice_p.h"
#include "private/remotedataengine_p.h"
#include "private/service_p.h"
#include "private/storage_p.h"
namespace Plasma
{
DataEngine::DataEngine(QObject *parent, KService::Ptr service)
: QObject(parent),
d(new DataEnginePrivate(this, KPluginInfo(service)))
{
}
DataEngine::DataEngine(QObject *parent, const QVariantList &args)
: QObject(parent),
d(new DataEnginePrivate(this, KPluginInfo(KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()))))
{
}
DataEngine::~DataEngine()
{
//kDebug() << objectName() << ": bye bye birdy! ";
delete d;
}
QStringList DataEngine::sources() const
{
if (d->script) {
return d->script->sources();
} else {
return d->sources.keys();
}
}
Service *DataEngine::serviceForSource(const QString &source)
{
if (d->script) {
Service * s = d->script->serviceForSource(source);
if (s) {
return s;
}
}
return new NullService(source, this);
}
void DataEngine::connectSource(const QString &source, QObject *visualization,
uint pollingInterval,
Plasma::IntervalAlignment intervalAlignment) const
{
//kDebug() << "connectSource" << source;
bool newSource;
DataContainer *s = d->requestSource(source, &newSource);
if (s) {
// we suppress the immediate invocation of dataUpdated here if the
// source was prexisting and they don't request delayed updates
// (we want to do an immediate update in that case so they don't
// have to wait for the first time out)
if (newSource && !s->data().isEmpty()) {
newSource = false;
}
d->connectSource(s, visualization, pollingInterval, intervalAlignment,
!newSource || pollingInterval > 0);
//kDebug() << " ==> source connected";
}
}
void DataEngine::connectAllSources(QObject *visualization, uint pollingInterval,
Plasma::IntervalAlignment intervalAlignment) const
{
foreach (DataContainer *s, d->sources) {
d->connectSource(s, visualization, pollingInterval, intervalAlignment);
}
}
void DataEngine::disconnectSource(const QString &source, QObject *visualization) const
{
DataContainer *s = d->source(source, false);
if (s) {
s->disconnectVisualization(visualization);
}
}
DataContainer *DataEngine::containerForSource(const QString &source)
{
return d->source(source, false);
}
DataEngine::Data DataEngine::query(const QString &source) const
{
bool newSource;
DataContainer *s = d->requestSource(source, &newSource);
if (!s) {
return DataEngine::Data();
} else if (!newSource && d->minPollingInterval >= 0 &&
s->timeSinceLastUpdate() >= uint(d->minPollingInterval)) {
DataEngine *unconstThis = const_cast<DataEngine*>(this);
if (unconstThis->updateSourceEvent(source)) {
unconstThis->scheduleSourcesUpdated();
}
}
DataEngine::Data data = s->data();
s->d->checkUsage();
return data;
}
void DataEngine::init()
{
if (d->script) {
d->setupScriptSupport();
d->script->init();
} else {
// kDebug() << "called";
// default implementation does nothing. this is for engines that have to
// start things in motion external to themselves before they can work
}
}
bool DataEngine::sourceRequestEvent(const QString &name)
{
if (d->script) {
return d->script->sourceRequestEvent(name);
} else {
return false;
}
}
bool DataEngine::updateSourceEvent(const QString &source)
{
if (d->script) {
return d->script->updateSourceEvent(source);
} else {
//kDebug() << source;
return false; //TODO: should this be true to trigger, even needless, updates on every tick?
}
}
void DataEngine::setData(const QString &source, const QVariant &value)
{
setData(source, source, value);
}
void DataEngine::setData(const QString &source, const QString &key, const QVariant &value)
{
DataContainer *s = d->source(source, false);
bool isNew = !s;
if (isNew) {
s = d->source(source);
}
s->setData(key, value);
if (isNew && source != d->waitingSourceRequest) {
emit sourceAdded(source);
}
scheduleSourcesUpdated();
}
void DataEngine::setData(const QString &source, const Data &data)
{
DataContainer *s = d->source(source, false);
bool isNew = !s;
if (isNew) {
s = d->source(source);
}
Data::const_iterator it = data.constBegin();
while (it != data.constEnd()) {
s->setData(it.key(), it.value());
++it;
}
if (isNew && source != d->waitingSourceRequest) {
emit sourceAdded(source);
}
scheduleSourcesUpdated();
}
void DataEngine::removeAllData(const QString &source)
{
DataContainer *s = d->source(source, false);
if (s) {
s->removeAllData();
scheduleSourcesUpdated();
}
}
void DataEngine::removeData(const QString &source, const QString &key)
{
DataContainer *s = d->source(source, false);
if (s) {
s->setData(key, QVariant());
scheduleSourcesUpdated();
}
}
void DataEngine::addSource(DataContainer *source)
{
if (d->sources.contains(source->objectName())) {
#ifndef NDEBUG
kDebug() << "source named \"" << source->objectName() << "\" already exists.";
#endif
return;
}
QObject::connect(source, SIGNAL(updateRequested(DataContainer*)),
this, SLOT(internalUpdateSource(DataContainer*)));
QObject::connect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
d->sources.insert(source->objectName(), source);
emit sourceAdded(source->objectName());
scheduleSourcesUpdated();
}
void DataEngine::setMinimumPollingInterval(int minimumMs)
{
d->minPollingInterval = minimumMs;
}
int DataEngine::minimumPollingInterval() const
{
return d->minPollingInterval;
}
void DataEngine::setPollingInterval(uint frequency)
{
killTimer(d->updateTimerId);
d->updateTimerId = 0;
if (frequency > 0) {
d->updateTimerId = startTimer(frequency);
}
}
void DataEngine::removeSource(const QString &source)
{
SourceDict::iterator it = d->sources.find(source);
if (it != d->sources.end()) {
DataContainer *s = it.value();
s->d->store();
s->disconnect(this);
s->deleteLater();
d->sources.erase(it);
emit sourceRemoved(source);
}
}
void DataEngine::removeAllSources()
{
QMutableHashIterator<QString, Plasma::DataContainer*> it(d->sources);
while (it.hasNext()) {
it.next();
Plasma::DataContainer *s = it.value();
const QString source = it.key();
it.remove();
s->disconnect(this);
s->deleteLater();
emit sourceRemoved(source);
}
}
bool DataEngine::isValid() const
{
return d->valid;
}
bool DataEngine::isEmpty() const
{
return d->sources.isEmpty();
}
void DataEngine::setValid(bool valid)
{
d->valid = valid;
}
DataEngine::SourceDict DataEngine::containerDict() const
{
return d->sources;
}
void DataEngine::timerEvent(QTimerEvent *event)
{
//kDebug();
if (event->timerId() == d->updateTimerId) {
// if the freq update is less than 0, don't bother
if (d->minPollingInterval < 0) {
//kDebug() << "uh oh.. no polling allowed!";
return;
}
// minPollingInterval
if (d->updateTimestamp.elapsed() < d->minPollingInterval) {
//kDebug() << "hey now.. slow down!";
return;
}
d->updateTimestamp.restart();
updateAllSources();
} else if (event->timerId() == d->checkSourcesTimerId) {
killTimer(d->checkSourcesTimerId);
d->checkSourcesTimerId = 0;
QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
while (it.hasNext()) {
it.next();
it.value()->checkForUpdate();
}
} else {
QObject::timerEvent(event);
}
}
void DataEngine::updateAllSources()
{
QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
while (it.hasNext()) {
it.next();
//kDebug() << "updating" << it.key();
updateSourceEvent(it.key());
}
scheduleSourcesUpdated();
}
void DataEngine::forceImmediateUpdateOfAllVisualizations()
{
foreach (DataContainer *source, d->sources) {
source->forceImmediateUpdate();
}
}
void DataEngine::setIcon(const QString &icon)
{
d->icon = icon;
}
QString DataEngine::icon() const
{
return d->icon;
}
QString DataEngine::pluginName() const
{
if (!d->dataEngineDescription.isValid()) {
return QString();
}
return d->dataEngineDescription.pluginName();
}
void DataEngine::setDefaultService(const QString &serviceName)
{
d->serviceName = serviceName;
}
Service* DataEngine::createDefaultService(QObject *parent)
{
QVariantList args;
args << QVariant::fromValue<DataEngine*>(this);
return PluginLoader::self()->loadService(d->serviceName, args, parent);
}
void DataEnginePrivate::publish(AnnouncementMethods methods, const QString &name)
{
if (!publishedService) {
publishedService = new DataEngineService(q);
}
//QString resourceName =
//i18nc("%1 is the name of a dataengine, %2 the name of the machine that engine is published
//on",
//"%1 dataengine on %2", name(), AuthorizationManager::self()->d->myCredentials.name());
#ifndef NDEBUG
kDebug() << "name: " << name;
#endif
publishedService->d->publish(methods, name);
}
void DataEnginePrivate::unpublish(const QString &name)
{
Q_UNUSED(name)
if (publishedService) {
publishedService->d->unpublish();
}
}
bool DataEnginePrivate::isPublished() const
{
if (publishedService) {
return publishedService->d->isPublished();
} else {
return false;
}
}
Package DataEngine::package() const
{
return d->package ? *d->package : Package();
}
void DataEngine::scheduleSourcesUpdated()
{
if (d->checkSourcesTimerId) {
return;
}
d->checkSourcesTimerId = startTimer(0);
}
QString DataEngine::name() const
{
return d->engineName;
}
void DataEngine::setName(const QString &name)
{
d->engineName = name;
setObjectName(name);
}
void DataEngine::setStorageEnabled(const QString &source, bool store)
{
DataContainer *s = d->source(source, false);
if (s) {
s->setStorageEnabled(store);
}
}
// Private class implementations
DataEnginePrivate::DataEnginePrivate(DataEngine *e, const KPluginInfo &info)
: q(e),
dataEngineDescription(info),
refCount(-1), // first ref
checkSourcesTimerId(0),
updateTimerId(0),
minPollingInterval(-1),
valid(true),
script(0),
package(0),
publishedService(0)
{
updateTimestamp.start();
if (!info.isValid()) {
engineName = i18n("Unnamed");
return;
}
engineName = info.name();
if (engineName.isEmpty()) {
engineName = i18n("Unnamed");
}
e->setObjectName(engineName);
icon = info.icon();
if (dataEngineDescription.isValid()) {
QString api = dataEngineDescription.property("X-Plasma-API").toString();
if (!api.isEmpty()) {
const QString path =
KStandardDirs::locate("data",
"plasma/dataengines/" + dataEngineDescription.pluginName() + '/');
package = new Package(PluginLoader::self()->loadPackage("Plasma/DataEngine", api));
package->setPath(path);
if (package->isValid()) {
script = Plasma::loadScriptEngine(api, q);
}
if (!script) {
#ifndef NDEBUG
kDebug() << "Could not create a" << api << "ScriptEngine for the"
<< dataEngineDescription.name() << "DataEngine.";
#endif
delete package;
package = 0;
}
}
}
}
DataEnginePrivate::~DataEnginePrivate()
{
delete script;
script = 0;
delete package;
package = 0;
}
void DataEnginePrivate::internalUpdateSource(DataContainer *source)
{
if (minPollingInterval > 0 &&
source->timeSinceLastUpdate() < (uint)minPollingInterval) {
// skip updating this source; it's been too soon
//kDebug() << "internal update source is delaying" << source->timeSinceLastUpdate() << minPollingInterval;
//but fake an update so that the signalrelay that triggered this gets the data from the
//recent update. this way we don't have to worry about queuing - the relay will send a
//signal immediately and everyone else is undisturbed.
source->setNeedsUpdate();
return;
}
if (q->updateSourceEvent(source->objectName())) {
//kDebug() << "queuing an update";
q->scheduleSourcesUpdated();
}/* else {
#ifndef NDEBUG
kDebug() << "no update";
#endif
}*/
}
void DataEnginePrivate::ref()
{
--refCount;
}
void DataEnginePrivate::deref()
{
++refCount;
}
bool DataEnginePrivate::isUsed() const
{
return refCount != 0;
}
DataContainer *DataEnginePrivate::source(const QString &sourceName, bool createWhenMissing)
{
DataEngine::SourceDict::const_iterator it = sources.constFind(sourceName);
if (it != sources.constEnd()) {
DataContainer *s = it.value();
return s;
}
if (!createWhenMissing) {
return 0;
}
//kDebug() << "DataEngine " << q->objectName() << ": could not find DataContainer " << sourceName << ", creating";
DataContainer *s = new DataContainer(q);
s->setObjectName(sourceName);
sources.insert(sourceName, s);
QObject::connect(s, SIGNAL(destroyed(QObject*)), q, SLOT(sourceDestroyed(QObject*)));
QObject::connect(s, SIGNAL(updateRequested(DataContainer*)),
q, SLOT(internalUpdateSource(DataContainer*)));
return s;
}
void DataEnginePrivate::connectSource(DataContainer *s, QObject *visualization,
uint pollingInterval,
Plasma::IntervalAlignment align,
bool immediateCall)
{
//kDebug() << "connect source called" << s->objectName() << "with interval" << pollingInterval;
//FIXME: at the moment a remote dataengine can only poll, a push mechanism will be needed instead
if (pollingInterval == 0 && qobject_cast<RemoteDataEngine *>(q)) {
pollingInterval = 5000;
}
if (pollingInterval > 0) {
// never more frequently than allowed, never more than 20 times per second
uint min = qMax(50, minPollingInterval); // for qMax below
pollingInterval = qMax(min, pollingInterval);
// align on the 50ms
pollingInterval = pollingInterval - (pollingInterval % 50);
}
if (immediateCall) {
// we don't want to do an immediate call if we are simply
// reconnecting
//kDebug() << "immediate call requested, we have:" << s->visualizationIsConnected(visualization);
immediateCall = !s->data().isEmpty() &&
!s->visualizationIsConnected(visualization);
}
s->connectVisualization(visualization, pollingInterval, align);
if (immediateCall) {
QMetaObject::invokeMethod(visualization, "dataUpdated",
Q_ARG(QString, s->objectName()),
Q_ARG(Plasma::DataEngine::Data, s->data()));
s->d->dirty = false;
}
}
void DataEnginePrivate::sourceDestroyed(QObject *object)
{
DataEngine::SourceDict::iterator it = sources.begin();
while (it != sources.end()) {
if (it.value() == object) {
sources.erase(it);
emit q->sourceRemoved(object->objectName());
break;
}
++it;
}
}
DataContainer *DataEnginePrivate::requestSource(const QString &sourceName, bool *newSource)
{
if (newSource) {
*newSource = false;
}
//kDebug() << "requesting source " << sourceName;
DataContainer *s = source(sourceName, false);
if (!s) {
// we didn't find a data source, so give the engine an opportunity to make one
/*kDebug() << "DataEngine " << q->objectName()
<< ": could not find DataContainer " << sourceName
<< " will create on request" << endl;*/
waitingSourceRequest = sourceName;
if (q->sourceRequestEvent(sourceName)) {
s = source(sourceName, false);
if (s) {
// now we have a source; since it was created on demand, assume
// it should be removed when not used
if (newSource) {
*newSource = true;
}
QObject::connect(s, SIGNAL(becameUnused(QString)), q, SLOT(removeSource(QString)));
emit q->sourceAdded(sourceName);
}
}
waitingSourceRequest.clear();
}
return s;
}
// put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engine
void DataEnginePrivate::setupScriptSupport()
{
if (!package) {
return;
}
/*
#ifndef NDEBUG
kDebug() << "sletting up script support, package is in" << package->path()
#endif
<< "which is a" << package->structure()->type() << "package"
<< ", main script is" << package->filePath("mainscript");
*/
const QString translationsPath = package->filePath("translations");
if (!translationsPath.isEmpty()) {
KGlobal::dirs()->addResourceDir("locale", translationsPath);
KLocalizedString::insertCatalog(dataEngineDescription.pluginName());
}
}
QStringList DataEngine::listAllEngines(const QString &parentApp)
{
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
QStringList engines;
foreach (const KService::Ptr &service, offers) {
QString name = service->property("X-KDE-PluginInfo-Name").toString();
if (!name.isEmpty()) {
engines.append(name);
}
}
return engines;
}
KPluginInfo::List DataEngine::listEngineInfo(const QString &parentApp)
{
return PluginLoader::self()->listDataEngineInfo(parentApp);
}
KPluginInfo::List DataEngine::listEngineInfoByCategory(const QString &category, const QString &parentApp)
{
QString constraint = QString("[X-KDE-PluginInfo-Category] == '%1'").arg(category);
if (parentApp.isEmpty()) {
constraint.append(" and not exist [X-KDE-ParentApp]");
} else {
constraint.append(" and [X-KDE-ParentApp] == '").append(parentApp).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
return KPluginInfo::fromServices(offers);
}
}
#include "moc_dataengine.cpp"

548
plasma/dataengine.h Normal file
View File

@ -0,0 +1,548 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DATAENGINE_H
#define PLASMA_DATAENGINE_H
#include <QtCore/QHash>
#include <QtCore/QObject>
#include <QtCore/QStringList>
#include <kplugininfo.h>
#include <kservice.h>
#include <plasma/version.h>
#include <plasma/plasma.h>
#include <plasma/service.h>
namespace Plasma
{
class DataContainer;
class DataEngineScript;
class Package;
class Service;
class DataEnginePrivate;
/**
* @class DataEngine plasma/dataengine.h <Plasma/DataEngine>
*
* @short Data provider for plasmoids (Plasma plugins)
*
* This is the base class for DataEngines, which provide access to bodies of
* data via a common and consistent interface. The common use of a DataEngine
* is to provide data to a widget for display. This allows a user interface
* element to show all sorts of data: as long as there is a DataEngine, the
* data is retrievable.
*
* DataEngines are loaded as plugins on demand and provide zero, one or more
* data sources which are identified by name. For instance, a network
* DataEngine might provide a data source for each network interface.
**/
class PLASMA_EXPORT DataEngine : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList sources READ sources)
Q_PROPERTY(bool valid READ isValid)
Q_PROPERTY(QString icon READ icon WRITE setIcon)
Q_PROPERTY(QString name READ name)
public:
typedef QHash<QString, DataEngine*> Dict;
typedef QHash<QString, QVariant> Data;
typedef QHashIterator<QString, QVariant> DataIterator;
typedef QHash<QString, DataContainer*> SourceDict;
/**
* Constructor.
*
* @param parent The parent object.
* @param service pointer to the service that describes the engine
**/
explicit DataEngine(QObject *parent = 0, KService::Ptr service = KService::Ptr(0));
DataEngine(QObject *parent, const QVariantList &args);
~DataEngine();
/**
* This method is called when the DataEngine is started. When this
* method is called the DataEngine is fully constructed and ready to be
* used. This method should be reimplemented by DataEngine subclasses
* which need to perform a startup routine.
*
* The default implementation does nothing. Reimplementations in
* subclasses don't need to call this one.
**/
virtual void init();
/**
* @return a list of all the data sources available via this DataEngine
* Whether these sources are currently available (which is what
* the default implementation provides) or not is up to the
* DataEngine to decide.
**/
virtual QStringList sources() const;
/**
* @param source the source to target the Service at
* @return a Service that has the source as a destination. The service
* is parented to the DataEngine, but should be deleted by the
* caller when finished with it
*/
Q_INVOKABLE virtual Service *serviceForSource(const QString &source);
/**
* Returns the engine name for the DataEngine
*/
QString name() const;
/**
* Connects a source to an object for data updates. The object must
* have a slot with the following signature:
*
* dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
*
* The data is a QHash of QVariants keyed by QString names, allowing
* one data source to provide sets of related data.
*
* @param source the name of the data source
* @param visualization the object to connect the data source to
* @param pollingInterval the frequency, in milliseconds, with which to check for updates;
* a value of 0 (the default) means to update only
* when there is new data spontaneously generated
* (e.g. by the engine); any other value results in
* periodic updates from this source. This value is
* per-visualization and can be handy for items that require
* constant updates such as scrolling graphs or clocks.
* If the data has not changed, no update will be sent.
* @param intervalAlignment the number of ms to align the interval to
**/
Q_INVOKABLE void connectSource(
const QString &source, QObject *visualization,
uint pollingInterval = 0,
Plasma::IntervalAlignment intervalAlignment = NoAlignment) const;
/**
* Connects all currently existing sources to an object for data updates.
* The object must have a slot with the following signature:
*
* SLOT(dataUpdated(QString,Plasma::DataEngine::Data))
*
* The data is a QHash of QVariants keyed by QString names, allowing
* one data source to provide sets of related data.
*
* This method may be called multiple times for the same visualization
* without side-effects. This can be useful to change the pollingInterval.
*
* Note that this method does not automatically connect sources that
* may appear later on. Connecting and responding to the sourceAdded signal
* is still required to achieve that.
*
* @param visualization the object to connect the data source to
* @param pollingInterval the frequency, in milliseconds, with which to check for updates;
* a value of 0 (the default) means to update only
* when there is new data spontaneously generated
* (e.g. by the engine); any other value results in
* periodic updates from this source. This value is
* per-visualization and can be handy for items that require
* constant updates such as scrolling graphs or clocks.
* If the data has not changed, no update will be sent.
* @param intervalAlignment the number of ms to align the interval to
**/
Q_INVOKABLE void connectAllSources(QObject *visualization, uint pollingInterval = 0,
Plasma::IntervalAlignment intervalAlignment =
NoAlignment) const;
/**
* Disconnects a source from an object that was receiving data updates.
*
* @param source the name of the data source
* @param visualization the object to connect the data source to
**/
Q_INVOKABLE void disconnectSource(const QString &source, QObject *visualization) const;
/**
* Retrieves a pointer to the DataContainer for a given source. This method
* should not be used if possible. An exception is for script engines that
* can not provide a QMetaObject as required by connectSource for the initial
* call to dataUpdated. Using this method, such engines can provide their own
* connectSource API.
*
* @param source the name of the source.
* @return pointer to a DataContainer, or zero on failure
**/
Q_INVOKABLE DataContainer *containerForSource(const QString &source);
/**
* Gets the Data associated with a data source.
*
* The data is a QHash of QVariants keyed by QString names, allowing
* one data source to provide sets of related data.
*
* @param source the data source to retrieve the data for
* @return the Data associated with the source; if the source doesn't
* exist an empty data set is returned
**/
Q_INVOKABLE DataEngine::Data query(const QString &source) const;
/**
* Returns true if this engine is valid, otherwise returns false
*
* @return true if the engine is valid
**/
bool isValid() const;
/**
* Returns true if the data engine is empty, which is to say that it has no
* data sources currently.
*
* @return true if the engine has no sources currently
*/
bool isEmpty() const;
/**
* @return the name of the icon for this data engine; and empty string
* is returned if there is no associated icon.
**/
QString icon() const;
/**
* Accessor for the associated Package object if any.
*
* @return the Package object, or 0 if none
**/
Package package() const;
/**
* @return the plugin name for the applet
*/
QString pluginName() const;
/**
* Initializes and returns a new service from the name that was set
* with setDefaultService. (service name is set internally). Remember to dispose
* of the Service* when you are finished with it (even if a parent is passed)
* A DataEngine* is sent to the created service via the QVariantList arguments.
*
* @see setDefaultService
* @param the parent of the object, if any, for the returned service
* @return the newly created service
* @since 4.5
*/
Q_INVOKABLE Service* createDefaultService(QObject *parent = 0);
/**
* @return a listing of all known DataEngines by name
*
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
*/
static QStringList listAllEngines(const QString &parentApp = QString());
/**
* Returns a list of all known DataEngines.
*
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of DataEngines
**/
static KPluginInfo::List listEngineInfo(const QString &parentApp = QString());
/**
* Returns a list of all known DataEngines filtering by category.
*
* @param category the category to filter applets on. Uses the
* X-KDE-PluginInfo-Category entry (if any) in the
* plugin info. The value of QString() will
* result in a list of engines with an empty category.
*
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of DataEngines
* @since 4.3
**/
static KPluginInfo::List listEngineInfoByCategory(const QString &category, const QString &parentApp = QString());
Q_SIGNALS:
/**
* Emitted when a new data source is created
*
* Note that you do not need to emit this yourself unless
* you are reimplementing sources() and want to advertise
* that a new source is available (but hasn't been created
* yet).
*
* @param source the name of the new data source
**/
void sourceAdded(const QString &source);
/**
* Emitted when a data source is removed.
*
* Note that you do not need to emit this yourself unless
* you have reimplemented sources() and want to signal that
* a source that was available but was never created is no
* longer available.
*
* @param source the name of the data source that was removed
**/
void sourceRemoved(const QString &source);
protected:
/**
* When a source that does not currently exist is requested by the
* consumer, this method is called to give the DataEngine the
* opportunity to create one.
*
* The name of the data source (e.g. the source parameter passed into
* setData) must be the same as the name passed to sourceRequestEvent
* otherwise the requesting visualization may not receive notice of a
* data update.
*
* If the source can not be populated with data immediately (e.g. due to
* an asynchronous data acquisition method such as an HTTP request)
* the source must still be created, even if it is empty. This can
* be accomplished in these cases with the follow line:
*
* setData(name, DataEngine::Data());
*
* @param source the name of the source that has been requested
* @return true if a DataContainer was set up, false otherwise
*/
virtual bool sourceRequestEvent(const QString &source);
/**
* Called by internal updating mechanisms to trigger the engine
* to refresh the data contained in a given source. Reimplement this
* method when using facilities such as setPollingInterval.
* @see setPollingInterval
*
* @param source the name of the source that should be updated
* @return true if the data was changed, or false if there was no
* change or if the change will occur later
**/
virtual bool updateSourceEvent(const QString &source);
/**
* Sets a value for a data source. If the source
* doesn't exist then it is created.
*
* @param source the name of the data source
* @param value the data to associated with the source
**/
void setData(const QString &source, const QVariant &value);
/**
* Sets a value for a data source. If the source
* doesn't exist then it is created.
*
* @param source the name of the data source
* @param key the key to use for the data
* @param value the data to associated with the source
**/
void setData(const QString &source, const QString &key, const QVariant &value);
/**
* Adds a set of data to a data source. If the source
* doesn't exist then it is created.
*
* @param source the name of the data source
* @param data the data to add to the source
**/
void setData(const QString &source, const Data &data);
/**
* Removes all the data associated with a data source.
*
* @param source the name of the data source
**/
void removeAllData(const QString &source);
/**
* Removes a data entry from a source
*
* @param source the name of the data source
* @param key the data entry to remove
**/
void removeData(const QString &source, const QString &key);
/**
* Adds an already constructed data source. The DataEngine takes
* ownership of the DataContainer object. The objectName of the source
* is used for the source name.
*
* @param source the DataContainer to add to the DataEngine
**/
void addSource(DataContainer *source);
/**
* Sets the minimum amount of time, in milliseconds, that must pass between
* successive updates of data. This can help prevent too many updates happening
* due to multiple update requests coming in, which can be useful for
* expensive (time- or resource-wise) update mechanisms.
*
* The default minimumPollingInterval is -1, or "never perform automatic updates"
*
* @param minimumMs the minimum time lapse, in milliseconds, between updates.
* A value less than 0 means to never perform automatic updates,
* a value of 0 means update immediately on every update request,
* a value >0 will result in a minimum time lapse being enforced.
**/
void setMinimumPollingInterval(int minimumMs);
/**
* @return the minimum time between updates. @see setMinimumPollingInterval
**/
int minimumPollingInterval() const;
/**
* Sets up an internal update tick for all data sources. On every update,
* updateSourceEvent will be called for each applicable source.
* @see updateSourceEvent
*
* @param frequency the time, in milliseconds, between updates. A value of 0
* will stop internally triggered updates.
**/
void setPollingInterval(uint frequency);
/**
* Removes all data sources
**/
void removeAllSources();
/**
* Sets whether or not this engine is valid, e.g. can be used.
* In practice, only the internal fall-back engine, the NullEngine
* should have need for this.
*
* @param valid whether or not the engine is valid
**/
void setValid(bool valid);
/**
* @return the list of active DataContainers.
*/
SourceDict containerDict() const;
/**
* Reimplemented from QObject
**/
void timerEvent(QTimerEvent *event);
/**
* Sets the engine name for the DataEngine
*/
void setName(const QString &name);
/**
* Sets the icon for this data engine
**/
void setIcon(const QString &icon);
/**
* Should be set if there will be 1 main service.
* This saves any users of this DataEngine from having to know the service name to load.
* It is not created until createDefaultService is called.
*
* @code
* DataEngine *engine = dataEngine("foo");
* Service *service = engine->createDefaultService(this);
* @endcode
*
* @see createDefaultService
* @param serviceName the name of the service to load (plugin name)
* @since 4.5
*/
void setDefaultService(const QString &serviceName);
/**
* Sets a source to be stored for easy retrieval
* when the real source of the data (usually a network connection)
* is unavailable.
* @param source the name of the source
* @param store if source should be stored
* @since 4.6
*/
void setStorageEnabled(const QString &source, bool store);
protected Q_SLOTS:
/**
* Call this method when you call setData directly on a DataContainer instead
* of using the DataEngine::setData methods.
* If this method is not called, no dataUpdated(..) signals will be emitted!
*/
void scheduleSourcesUpdated();
/**
* Removes a data source.
* @param source the name of the data source to remove
**/
void removeSource(const QString &source);
/**
* Immediately updates all existing sources when called
*/
void updateAllSources();
/**
* Forces an immediate update to all connected sources, even those with
* timeouts that haven't yet expired. This should _only_ be used when
* there was no data available, e.g. due to network non-availability,
* and then it becomes available. Normal changes in data values due to
* calls to updateSource or in the natural progression of the monitored
* object (e.g. CPU heat) should not result in a call to this method!
*
* @since 4.4
*/
void forceImmediateUpdateOfAllVisualizations();
private:
friend class DataEnginePrivate;
friend class DataEngineScript;
friend class DataEngineManager;
friend class PlasmoidServiceJob;
friend class NullEngine;
Q_PRIVATE_SLOT(d, void internalUpdateSource(DataContainer *source))
Q_PRIVATE_SLOT(d, void sourceDestroyed(QObject *object))
DataEnginePrivate *const d;
};
} // Plasma namespace
/**
* Register a data engine when it is contained in a loadable module
*/
#define K_EXPORT_PLASMA_DATAENGINE(libname, classname) \
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN(factory("plasma_engine_" #libname)) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
Q_DECLARE_METATYPE(Plasma::DataEngine*)
#endif // multiple inclusion guard

View File

@ -0,0 +1,161 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "dataengineconsumer.h"
#include "private/dataengineconsumer_p.h"
#include <QSet>
#include <qurlpathinfo.h>
#include <kdebug.h>
#include "private/dataenginemanager_p.h"
#include "private/remotedataengine_p.h"
#include "servicejob.h"
namespace Plasma
{
void DataEngineConsumerPrivate::slotJobFinished(Plasma::ServiceJob *job)
{
#ifndef NDEBUG
kDebug() << "engine ready!";
#endif
QString engineName = job->parameters()["EngineName"].toString();
QString location = job->destination();
QPair<QString, QString> pair(location, engineName);
#ifndef NDEBUG
kDebug() << "pair = " << pair;
#endif
if (!remoteEngines.contains(pair)) {
#ifndef NDEBUG
kDebug() << "engine does not exist yet!";
#endif
} else {
QUrlPathInfo engineLocation = QUrlPathInfo(QUrl(location));
engineLocation.setFileName(job->result().toString());
#ifndef NDEBUG
kDebug() << "setting location : " << engineLocation.url();
#endif
remoteEngines[pair]->setLocation(engineLocation.url());
}
}
void DataEngineConsumerPrivate::slotServiceReady(Plasma::Service *plasmoidService)
{
#ifndef NDEBUG
kDebug() << "service ready!";
#endif
if (!engineNameForService.contains(plasmoidService)) {
#ifndef NDEBUG
kDebug() << "no engine name for service!";
#endif
#ifndef NDEBUG
kDebug() << "amount of services in map: " << engineNameForService.count();
#endif
} else {
#ifndef NDEBUG
kDebug() << "value = " << engineNameForService.value(plasmoidService);
#endif
}
#ifndef NDEBUG
kDebug() << "requesting dataengine!";
#endif
KConfigGroup op = plasmoidService->operationDescription("DataEngine");
op.writeEntry("EngineName", engineNameForService.value(plasmoidService));
plasmoidService->startOperationCall(op);
connect(plasmoidService, SIGNAL(finished(Plasma::ServiceJob*)),
this, SLOT(slotJobFinished(Plasma::ServiceJob*)));
}
DataEngine *DataEngineConsumerPrivate::remoteDataEngine(const QString &name, const QUrl &location)
{
QPair<QString, QString> pair(location.toString(), name);
#ifndef NDEBUG
kDebug() << "pair = " << pair;
#endif
if (remoteEngines.contains(pair)) {
#ifndef NDEBUG
kDebug() << "existing remote dataengine at " << location;
#endif
return remoteEngines[pair];
}
#ifndef NDEBUG
kDebug() << "new remote dataengine at " << location;
#endif
RemoteDataEngine *engine = new RemoteDataEngine(QUrl());
remoteEngines[pair] = engine;
Service *plasmoidService = Service::access(location);
plasmoidService->setDestination(location.toString());
engineNameForService[plasmoidService] = name;
#ifndef NDEBUG
kDebug() << "name = " << name;
#endif
connect(plasmoidService, SIGNAL(serviceReady(Plasma::Service*)),
this, SLOT(slotServiceReady(Plasma::Service*)));
return engine;
}
DataEngineConsumer::DataEngineConsumer()
: d(new DataEngineConsumerPrivate)
{
}
DataEngineConsumer::~DataEngineConsumer()
{
foreach (const QString &engine, d->loadedEngines) {
DataEngineManager::self()->unloadEngine(engine);
}
delete d;
}
DataEngine *DataEngineConsumer::dataEngine(const QString &name, const QUrl &location)
{
if (!location.isEmpty()) {
return d->remoteDataEngine(name, location);
}
if (d->loadedEngines.contains(name)) {
DataEngine *engine = DataEngineManager::self()->engine(name);
if (engine->isValid()) {
return engine;
} else {
d->loadedEngines.remove(name);
}
}
DataEngine *engine = DataEngineManager::self()->loadEngine(name);
if (engine->isValid()) {
d->loadedEngines.insert(name);
}
return engine;
}
} // namespace Plasma
#include "private/moc_dataengineconsumer_p.cpp"

View File

@ -0,0 +1,83 @@
/*
* Copyright 2012 by Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DATAENGINECONSUMER_H
#define PLASMA_DATAENGINECONSUMER_H
#include <QtCore/QUrl>
#include <plasma/plasma_export.h>
namespace Plasma
{
class DataEngine;
class DataEngineConsumerPrivate;
/**
* @class DataEngineConsumer plasma/dataengineconsumer.h <Plasma/DataEngineConsumer>
*
* @brief A class that makes it safe and easy to use DataEngines
*
* DataEngineConsumer provides access to DataEngines, which are internally reference
* counted and shared between all users of them. The only public method provided is
* dataEngine which returns engines upon request.
*
* When the DataEngineConsumer class is deleted, all engines accessed using it are
* de-referenced and possibly deleted (in the case that there are no other users of
* the engine in question).
*
* DataEngineConsumer can be subclassed by other C++ classes to allow this simple
* API to be used directly from these classes in a convenient manner.
**/
class PLASMA_EXPORT DataEngineConsumer
{
public:
/**
* Constructs a DataEngineConsumer
**/
DataEngineConsumer();
~DataEngineConsumer();
/**
* Returns a Plasma::DataEngine. It never returns a null pointer, and the
* DataEngine returned should not be deleted. All DataEngines will be dereferenced
* once this DataEngineConsumer instance is deleted.
*
* It is safe and fast to request the same engine more than once.
*
* @param name the name of the DataEngine. This corresponds to the plugin name
* of the DataEngine.
* @param location if a non-empty URI is passed in, then a connection with a
* remote DataEngine at the location is attempted to be made.
* The returned pointer is a proxy object for this connection.
* In the common case, location is always an empty URI (QUrl())
* and the DataEngine is loaded locally.
*/
DataEngine *dataEngine(const QString &name, const QUrl &location = QUrl());
private:
DataEngineConsumerPrivate * const d;
};
} // namespace Plasma
#endif

View File

@ -0,0 +1,43 @@
Implementation Items
====================
* Applet::screenRect
Functionality Blocks
====================
* QML Wallpaper
* QML Containment
* port Sebas' work for QML Containment to libplasma2
* wallpaper loading
* action plugins access
* applet geometry save/restore
* move ContainmentPrivate::dropData to be a protected member (slot?) so QML Containment can
provide a drop action
* ContainmentActions
* add ToolBox as a recognized trigger
* only return sets of actions
* PopupApplet -> merge into Applet with functionality implemented in QML rather than in libplasma
* QML Tooltips
* ToolTipManager -> replace with a QML component
* QML tips
* View -> dump
* Default Package classes
* Can this be provided by the graphics system specialization?
* make (all?) plugins able to only be available from specific workspaces
* does this mean simply implementing pluginLoaders for the shells?
* better yet -> add shell-specific constraints for PluginLoader to use
* OR not exists [X-Plasma-<something>] or [X-Plasma-<something>] = 'foo'
Porting of Applet and Containment
=================================
* ContainmentPrivate::appletAt(const QPointF &point) -> depends from ContainmentActions refactoring : disabled now in the code
* ContainmentPrivate::setScreen(int newScreen, int newDesktop, bool preventInvalidDesktops)
* all geometry functions in Applet and Containment (width, height, geometry, raise, lower...)
* move Containment::addAssociatedWidget/removeAssociatedWidget in the c++ part of the QML implementation
Porting of Wallpaper
====================
* port complete dropData/mimeTypeRetrieved from ContainmentPrivate to the c++ part of the Containment implementation. The code is right now in intoDeclarativeEngine/declarativecontainment_p.cpp
* Containments should just have a string property for wallpapers that is the name of a Package with the wallpaper qml
* the qml wallpaper must receive a signal when Containment::save() is called so it can do own config save (TODO around line 329 of containment.cpp)
* redo WallpaperPackage, but this time is a package to load qml

1096
plasma/framesvg.cpp Normal file

File diff suppressed because it is too large Load Diff

279
plasma/framesvg.h Normal file
View File

@ -0,0 +1,279 @@
/*
* Copyright 2008 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 Marco Martin <notmart@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_FRAMESVG_H
#define PLASMA_FRAMESVG_H
#include <QtCore/QObject>
#include <QPixmap>
#include <plasma/plasma_export.h>
#include <plasma/plasma.h>
#include <plasma/svg.h>
class QPainter;
class QPoint;
class QPointF;
class QRect;
class QRectF;
class QSize;
class QSizeF;
class QMatrix;
namespace Plasma
{
class FrameSvgPrivate;
/**
* @class FrameSvg plasma/framesvg.h <Plasma/FrameSvg>
*
* @short Provides an SVG with borders.
*
* When using SVG images for a background of an object that may change
* its aspect ratio, such as a dialog, simply scaling a single image
* may not be enough.
*
* FrameSvg allows SVGs to provide several elements for borders as well
* as a central element, each of which are scaled individually. These
* elements should be named
*
* - @c center - the central element, which will be scaled in both directions
* - @c top - the top border; the height is fixed, but it will be scaled
* horizontally to the same width as @c center
* - @c bottom - the bottom border; scaled in the same way as @c top
* - @c left - the left border; the width is fixed, but it will be scaled
* vertically to the same height as @c center
* - @c right - the right border; scaled in the same way as @c left
* - @c topleft - fixed size; must be the same height as @c top and the same
* width as @c left
* - @c bottomleft, @c topright, @c bottomright - similar to @c topleft
*
* @c center must exist, but all the others are optional. @c topleft and
* @c topright will be ignored if @c top does not exist, and similarly for
* @c bottomleft and @c bottomright.
*
* @see Plasma::Svg
**/
class PLASMA_EXPORT FrameSvg : public Svg
{
Q_OBJECT
Q_FLAGS(EnabledBorders)
Q_PROPERTY(EnabledBorders enabledBorders READ enabledBorders WRITE setEnabledBorders)
public:
/**
* These flags represents what borders should be drawn
*/
enum EnabledBorder {
NoBorder = 0,
TopBorder = 1,
BottomBorder = 2,
LeftBorder = 4,
RightBorder = 8,
AllBorders = TopBorder | BottomBorder | LeftBorder | RightBorder
};
Q_DECLARE_FLAGS(EnabledBorders, EnabledBorder)
/**
* Constructs a new FrameSvg that paints the proper named subelements
* as borders. It may also be used as a regular Plasma::Svg object
* for direct access to elements in the Svg.
*
* @param parent options QObject to parent this to
*
* @related Plasma::Theme
*/
explicit FrameSvg(QObject *parent = 0);
~FrameSvg();
/**
* Loads a new Svg
* @param imagePath the new file
*/
Q_INVOKABLE void setImagePath(const QString &path);
/**
* Sets what borders should be painted
* @param flags borders we want to paint
*/
void setEnabledBorders(const EnabledBorders borders);
/**
* Convenience method to get the enabled borders
* @return what borders are painted
*/
EnabledBorders enabledBorders() const;
/**
* Resize the frame maintaining the same border size
* @param size the new size of the frame
*/
Q_INVOKABLE void resizeFrame(const QSizeF &size);
/**
* @returns the size of the frame
*/
Q_INVOKABLE QSizeF frameSize() const;
/**
* Returns the margin size given the margin edge we want
* @param edge the margin edge we want, top, bottom, left or right
* @return the margin size
*/
Q_INVOKABLE qreal marginSize(const Plasma::MarginEdge edge) const;
/**
* Convenience method that extracts the size of the four margins
* in the four output parameters
* @param left left margin size
* @param top top margin size
* @param right right margin size
* @param bottom bottom margin size
*/
Q_INVOKABLE void getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const;
/**
* @return the rectangle of the center element, taking the margins into account.
*/
Q_INVOKABLE QRectF contentsRect() const;
/**
* Sets the prefix (@see setElementPrefix) to 'north', 'south', 'west' and 'east'
* when the location is TopEdge, BottomEdge, LeftEdge and RightEdge,
* respectively. Clears the prefix in other cases.
*
* The prefix must exist in the SVG document, which means that this can only be
* called successfully after setImagePath is called.
* @param location location in the UI this frame will be drawn
*/
Q_INVOKABLE void setElementPrefix(Plasma::Location location);
/**
* Sets the prefix for the SVG elements to be used for painting. For example,
* if prefix is 'active', then instead of using the 'top' element of the SVG
* file to paint the top border, 'active-top' element will be used. The same
* goes for other SVG elements.
*
* If the elements with prefixes are not present, the default ones are used.
* (for the sake of speed, the test is present only for the 'center' element)
*
* Setting the prefix manually resets the location to Floating.
*
* The prefix must exist in the SVG document, which means that this can only be
* called successfully after setImagePath is called.
*
* @param prefix prefix for the SVG elements that make up the frame
*/
Q_INVOKABLE void setElementPrefix(const QString & prefix);
/**
* @return true if the svg has the necessary elements with the given prefix
* to draw a frame
* @param prefix the given prefix we want to check if drawable
*/
Q_INVOKABLE bool hasElementPrefix(const QString & prefix) const;
/**
* This is an overloaded method provided for convenience equivalent to
* hasElementPrefix("north"), hasElementPrefix("south")
* hasElementPrefix("west") and hasElementPrefix("east")
* @return true if the svg has the necessary elements with the given prefix
* to draw a frame.
* @param location the given prefix we want to check if drawable
*/
Q_INVOKABLE bool hasElementPrefix(Plasma::Location location) const;
/**
* Returns the prefix for SVG elements of the FrameSvg
* @return the prefix
*/
Q_INVOKABLE QString prefix();
/**
* Returns a mask that tightly contains the fully opaque areas of the svg
* @return a region of opaque areas
*/
Q_INVOKABLE QRegion mask() const;
/**
* @return a pixmap whose alpha channel is the opacity of the frame. It may be the frame itself or a special frame with the mask- prefix
*/
QPixmap alphaMask() const;
/**
* Sets whether saving all the rendered prefixes in a cache or not
* @param cache if use the cache or not
*/
Q_INVOKABLE void setCacheAllRenderedFrames(bool cache);
/**
* @return if all the different prefixes should be kept in a cache when rendered
*/
Q_INVOKABLE bool cacheAllRenderedFrames() const;
/**
* Deletes the internal cache freeing memory: use this if you want to switch the rendered
* element and you don't plan to switch back to the previous one for a long time and you
* used setUsingRenderingCache(true)
*/
Q_INVOKABLE void clearCache();
/**
* Returns a pixmap of the SVG represented by this object.
*
* @param elelementId the ID string of the element to render, or an empty
* string for the whole SVG (the default)
* @return a QPixmap of the rendered SVG
*/
Q_INVOKABLE QPixmap framePixmap();
/**
* Paints the loaded SVG with the elements that represents the border
* @param painter the QPainter to use
* @param target the target rectangle on the paint device
* @param source the portion rectangle of the source image
*/
Q_INVOKABLE void paintFrame(QPainter *painter, const QRectF &target,
const QRectF &source = QRectF());
/**
* Paints the loaded SVG with the elements that represents the border
* This is an overloaded member provided for convenience
* @param painter the QPainter to use
* @param pos where to paint the svg
*/
Q_INVOKABLE void paintFrame(QPainter *painter, const QPointF &pos = QPointF(0, 0));
private:
FrameSvgPrivate *const d;
friend class Applet;
Q_PRIVATE_SLOT(d, void updateSizes())
Q_PRIVATE_SLOT(d, void updateNeeded())
};
} // Plasma namespace
Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::FrameSvg::EnabledBorders)
#endif // multiple inclusion guard

View File

@ -0,0 +1,53 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* Copyright 2009 Chani Armitage <chani@kde.org>
* Copyright 2012 Marco Martin <notmart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
void Containment::focusNextApplet()
{
if (d->applets.isEmpty()) {
return;
}
int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) + 1 : 0;
if (index >= d->applets.size()) {
index = 0;
}
#ifndef NDEBUG
kDebug() << "index" << index;
#endif
d->focusApplet(d->applets.at(index));
}
void Containment::focusPreviousApplet()
{
if (d->applets.isEmpty()) {
return;
}
int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) - 1 : -1;
if (index < 0) {
index = d->applets.size() - 1;
}
#ifndef NDEBUG
kDebug() << "index" << index;
#endif
d->focusApplet(d->applets.at(index));
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CONTAINMENT_H
#define PLASMA_CONTAINMENT_H
#include <QObject>
#include <QWidget>
#include <kplugininfo.h>
#include <ksharedconfig.h>
#include <plasma/applet.h>
namespace Plasma
{
class AccessAppletJob;
class AppletHandle;
class DataEngine;
class Package;
class Corona;
class View;
class Wallpaper;
class DeclarativeContainmentActions;
class DeclarativeContainmentPrivate;
class AbstractToolBox;
class PLASMA_EXPORT DeclarativeContainment : public Applet
{
Q_OBJECT
public:
void focusNextApplet();
void focusPreviousApplet();
private:
Q_PRIVATE_SLOT(d, void showDropZoneDelayed())
Q_PRIVATE_SLOT(d, void remoteAppletReady(Plasma::AccessAppletJob *))
/**
* This slot is called when the 'stat' after a job event has finished.
*/
Q_PRIVATE_SLOT(d, void mimeTypeRetrieved(KIO::Job *, const QString &))
Q_PRIVATE_SLOT(d, void dropJobResult(KJob *))
DeclarativeContainmentPrivate *const d;
};
} // Plasma namespace
#endif // multiple inclusion guard

View File

@ -0,0 +1,476 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* Copyright 2009 Chani Armitage <chani@kde.org>
* Copyright 2012 Marco Martin <notmart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "private/containment_p.h"
#include <QApplication>
#include <QClipboard>
#include <QMimeData>
#include <QMimeDatabase>
#include <QDropEvent>
#include <qtemporaryfile.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <kcoreauthorized.h>
#include <kurlmimedata.h>
#include <kwindowsystem.h>
#include "config-plasma.h"
#if !PLASMA_NO_KIO
#include "kio/jobclasses.h" // for KIO::JobFlags
#include "kio/job.h"
#include "kio/scheduler.h"
#endif
#include "containmentactions.h"
#include "containmentactionspluginsconfig.h"
#include "corona.h"
#include "pluginloader.h"
#include "svg.h"
#include "remote/accessappletjob.h"
#include "remote/accessmanager.h"
#include "private/applet_p.h"
#include "private/containmentactionspluginsconfig_p.h"
namespace Plasma
{
const char DeclarativeContainmentPrivate::defaultWallpaperMode[] = "SingleImage";
void DeclarativeContainmentPrivate::showDropZoneDelayed()
{
dropZoneStarted = true;
q->showDropZone(dropPoints.value(0).toPoint());
dropPoints.remove(0);
}
void DeclarativeContainmentPrivate::dropData(QPoint screenPos, QDropEvent *dropEvent)
{
if (q->immutability() != Mutable) {
return;
}
const QMimeData *mimeData = 0;
if (dropEvent) {
mimeData = dropEvent->mimeData();
} else {
QClipboard *clipboard = QApplication::clipboard();
mimeData = clipboard->mimeData(QClipboard::Selection);
//TODO if that's not supported (ie non-linux) should we try clipboard instead of selection?
}
if (!mimeData) {
//Selection is either empty or not supported on this OS
#ifndef NDEBUG
kDebug() << "no mime data";
#endif
return;
}
//kDebug() << event->mimeData()->text();
QString appletMimetype(q->corona() ? q->corona()->appletMimeType() : QString());
if (!appletMimetype.isEmpty() && mimeData->hasFormat(appletMimetype)) {
QString data = mimeData->data(appletMimetype);
const QStringList appletNames = data.split('\n', QString::SkipEmptyParts);
foreach (const QString &appletName, appletNames) {
//kDebug() << "doing" << appletName;
QRectF geom(screenPos, QSize(0, 0));
q->addApplet(appletName, QVariantList(), geom);
}
if (dropEvent) {
dropEvent->acceptProposedAction();
}
} else if (mimeData->hasUrls()) {
//TODO: collect the mimeTypes of available script engines and offer
// to create widgets out of the matching URLs, if any
const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(mimeData);
foreach (const QUrl &url, urls) {
if (AccessManager::supportedProtocols().contains(url.scheme())) {
AccessAppletJob *job = AccessManager::self()->accessRemoteApplet(url);
if (dropEvent) {
dropPoints[job] = dropEvent->pos();
} else {
dropPoints[job] = screenPos;
}
QObject::connect(AccessManager::self(), SIGNAL(finished(Plasma::AccessAppletJob*)),
q, SLOT(remoteAppletReady(Plasma::AccessAppletJob*)));
}
#if !PLASMA_NO_KIO
else {
QMimeDatabase db;
QMimeType mime = db.mimeTypeForUrl(url);
QString mimeName = mime.name();
QRectF geom(screenPos, QSize());
QVariantList args;
args << url.toString();
#ifndef NDEBUG
kDebug() << "can decode" << mimeName << args;
#endif
// It may be a directory or a file, let's stat
KIO::JobFlags flags = KIO::HideProgressInfo;
KIO::MimetypeJob *job = KIO::mimetype(url, flags);
if (dropEvent) {
dropPoints[job] = dropEvent->pos();
} else {
dropPoints[job] = screenPos;
}
QObject::connect(job, SIGNAL(result(KJob*)), q, SLOT(dropJobResult(KJob*)));
QObject::connect(job, SIGNAL(mimetype(KIO::Job*,QString)),
q, SLOT(mimeTypeRetrieved(KIO::Job*,QString)));
KMenu *choices = new KMenu("Content dropped");
choices->addAction(KDE::icon("process-working"), i18n("Fetching file type..."));
if (dropEvent) {
choices->popup(dropEvent->pos());
} else {
choices->popup(screenPos);
}
dropMenus[job] = choices;
}
#endif
}
if (dropEvent) {
dropEvent->acceptProposedAction();
}
} else {
QStringList formats = mimeData->formats();
QHash<QString, KPluginInfo> seenPlugins;
QHash<QString, QString> pluginFormats;
foreach (const QString &format, formats) {
KPluginInfo::List plugins = Applet::listAppletInfoForMimeType(format);
foreach (const KPluginInfo &plugin, plugins) {
if (seenPlugins.contains(plugin.pluginName())) {
continue;
}
seenPlugins.insert(plugin.pluginName(), plugin);
pluginFormats.insert(plugin.pluginName(), format);
}
}
//kDebug() << "Mimetype ..." << formats << seenPlugins.keys() << pluginFormats.values();
QString selectedPlugin;
if (seenPlugins.isEmpty()) {
// do nothing
} else if (seenPlugins.count() == 1) {
selectedPlugin = seenPlugins.constBegin().key();
} else {
KMenu choices;
QHash<QAction *, QString> actionsToPlugins;
foreach (const KPluginInfo &info, seenPlugins) {
QAction *action;
if (!info.icon().isEmpty()) {
action = choices.addAction(KDE::icon(info.icon()), info.name());
} else {
action = choices.addAction(info.name());
}
actionsToPlugins.insert(action, info.pluginName());
}
QAction *choice = choices.exec(screenPos);
if (choice) {
selectedPlugin = actionsToPlugins[choice];
}
}
if (!selectedPlugin.isEmpty()) {
if (!dropEvent) {
// since we may have entered an event loop up above with the menu,
// the clipboard item may no longer be valid, as QClipboard resets
// the object behind the back of the application with a zero timer
// so we fetch it again here
QClipboard *clipboard = QApplication::clipboard();
mimeData = clipboard->mimeData(QClipboard::Selection);
}
QTemporaryFile tempFile;
if (mimeData && tempFile.open()) {
//TODO: what should we do with files after the applet is done with them??
tempFile.setAutoRemove(false);
{
QDataStream stream(&tempFile);
QByteArray data = mimeData->data(pluginFormats[selectedPlugin]);
stream.writeRawData(data, data.size());
}
QRectF geom(screenPos, QSize());
QVariantList args;
args << tempFile.fileName();
#ifndef NDEBUG
kDebug() << args;
#endif
tempFile.close();
q->addApplet(selectedPlugin, args, geom);
}
}
}
}
void DeclarativeContainmentPrivate::clearDataForMimeJob(KIO::Job *job)
{
#if !PLASMA_NO_KIO
QObject::disconnect(job, 0, q, 0);
dropPoints.remove(job);
KMenu *choices = dropMenus.take(job);
delete choices;
job->kill();
#endif // PLASMA_NO_KIO
}
void DeclarativeContainmentPrivate::dropJobResult(KJob *job)
{
#if !PLASMA_NO_KIO
KIO::TransferJob* tjob = dynamic_cast<KIO::TransferJob*>(job);
if (!tjob) {
#ifndef NDEBUG
kDebug() << "job is not a KIO::TransferJob, won't handle the drop...";
#endif
clearDataForMimeJob(tjob);
return;
}
if (job->error()) {
#ifndef NDEBUG
kDebug() << "ERROR" << tjob->error() << ' ' << tjob->errorString();
#endif
}
// We call mimeTypeRetrieved since there might be other mechanisms
// for finding suitable applets. Cleanup happens there as well.
mimeTypeRetrieved(qobject_cast<KIO::Job *>(job), QString());
#endif // PLASMA_NO_KIO
}
void DeclarativeContainmentPrivate::mimeTypeRetrieved(KIO::Job *job, const QString &mimeType)
{
#if !PLASMA_NO_KIO
#ifndef NDEBUG
kDebug() << "Mimetype Job returns." << mimeType;
#endif
KIO::TransferJob* tjob = dynamic_cast<KIO::TransferJob*>(job);
if (!tjob) {
#ifndef NDEBUG
kDebug() << "job should be a TransferJob, but isn't";
#endif
clearDataForMimeJob(job);
return;
}
KPluginInfo::List appletList = Applet::listAppletInfoForUrl(tjob->url());
if (mimeType.isEmpty() && !appletList.count()) {
clearDataForMimeJob(job);
#ifndef NDEBUG
kDebug() << "No applets found matching the url (" << tjob->url() << ") or the mimeType (" << mimeType << ")";
#endif
return;
} else {
QPointF posi; // will be overwritten with the event's position
if (dropPoints.keys().contains(tjob)) {
posi = dropPoints[tjob];
#ifndef NDEBUG
kDebug() << "Received a suitable dropEvent at" << posi;
#endif
} else {
#ifndef NDEBUG
kDebug() << "Bailing out. Cannot find associated dropEvent related to the TransferJob";
#endif
clearDataForMimeJob(job);
return;
}
KMenu *choices = dropMenus.value(tjob);
if (!choices) {
#ifndef NDEBUG
kDebug() << "Bailing out. No QMenu found for this job.";
#endif
clearDataForMimeJob(job);
return;
}
QVariantList args;
args << tjob->url().toString() << mimeType;
#ifndef NDEBUG
kDebug() << "Creating menu for:" << mimeType << posi << args;
#endif
appletList << Applet::listAppletInfoForMimeType(mimeType);
KPluginInfo::List wallpaperList;
if (drawWallpaper) {
if (wallpaper && wallpaper->supportsMimetype(mimeType)) {
wallpaperList << wallpaper->d->wallpaperDescription;
} else {
wallpaperList = Wallpaper::listWallpaperInfoForMimeType(mimeType);
}
}
if (!appletList.isEmpty() || !wallpaperList.isEmpty()) {
choices->clear();
QHash<QAction *, QString> actionsToApplets;
choices->addTitle(i18n("Widgets"));
foreach (const KPluginInfo &info, appletList) {
#ifndef NDEBUG
kDebug() << info.name();
#endif
QAction *action;
if (!info.icon().isEmpty()) {
action = choices->addAction(KDE::icon(info.icon()), info.name());
} else {
action = choices->addAction(info.name());
}
actionsToApplets.insert(action, info.pluginName());
#ifndef NDEBUG
kDebug() << info.pluginName();
#endif
}
actionsToApplets.insert(choices->addAction(i18n("Icon")), "icon");
QHash<QAction *, QString> actionsToWallpapers;
if (!wallpaperList.isEmpty()) {
choices->addTitle(i18n("Wallpaper"));
QMap<QString, KPluginInfo> sorted;
foreach (const KPluginInfo &info, appletList) {
sorted.insert(info.name(), info);
}
foreach (const KPluginInfo &info, wallpaperList) {
QAction *action;
if (!info.icon().isEmpty()) {
action = choices->addAction(KDE::icon(info.icon()), info.name());
} else {
action = choices->addAction(info.name());
}
actionsToWallpapers.insert(action, info.pluginName());
}
}
QAction *choice = choices->exec();
if (choice) {
// Put the job on hold so it can be recycled to fetch the actual content,
// which is to be expected when something's dropped onto the desktop and
// an applet is to be created with this URL
if (!mimeType.isEmpty() && !tjob->error()) {
tjob->putOnHold();
KIO::Scheduler::publishSlaveOnHold();
}
QString plugin = actionsToApplets.value(choice);
if (plugin.isEmpty()) {
//set wallpapery stuff
plugin = actionsToWallpapers.value(choice);
if (!wallpaper || plugin != wallpaper->pluginName()) {
//kDebug() << "Wallpaper dropped:" << tjob->url();
q->setWallpaper(plugin);
}
if (wallpaper) {
//kDebug() << "Wallpaper dropped:" << tjob->url();
wallpaper->addUrls(QList<QUrl>() << tjob->url());
}
} else {
addApplet(actionsToApplets[choice], args, QRectF(posi, QSize()));
}
clearDataForMimeJob(job);
return;
}
} else {
// we can at least create an icon as a link to the URL
addApplet("icon", args, QRectF(posi, QSize()));
}
}
clearDataForMimeJob(job);
#endif // PLASMA_NO_KIO
}
void DeclarativeContainmentPrivate::focusApplet(Plasma::Applet *applet)
{
if (focusedApplet == applet) {
return;
}
QList<QWidget *> widgets = actions()->associatedWidgets();
if (focusedApplet) {
foreach (QWidget *w, widgets) {
focusedApplet->removeAssociatedWidget(w);
}
}
if (applet && applets.contains(applet)) {
//kDebug() << "switching to" << applet->name();
focusedApplet = applet;
foreach (QWidget *w, widgets) {
focusedApplet->addAssociatedWidget(w);
}
if (!focusedApplet->hasFocus()) {
focusedApplet->setFocus(Qt::ShortcutFocusReason);
}
} else {
focusedApplet = 0;
}
}
void DeclarativeContainmentPrivate::remoteAppletReady(Plasma::AccessAppletJob *job)
{
QPointF pos = dropPoints.take(job);
if (job->error()) {
//TODO: nice user visible error handling (knotification probably?)
#ifndef NDEBUG
kDebug() << "remote applet access failed: " << job->errorText();
#endif
return;
}
if (!job->applet()) {
#ifndef NDEBUG
kDebug() << "how did we end up here? if applet is null, the job->error should be nonzero";
#endif
return;
}
q->addApplet(job->applet(), pos);
}
}

View File

@ -0,0 +1,102 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* Copyright 2012 by Marco MArtin <mart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DECLARATIVECONTAINMENT_P_H
#define DECLARATIVECONTAINMENT_P_H
#include <kactioncollection.h>
#include <kmenu.h>
#include "plasma.h"
#include "applet.h"
#include "corona.h"
class KJob;
namespace KIO
{
class Job;
}
namespace Plasma
{
class AccessAppletJob;
class Containment;
class DeclarativeContainmentPrivate
{
public:
DeclarativeContainmentPrivate(Containment *c)
: q(c),
focusedApplet(0),
wallpaper(0),
showDropZoneDelayTimer(0),
dropZoneStarted(false),
{
}
~DeclarativeContainmentPrivate()
{
qDeleteAll(dropMenus);
dropMenus.clear();
}
void clearDataForMimeJob(KIO::Job *job);
void mimeTypeRetrieved(KIO::Job *job, const QString &mimetype);
void dropJobResult(KJob *);
void remoteAppletReady(Plasma::AccessAppletJob *job);
/**
* give keyboard focus to applet within this containment
*/
void focusApplet(Plasma::Applet *applet);
/**
* Handles dropped/pasted mimetype data
* @param screenPos screen-relative position
* @param dropEvent the drop event (if null, the clipboard is used instead)
*/
void dropData(QPoint screenPos, QDropEvent *dropEvent = 0);
/**
* Delayed drop zone display
*/
void showDropZoneDelayed();
DeclarativeContainment *q;
Applet *focusedApplet;
Plasma::Wallpaper *wallpaper;
QHash<KJob*, QPointF> dropPoints;
QHash<KJob*, KMenu*> dropMenus;
QTimer *showDropZoneDelayTimer;
bool dropZoneStarted : 1;
static const char defaultWallpaper[];
static const char defaultWallpaperMode[];
};
} // Plasma namespace
#endif

View File

@ -0,0 +1,335 @@
/*
* Copyright 2010 Marco Martin <mart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "declarativewidget.h"
#include <QDeclarativeComponent>
#include <QDeclarativeItem>
#include <QDeclarativeEngine>
#include <QDeclarativeContext>
#include <QScriptEngine>
#include <QGraphicsLinearLayout>
#include <QGraphicsScene>
#include <QTimer>
#include <kdebug.h>
#include <kdeclarative.h>
#include "private/declarative/declarativenetworkaccessmanagerfactory_p.h"
#include "private/declarative/dataenginebindings_p.h"
namespace Plasma
{
class DeclarativeWidgetPrivate
{
public:
DeclarativeWidgetPrivate(DeclarativeWidget *parent)
: q(parent),
engine(0),
scriptEngine(0),
component(0),
root(0),
delay(false)
{
}
~DeclarativeWidgetPrivate()
{
}
void errorPrint();
void execute(const QString &fileName);
void finishExecute();
void scheduleExecutionEnd();
void minimumWidthChanged();
void minimumHeightChanged();
void maximumWidthChanged();
void maximumHeightChanged();
void preferredWidthChanged();
void preferredHeightChanged();
DeclarativeWidget *q;
QString qmlPath;
QDeclarativeEngine* engine;
QScriptEngine *scriptEngine;
QDeclarativeComponent* component;
QObject *root;
bool delay : 1;
};
void DeclarativeWidgetPrivate::errorPrint()
{
QString errorStr = "Error loading QML file.\n";
if(component->isError()){
QList<QDeclarativeError> errors = component->errors();
foreach (const QDeclarativeError &error, errors) {
errorStr += (error.line()>0?QString(QString::number(error.line()) + QLatin1String(": ")):QLatin1String(""))
+ error.description() + '\n';
}
}
kWarning() << component->url().toString() + '\n' + errorStr;
}
void DeclarativeWidgetPrivate::execute(const QString &fileName)
{
if (fileName.isEmpty()) {
#ifndef NDEBUG
kDebug() << "File name empty!";
#endif
return;
}
KDeclarative kdeclarative;
kdeclarative.setDeclarativeEngine(engine);
kdeclarative.initialize();
//binds things like kconfig and icons
kdeclarative.setupBindings();
component->loadUrl(QUrl::fromLocalFile(fileName));
scriptEngine = kdeclarative.scriptEngine();
registerDataEngineMetaTypes(scriptEngine);
if (delay) {
QTimer::singleShot(0, q, SLOT(scheduleExecutionEnd()));
} else {
scheduleExecutionEnd();
}
}
void DeclarativeWidgetPrivate::scheduleExecutionEnd()
{
if (component->isReady() || component->isError()) {
finishExecute();
} else {
QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), q, SLOT(finishExecute()));
}
}
void DeclarativeWidgetPrivate::finishExecute()
{
if (component->isError()) {
errorPrint();
}
root = component->create();
if (!root) {
errorPrint();
}
#ifndef NDEBUG
kDebug() << "Execution of QML done!";
#endif
QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget*>(root);
QGraphicsObject *object = dynamic_cast<QGraphicsObject *>(root);
if (object) {
static_cast<QGraphicsItem *>(object)->setParentItem(q);
}
if (widget) {
q->setPreferredSize(-1,-1);
QGraphicsLinearLayout *lay = static_cast<QGraphicsLinearLayout *>(q->layout());
if (!lay) {
lay = new QGraphicsLinearLayout(q);
lay->setContentsMargins(0, 0, 0, 0);
}
lay->addItem(widget);
} else {
q->setLayout(0);
qreal minimumWidth = 0;
qreal minimumHeight = 0;
qreal maximumWidth = 0;
qreal maximumHeight = 0;
qreal preferredWidth = 0;
qreal preferredHeight = 0;
if (object) {
object->setProperty("width", q->size().width());
object->setProperty("height", q->size().height());
if (object->metaObject()->indexOfProperty("minimumWidth")>=0) {
minimumWidth = object->property("minimumWidth").toReal();
QObject::connect(object, SIGNAL(minimumWidthChanged()), q, SLOT(minimumWidthChanged()));
}
if (object->metaObject()->indexOfProperty("minimumHeight")>=0) {
minimumHeight = object->property("minimumHeight").toReal();
QObject::connect(object, SIGNAL(minimumHeightChanged()), q, SLOT(minimumHeightChanged()));
}
if (object->metaObject()->indexOfProperty("maximumWidth")>=0) {
maximumWidth = object->property("maximumWidth").toReal();
QObject::connect(object, SIGNAL(maximumWidthChanged()), q, SLOT(maximumWidthChanged()));
}
if (object->metaObject()->indexOfProperty("maximumHeight")>=0) {
maximumHeight = object->property("maximumHeight").toReal();
QObject::connect(object, SIGNAL(maximumHeightChanged()), q, SLOT(maximumHeightChanged()));
}
if (object->metaObject()->indexOfProperty("preferredWidth")>=0) {
preferredWidth = object->property("preferredWidth").toReal();
QObject::connect(object, SIGNAL(preferredWidthChanged()), q, SLOT(preferredWidthChanged()));
}
if (object->metaObject()->indexOfProperty("preferredHeight")>=0) {
preferredHeight = object->property("preferredHeight").toReal();
QObject::connect(object, SIGNAL(preferredHeightChanged()), q, SLOT(preferredHeightChanged()));
}
}
if (minimumWidth > 0 && minimumHeight > 0) {
q->setMinimumSize(minimumWidth, minimumHeight);
} else {
q->setMinimumSize(-1, -1);
}
if (maximumWidth > 0 && maximumHeight > 0) {
q->setMaximumSize(maximumWidth, maximumHeight);
} else {
q->setMaximumSize(-1, -1);
}
if (preferredWidth > 0 && preferredHeight > 0) {
q->setPreferredSize(preferredWidth, preferredHeight);
} else {
q->setPreferredSize(-1, -1);
}
}
emit q->finished();
}
void DeclarativeWidgetPrivate::minimumWidthChanged()
{
qreal minimumWidth = root->property("minimumWidth").toReal();
q->setMinimumWidth(minimumWidth);
}
void DeclarativeWidgetPrivate::minimumHeightChanged()
{
qreal minimumHeight = root->property("minimumHeight").toReal();
q->setMinimumHeight(minimumHeight);
}
void DeclarativeWidgetPrivate::maximumWidthChanged()
{
qreal maximumWidth = root->property("maximumWidth").toReal();
q->setMaximumWidth(maximumWidth);
}
void DeclarativeWidgetPrivate::maximumHeightChanged()
{
qreal maximumHeight = root->property("maximumHeight").toReal();
q->setMaximumHeight(maximumHeight);
}
void DeclarativeWidgetPrivate::preferredWidthChanged()
{
qreal preferredWidth = root->property("preferredWidth").toReal();
q->setPreferredWidth(preferredWidth);
}
void DeclarativeWidgetPrivate::preferredHeightChanged()
{
qreal preferredHeight = root->property("preferredHeight").toReal();
q->setPreferredHeight(preferredHeight);
}
DeclarativeWidget::DeclarativeWidget(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new DeclarativeWidgetPrivate(this))
{
setFlag(QGraphicsItem::ItemHasNoContents);
d->engine = new QDeclarativeEngine(this);
d->engine->setNetworkAccessManagerFactory(new DeclarativeNetworkAccessManagerFactory);
d->component = new QDeclarativeComponent(d->engine, this);
}
DeclarativeWidget::~DeclarativeWidget()
{
QDeclarativeNetworkAccessManagerFactory *factory = d->engine->networkAccessManagerFactory();
d->engine->setNetworkAccessManagerFactory(0);
delete factory;
delete d;
}
void DeclarativeWidget::setQmlPath(const QString &path)
{
d->qmlPath = path;
d->execute(path);
}
QString DeclarativeWidget::qmlPath() const
{
return d->qmlPath;
}
void DeclarativeWidget::setInitializationDelayed(const bool delay)
{
d->delay = delay;
}
bool DeclarativeWidget::isInitializationDelayed() const
{
return d->delay;
}
QDeclarativeEngine* DeclarativeWidget::engine()
{
return d->engine;
}
QScriptEngine *DeclarativeWidget::scriptEngine() const
{
return d->scriptEngine;
}
QObject *DeclarativeWidget::rootObject() const
{
return d->root;
}
QDeclarativeComponent *DeclarativeWidget::mainComponent() const
{
return d->component;
}
void DeclarativeWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
{
QGraphicsWidget::resizeEvent(event);
if (d->root) {
d->root->setProperty("width", size().width());
d->root->setProperty("height", size().height());
}
}
} // namespace Plasma
#include "moc_declarativewidget.cpp"

View File

@ -0,0 +1,142 @@
/*
* Copyright 2010 Marco Martin <mart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DECLARATIVEWIDGET_H
#define PLASMA_DECLARATIVEWIDGET_H
#include <QGraphicsWidget>
#include <plasma/plasma_export.h>
class QDeclarativeEngine;
class QDeclarativeComponent;
class QScriptEngine;
namespace Plasma
{
class DeclarativeWidgetPrivate;
/**
* @class DeclarativeWidget plasma/declarativewidget.h <Plasma/DeclarativeWidget>
*
* @author Marco Martin <mart@kde.org>
*
* @short A widget that contains an entire QML context, with its own declarative engine
*
* Plasma::DeclarativeWidget provides a class for conveniently use QML based
* declarative user interfaces inside Plasma widgets.
* To one DeclarativeWidget corresponds one QML file (that can eventually include others)
* tere will be its own QDeclarativeEngine with a single root object,
* described in the QML file.
*/
class PLASMA_EXPORT DeclarativeWidget : public QGraphicsWidget
{
Q_OBJECT
Q_PROPERTY(QString qmlPath READ qmlPath WRITE setQmlPath)
Q_PROPERTY(bool initializationDelayed READ isInitializationDelayed WRITE setInitializationDelayed)
Q_PROPERTY(QObject * rootObject READ rootObject)
public:
/**
* Constructs a new DeclarativeWidget
*
* @param parent the parent of this widget
*/
explicit DeclarativeWidget(QGraphicsWidget *parent = 0);
~DeclarativeWidget();
/**
* Sets the path of the QML file to parse and execute
*
* @param path the absolute path of a QML file
*/
void setQmlPath(const QString &path);
/**
* @return the absolute path of the current QML file
*/
QString qmlPath() const;
/**
* Sets whether the execution of the QML file has to be delayed later in the event loop. It has to be called before setQmlPath().
* In this case will be possible to assign new objects in the main engine context
* before the main component gets initialized.
* So it will be possible to access it immediately from the QML code.
*
* @param delay if true the initialization of the QML file will be delayed
* at the end of the event loop
*/
void setInitializationDelayed(const bool delay);
/**
* @return true if the initialization of the QML file will be delayed
* at the end of the event loop
*/
bool isInitializationDelayed() const;
/**
* @return the declarative engine that runs the qml file assigned to this widget.
*/
QDeclarativeEngine* engine();
/**
* @return the script engine used by the declarative engine
* @since 4.7
*/
QScriptEngine *scriptEngine() const;
/**
* @return the root object of the declarative object tree
*/
QObject *rootObject() const;
/**
* @return the main QDeclarativeComponent of the engine
*/
QDeclarativeComponent *mainComponent() const;
protected:
void resizeEvent(QGraphicsSceneResizeEvent *event);
Q_SIGNALS:
/**
* Emitted when the parsing and execution of the QML file is terminated
*/
void finished();
private:
friend class DeclarativeWidgetPrivate;
DeclarativeWidgetPrivate * const d;
Q_PRIVATE_SLOT(d, void finishExecute())
Q_PRIVATE_SLOT(d, void scheduleExecutionEnd())
Q_PRIVATE_SLOT(d, void minimumWidthChanged())
Q_PRIVATE_SLOT(d, void minimumHeightChanged())
Q_PRIVATE_SLOT(d, void maximumWidthChanged())
Q_PRIVATE_SLOT(d, void maximumHeightChanged())
Q_PRIVATE_SLOT(d, void preferredWidthChanged())
Q_PRIVATE_SLOT(d, void preferredHeightChanged())
};
} // namespace Plasma
#endif // multiple inclusion guard

777
plasma/package.cpp Normal file
View File

@ -0,0 +1,777 @@
/******************************************************************************
* Copyright 2007 by Aaron Seigo <aseigo@kde.org> *
* Copyright 2010 by Marco Martin <notmart@gmail.com> *
* Copyright 2010 by Kevin Ottens <ervin@kde.org> *
* Copyright 2009 by Rob Scheepmaker *
* *
* 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 "package.h"
#include <qtemporarydir.h>
#include <karchive.h>
#include <kdebug.h>
#include <kdesktopfile.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#include <ktar.h>
#include <kzip.h>
#include "config-plasma.h"
#include <qstandardpaths.h>
#include <qmimedatabase.h>
#include "packagestructure.h"
#include "pluginloader.h"
#include "private/package_p.h"
#include "private/packages_p.h"
#include "private/packagejob_p.h"
namespace Plasma
{
Package::Package(PackageStructure *structure)
: d(new PackagePrivate())
{
d->structure = structure;
if (d->structure) {
d->structure.data()->initPackage(this);
}
}
Package::Package(const Package &other)
: d(other.d)
{
}
Package::~Package()
{
}
Package &Package::operator=(const Package &rhs)
{
if (&rhs != this) {
d = rhs.d;
}
return *this;
}
bool Package::isValid() const
{
if (!d->valid) {
return false;
}
//search for the file in all prefixes and in all possible paths for each prefix
//even if it's a big nested loop, usually there is one prefix and one location
//so shouldn't cause too much disk access
QHashIterator<QByteArray, ContentStructure> it(d->contents);
while (it.hasNext()) {
it.next();
if (!it.value().required) {
continue;
}
bool failed = true;
foreach (const QString &path, it.value().paths) {
foreach (const QString &prefix, d->contentsPrefixPaths) {
if (QFile::exists(d->path + prefix + path)) {
failed = false;
break;
}
}
if (!failed) {
break;
}
}
if (failed) {
kWarning() << "Could not find required" << (it.value().directory ? "directory" : "file") << it.key();
d->valid = false;
return false;
}
}
return true;
}
QString Package::name(const char *key) const
{
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
if (it == d->contents.constEnd()) {
return QString();
}
return it.value().name;
#else
Q_UNUSED(key);
return QString();
#endif
}
bool Package::isRequired(const char *key) const
{
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
if (it == d->contents.constEnd()) {
return false;
}
return it.value().required;
}
QStringList Package::mimeTypes(const char *key) const
{
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
if (it == d->contents.constEnd()) {
return QStringList();
}
if (it.value().mimeTypes.isEmpty()) {
return d->mimeTypes;
}
return it.value().mimeTypes;
#else
return QStringList();
#endif
}
QString Package::defaultPackageRoot() const
{
return d->defaultPackageRoot;
}
void Package::setDefaultPackageRoot(const QString &packageRoot)
{
d.detach();
d->defaultPackageRoot = packageRoot;
if (!d->defaultPackageRoot.isEmpty() && !d->defaultPackageRoot.endsWith('/')) {
d->defaultPackageRoot.append('/');
}
}
QString Package::servicePrefix() const
{
return d->servicePrefix;
}
void Package::setServicePrefix(const QString &servicePrefix)
{
d.detach();
d->servicePrefix = servicePrefix;
}
bool Package::allowExternalPaths() const
{
return d->externalPaths;
}
void Package::setAllowExternalPaths(bool allow)
{
d.detach();
d->externalPaths = allow;
}
KPluginInfo Package::metadata() const
{
if (!d->metadata && !d->path.isEmpty()) {
const QString metadataPath = filePath("metadata");
if (!metadataPath.isEmpty()) {
d->createPackageMetadata(metadataPath);
} else {
QFileInfo fileInfo(d->path);
if (fileInfo.isDir()) {
d->createPackageMetadata(d->path);
} else if (fileInfo.exists()) {
KArchive *archive = 0;
QMimeDatabase db;
QMimeType mimeType = db.mimeTypeForFile(d->path);
if (mimeType.inherits("application/zip")) {
archive = new KZip(d->path);
} else if (mimeType.inherits("application/x-compressed-tar") || mimeType.inherits("application/x-gzip") ||
mimeType.inherits("application/x-tar") || mimeType.inherits("application/x-bzip-compressed-tar") ||
mimeType.inherits("application/x-xz") || mimeType.inherits("application/x-lzma")) {
archive = new KTar(d->path);
} else {
kWarning() << "Could not open package file, unsupported archive format:" << d->path << mimeType.name();
}
if (archive && archive->open(QIODevice::ReadOnly)) {
const KArchiveDirectory *source = archive->directory();
QTemporaryDir tempdir;
source->copyTo(tempdir.path() + '/');
d->createPackageMetadata(tempdir.path() + '/');
} else {
kWarning() << "Could not open package file:" << d->path;
}
delete archive;
}
}
}
if (!d->metadata) {
d->metadata = new KPluginInfo();
}
return *d->metadata;
}
QString Package::filePath(const char *fileType, const QString &filename) const
{
if (!d->valid) {
//kDebug() << "package is not valid";
return QString();
}
const QString discoveryKey(fileType + filename);
if (d->discoveries.contains(discoveryKey)) {
//qDebug() << "looking for" << discoveryKey << d->discoveries.value(discoveryKey);
return d->discoveries[discoveryKey];
}
QStringList paths;
if (qstrlen(fileType) != 0) {
if (!d->contents.contains(fileType)) {
//kDebug() << "package does not contain" << fileType << filename;
return QString();
}
paths = d->contents[fileType].paths;
if (paths.isEmpty()) {
//kDebug() << "no matching path came of it, while looking for" << fileType << filename;
d->discoveries.insert(discoveryKey, QString());
return QString();
}
} else {
//when filetype is empty paths is always empty, so try with an empty string
paths << QString();
}
//Nested loop, but in the medium case resolves to just one iteration
//kDebug() << "prefixes:" << prefixes.count() << prefixes;
foreach (const QString &contentsPrefix, d->contentsPrefixPaths) {
const QString prefix(d->path + contentsPrefix);
foreach (const QString &path, paths) {
QString file = prefix + path;
if (!filename.isEmpty()) {
file.append("/").append(filename);
}
//kDebug() << "testing" << file << QFile::exists("/bin/ls") << QFile::exists(file);
if (QFile::exists(file)) {
if (d->externalPaths) {
//kDebug() << "found" << file;
d->discoveries.insert(discoveryKey, file);
return file;
}
// ensure that we don't return files outside of our base path
// due to symlink or ../ games
QDir dir(file);
QString canonicalized = dir.canonicalPath() + QDir::separator();
//kDebug() << "testing that" << canonicalized << "is in" << d->path;
if (canonicalized.startsWith(d->path)) {
//kDebug() << "found" << file;
d->discoveries.insert(discoveryKey, file);
return file;
}
}
}
}
//kDebug() << fileType << filename << "does not exist in" << prefixes << "at root" << d->path;
return QString();
}
QStringList Package::entryList(const char *key) const
{
if (!d->valid) {
return QStringList();
}
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
if (it == d->contents.constEnd()) {
//kDebug() << "couldn't find" << key;
return QStringList();
}
//kDebug() << "going to list" << key;
QStringList list;
foreach (const QString &prefix, d->contentsPrefixPaths) {
//kDebug() << " looking in" << prefix;
foreach (const QString &path, it.value().paths) {
//kDebug() << " looking in" << path;
if (it.value().directory) {
//kDebug() << "it's a directory, so trying out" << d->path + prefix + path;
QDir dir(d->path + prefix + path);
if (d->externalPaths) {
list += dir.entryList(QDir::Files | QDir::Readable);
} else {
// ensure that we don't return files outside of our base path
// due to symlink or ../ games
QString canonicalized = dir.canonicalPath();
if (canonicalized.startsWith(d->path)) {
list += dir.entryList(QDir::Files | QDir::Readable);
}
}
} else {
const QString fullPath = d->path + prefix + path;
//kDebug() << "it's a file at" << fullPath << QFile::exists(fullPath);
if (!QFile::exists(fullPath)) {
continue;
}
if (d->externalPaths) {
list += fullPath;
} else {
QDir dir(fullPath);
QString canonicalized = dir.canonicalPath() + QDir::separator();
//kDebug() << "testing that" << canonicalized << "is in" << d->path;
if (canonicalized.startsWith(d->path)) {
list += fullPath;
}
}
}
}
}
return list;
}
void Package::setPath(const QString &path)
{
kDebug() << "Package::setPath() " << path;
if (path == d->path) {
return;
}
d.detach();
d->discoveries.clear();
if (path.isEmpty()) {
d->path.clear();
d->valid = false;
if (d->structure) {
d->structure.data()->pathChanged(this);
}
return;
}
QDir dir(path);
if (dir.isRelative()) {
QString location;
//kDebug() <<
if (!d->defaultPackageRoot.isEmpty()) {
dir.setPath(d->defaultPackageRoot);
if (dir.isRelative()) {
location = QStandardPaths::locate(QStandardPaths::GenericDataLocation, d->defaultPackageRoot + path, QStandardPaths::LocateDirectory);
} else {
location = d->defaultPackageRoot + path;
}
}
if (location.isEmpty()) {
location = QStandardPaths::locate(QStandardPaths::GenericDataLocation, path, QStandardPaths::LocateDirectory);
if (location.isEmpty()) {
d->path.clear();
d->valid = false;
return;
}
}
dir.setPath(location);
}
QString basePath = dir.canonicalPath();
bool valid = QFile::exists(basePath);
if (valid) {
QFileInfo info(basePath);
if (info.isDir() && !basePath.endsWith('/')) {
basePath.append('/');
}
kDebug() << "basePath is" << basePath;
} else {
#ifndef NDEBUG
kDebug() << path << "invalid, basePath is" << basePath;
#endif
return;
}
if (d->path == basePath) {
return;
}
d->path = basePath;
delete d->metadata;
d->metadata = 0;
d->valid = !d->path.isEmpty();
if (d->structure) {
d->structure.data()->pathChanged(this);
}
}
const QString Package::path() const
{
return d->path;
}
QStringList Package::contentsPrefixPaths() const
{
return d->contentsPrefixPaths;
}
void Package::setContentsPrefixPaths(const QStringList &prefixPaths)
{
d.detach();
d->contentsPrefixPaths = prefixPaths;
if (d->contentsPrefixPaths.isEmpty()) {
d->contentsPrefixPaths << QString();
} else {
// the code assumes that the prefixes have a trailing slash
// so let's make that true here
QMutableStringListIterator it(d->contentsPrefixPaths);
while (it.hasNext()) {
it.next();
if (!it.value().endsWith('/')) {
it.setValue(it.value() % '/');
}
}
}
}
QString Package::contentsHash() const
{
if (!d->valid) {
kWarning() << "can not create hash due to Package being invalid";
return QString();
}
QCryptographicHash hash(QCryptographicHash::Sha1);
QString metadataPath = d->path + "metadata.desktop";
if (QFile::exists(metadataPath)) {
QFile f(metadataPath);
if (f.open(QIODevice::ReadOnly)) {
while (!f.atEnd()) {
hash.addData(f.read(1024));
}
} else {
kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading.";
}
} else {
kWarning() << "no metadata at" << metadataPath;
}
foreach (QString prefix, d->contentsPrefixPaths) {
const QString basePath = d->path + prefix;
QDir dir(basePath);
if (!dir.exists()) {
return QString();
}
d->updateHash(basePath, QString(), dir, hash);
}
return hash.result().toHex();
}
void Package::addDirectoryDefinition(const char *key, const QString &path, const QString &name)
{
ContentStructure s;
if (d->contents.contains(key)) {
s = d->contents[key];
}
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
if (!name.isEmpty()) {
s.name = name;
}
#else
Q_UNUSED(name)
#endif
s.paths.append(path);
s.directory = true;
d->contents[key] = s;
}
void Package::addFileDefinition(const char *key, const QString &path, const QString &name)
{
ContentStructure s;
if (d->contents.contains(key)) {
s = d->contents[key];
}
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
if (!name.isEmpty()) {
s.name = name;
}
#else
Q_UNUSED(name)
#endif
s.paths.append(path);
s.directory = false;
d->contents[key] = s;
}
void Package::removeDefinition(const char *key)
{
d->contents.remove(key);
}
void Package::setRequired(const char *key, bool required)
{
QHash<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
if (it == d->contents.end()) {
return;
}
d.detach();
it.value().required = required;
}
void Package::setDefaultMimeTypes(QStringList mimeTypes)
{
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
d.detach();
d->mimeTypes = mimeTypes;
#endif
}
void Package::setMimeTypes(const char *key, QStringList mimeTypes)
{
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
QHash<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
if (it == d->contents.end()) {
return;
}
d.detach();
it.value().mimeTypes = mimeTypes;
#endif
}
QList<const char*> Package::directories() const
{
QList<const char*> dirs;
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
while (it != d->contents.constEnd()) {
if (it.value().directory) {
dirs << it.key();
}
++it;
}
return dirs;
}
QList<const char*> Package::requiredDirectories() const
{
QList<const char*> dirs;
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
while (it != d->contents.constEnd()) {
if (it.value().directory &&
it.value().required) {
dirs << it.key();
}
++it;
}
return dirs;
}
QList<const char*> Package::files() const
{
QList<const char*> files;
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
while (it != d->contents.constEnd()) {
if (!it.value().directory) {
files << it.key();
}
++it;
}
return files;
}
QList<const char*> Package::requiredFiles() const
{
QList<const char*> files;
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
while (it != d->contents.constEnd()) {
if (!it.value().directory && it.value().required) {
files << it.key();
}
++it;
}
return files;
}
KJob* Package::install(const QString &sourcePackage, const QString &packageRoot)
{
const QString src = sourcePackage;
const QString dest = packageRoot.isEmpty() ? defaultPackageRoot() : packageRoot;
//kDebug() << "Source: " << src;
//kDebug() << "PackageRoot: " << dest;
d->path = packageRoot + "plasma-applet-org.kde.microblog-qml";
KJob *j = d->structure.data()->install(this, src, dest);
//connect(j, SIGNAL(finished(bool)), SLOT(installFinished(bool)));
return j;
}
KJob* Package::uninstall(const QString &packageName, const QString &packageRoot)
{
const QString pname = metadata().pluginName();
QString proot = path();
proot.replace(pname, "");
kDebug() << "Package::uninstalling ... " << packageRoot << proot << pname << packageName;
return d->structure.data()->uninstall(this, packageRoot);
}
PackagePrivate::PackagePrivate()
: QSharedData(),
servicePrefix("plasma-applet-"),
metadata(0),
externalPaths(false),
valid(false)
{
contentsPrefixPaths << "contents/";
}
PackagePrivate::PackagePrivate(const PackagePrivate &other)
: QSharedData()
{
*this = other;
metadata = 0;
}
PackagePrivate::~PackagePrivate()
{
delete metadata;
}
PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
{
if (&rhs == this) {
return *this;
}
structure = rhs.structure;
path = rhs.path;
contentsPrefixPaths = rhs.contentsPrefixPaths;
servicePrefix = rhs.servicePrefix;
contents = rhs.contents;
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
mimeTypes = rhs.mimeTypes;
#endif
defaultPackageRoot = rhs.defaultPackageRoot;
servicePrefix = rhs.servicePrefix;
metadata = 0;
externalPaths = rhs.externalPaths;
valid = rhs.valid;
return *this;
}
void PackagePrivate::updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash)
{
// hash is calculated as a function of:
// * files ordered alphabetically by name, with each file's:
// * path relative to the content root
// * file data
// * directories ordered alphabetically by name, with each dir's:
// * path relative to the content root
// * file listing (recursing)
// symlinks (in both the file and dir case) are handled by adding
// the name of the symlink itself and the abs path of what it points to
const QDir::SortFlags sorting = QDir::Name | QDir::IgnoreCase;
const QDir::Filters filters = QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
foreach (const QString &file, dir.entryList(QDir::Files | filters, sorting)) {
if (!subPath.isEmpty()) {
hash.addData(subPath.toUtf8());
}
hash.addData(file.toUtf8());
QFileInfo info(dir.path() + '/' + file);
if (info.isSymLink()) {
hash.addData(info.symLinkTarget().toUtf8());
} else {
QFile f(info.filePath());
if (f.open(QIODevice::ReadOnly)) {
while (!f.atEnd()) {
hash.addData(f.read(1024));
}
} else {
kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading. "
<< "permissions fail?" << info.permissions() << info.isFile();
}
}
}
foreach (const QString &subDirPath, dir.entryList(QDir::Dirs | filters, sorting)) {
const QString relativePath = subPath + subDirPath + '/';
hash.addData(relativePath.toUtf8());
QDir subDir(dir.path());
subDir.cd(subDirPath);
if (subDir.path() != subDir.canonicalPath()) {
hash.addData(subDir.canonicalPath().toUtf8());
} else {
updateHash(basePath, relativePath, subDir, hash);
}
}
}
void PackagePrivate::createPackageMetadata(const QString &path)
{
delete metadata;
QString metadataPath(path + "/metadata.desktop");
if (!QFile::exists(metadataPath)) {
kWarning() << "No metadata file in the package, expected it at:" << metadataPath;
metadataPath.clear();
}
metadata = new KPluginInfo(metadataPath);
}
} // Namespace

329
plasma/package.h Normal file
View File

@ -0,0 +1,329 @@
/******************************************************************************
* Copyright 2007-2011 by Aaron Seigo <aseigo@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 PLASMA_PACKAGE_H
#define PLASMA_PACKAGE_H
#include <QtCore/QStringList>
#include <kplugininfo.h>
#include <plasma/plasma.h>
#include <plasma/plasma_export.h>
class KJob;
namespace Plasma
{
/**
* @class Package plasma/package.h <Plasma/Package>
*
* @short object representing an installed Plasma package
*
* Package defines what is in a package and provides easy access to the contents.
*
* To define a package, one might write the following code:
*
@code
Package package;
package.addDirectoryDefinition("images", "pics/", i18n("Images"));
QStringList mimeTypes;
mimeTypes << "image/svg" << "image/png" << "image/jpeg";
package.setMimeTypes("images", mimeTypes);
package.addDirectoryDefinition("scripts", "code/", i18n("Executable Scripts"));
mimeTypes.clear();
mimeTypes << "text/\*";
package.setMimeTypes("scripts", mimeTypes);
package.addFileDefinition("mainscript", "code/main.js", i18n("Main Script File"));
package.setRequired("mainscript", true);
@endcode
* One may also choose to create a subclass of PackageStructure and include the setup
* in the constructor.
*
* Either way, Package creates a self-documenting contract between the packager and
* the application without exposing package internals such as actual on-disk structure
* of the package or requiring that all contents be explicitly known ahead of time.
*
* Subclassing PackageStructure does have provide a number of potential const benefits:
* * the package can be notified of path changes via the virtual pathChanged() method
* * the subclass may implement mechanisms to install and remove packages using the
* virtual install and uninstall methods
* * subclasses can be compiled as plugins for easy re-use
**/
//TODO: write documentation on USING a package
class PackagePrivate;
class PackageStructure;
class PLASMA_EXPORT Package
{
public:
/**
* Default constructor
*
* @arg structure if a NULL pointer is passed in, this will creates an empty (invalid) Package;
* otherwise the structure is allowed to set up the Package's initial layout
* @since 4.6
*/
explicit Package(PackageStructure *structure = 0);
/**
* Copy constructore
* @since 4.6
*/
Package(const Package &other);
~Package();
/**
* Assignment operator
* @since 4.6
*/
Package &operator=(const Package &rhs);
/**
* @return true if all the required components exist
**/
bool isValid() const;
/**
* Sets the path to the root of this package
* @param path an absolute path, or a relative path to the default package root
* @since 4.3
*/
void setPath(const QString &path);
/**
* @return the path to the root of this particular package
*/
const QString path() const;
/**
* Get the path to a given file based on the key and an optional filename.
* Example: finding the main script in a scripting package:
* filePath("mainscript")
*
* Example: finding a specific image in the images directory:
* filePath("images", "myimage.png")
*
* @param key the key of the file type to look for,
* @param filename optional name of the file to locate within the package
* @return path to the file on disk. QString() if not found.
**/
QString filePath(const char *key, const QString &filename = QString()) const;
/**
* Get the list of files of a given type.
*
* @param fileType the type of file to look for, as defined in the
* package structure.
* @return list of files by name, suitable for passing to filePath
**/
QStringList entryList(const char *key) const;
/**
* @return user visible name for the given entry
**/
QString name(const char *key) const;
/**
* @return true if the item at path exists and is required
**/
bool isRequired(const char *key) const;
/**
* @return the mimeTypes associated with the path, if any
**/
QStringList mimeTypes(const char *key) const;
/**
* @return the prefix paths inserted between the base path and content entries, in order of priority.
* When searching for a file, all paths will be tried in order.
* @since 4.6
*/
QStringList contentsPrefixPaths() const;
/**
* @return preferred package root. This defaults to plasma/plasmoids/
*/
QString defaultPackageRoot() const;
/**
* @return service prefix used in desktop files. This defaults to plasma-applet-
*/
QString servicePrefix() const;
/**
* @return true if paths/symlinks outside the package itself should be followed.
* By default this is set to false for security reasons.
*/
bool allowExternalPaths() const;
/**
* @return the package metadata object.
*/
KPluginInfo metadata() const;
/**
* @return a SHA1 hash digest of the contents of the package in hexadecimal form
* @since 4.4
*/
QString contentsHash() const;
/**
* Adds a directory to the structure of the package. It is added as
* a not-required element with no associated mimeTypes.
*
* Starting in 4.6, if an entry with the given key
* already exists, the path is added to it as a search alternative.
*
* @param key used as an internal label for this directory
* @param path the path within the package for this directory
* @param name the user visible (translated) name for the directory
**/
void addDirectoryDefinition(const char *key, const QString &path, const QString &name);
/**
* Adds a file to the structure of the package. It is added as
* a not-required element with no associated mimeTypes.
*
* Starting in 4.6, if an entry with the given key
* already exists, the path is added to it as a search alternative.
*
* @param key used as an internal label for this file
* @param path the path within the package for this file
* @param name the user visible (translated) name for the file
**/
void addFileDefinition(const char *key, const QString &path, const QString &name);
/**
* Removes a definition from the structure of the package.
* @since 4.6
* @param key the internal label of the file or directory to remove
*/
void removeDefinition(const char *key);
/**
* Sets whether or not a given part of the structure is required or not.
* The path must already have been added using addDirectoryDefinition
* or addFileDefinition.
*
* @param key the entry within the package
* @param required true if this entry is required, false if not
*/
void setRequired(const char *key, bool required);
/**
* Defines the default mimeTypes for any definitions that do not have
* associated mimeTypes. Handy for packages with only one or predominantly
* one file type.
*
* @param mimeTypes a list of mimeTypes
**/
void setDefaultMimeTypes(QStringList mimeTypes);
/**
* Define mimeTypes for a given part of the structure
* The path must already have been added using addDirectoryDefinition
* or addFileDefinition.
*
* @param key the entry within the package
* @param mimeTypes a list of mimeTypes
**/
void setMimeTypes(const char *key, QStringList mimeTypes);
/**
* Sets the prefixes that all the contents in this package should
* appear under. This defaults to "contents/" and is added automatically
* between the base path and the entries as defined by the package
* structure. Multiple entries can be added.
* In this case each file request will be searched in all prefixes in order,
* and the first found will be returned.
*
* @param prefix paths the directory prefix to use
* @since 4.6
*/
void setContentsPrefixPaths(const QStringList &prefixPaths);
/**
* Sets service prefix.
*/
void setServicePrefix(const QString &servicePrefix);
/**
* Sets whether or not external paths/symlinks can be followed by a package
* @param allow true if paths/symlinks outside of the package should be followed,
* false if they should be rejected.
*/
void setAllowExternalPaths(bool allow);
/**
* Sets preferred package root.
*/
void setDefaultPackageRoot(const QString &packageRoot);
// Content structure description methods
/**
* @return all directories registered as part of this Package's structure
*/
QList<const char*> directories() const;
/**
* @return all directories registered as part of this Package's required structure
*/
QList<const char*> requiredDirectories() const;
/**
* @return all files registered as part of this Package's structure
*/
QList<const char*> files() const;
/**
* @return all files registered as part of this Package's required structure
*/
QList<const char*> requiredFiles() const;
/**
* Installs a package matching this package structure. By default installs a
* native Plasma::Package.
*
* @return KJob to track installation progress and result
**/
KJob* install(const QString &sourcePackage, const QString &packageRoot = QString());
/**
* Uninstalls a package matching this package structure.
*
* @return KJob to track removal progress and result
*/
KJob* uninstall(const QString &packageName, const QString &packageRoot);
private:
QExplicitlySharedDataPointer<PackagePrivate> d;
};
}
Q_DECLARE_METATYPE(Plasma::Package)
#endif

View File

@ -0,0 +1,68 @@
/******************************************************************************
* Copyright 2011 by Aaron Seigo <aseigo@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 "packagestructure.h"
#include <kdebug.h>
#include <private/packagejob_p.h>
#include "private/package_p.h"
namespace Plasma
{
PackageStructure::PackageStructure(QObject *parent, const QVariantList &args)
: QObject(parent),
d(0)
{
Q_UNUSED(args)
}
PackageStructure::~PackageStructure()
{
}
void PackageStructure::initPackage(Package *package)
{
Q_UNUSED(package)
}
void PackageStructure::pathChanged(Package *package)
{
Q_UNUSED(package)
}
KJob* PackageStructure::install(Package *package, const QString &archivePath, const QString &packageRoot)
{
PackageJob* j = new PackageJob(package->servicePrefix(), this);
j->install(archivePath, packageRoot);
return j;
}
KJob* PackageStructure::uninstall(Package *package, const QString &packageRoot)
{
PackageJob* j = new PackageJob(package->servicePrefix(), this);
kDebug() << "PS: " << package->path() << package->isValid();
j->uninstall(package->path());
return j;
}
}
#include "moc_packagestructure.cpp"

104
plasma/packagestructure.h Normal file
View File

@ -0,0 +1,104 @@
/******************************************************************************
* Copyright 2011 by Aaron Seigo <aseigo@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 PLASMA_PACKAGESTRUCTURE_H
#define PLASMA_PACKAGESTRUCTURE_H
#include <QtCore/QStringList>
#include <kplugininfo.h>
#include <plasma/plasma.h>
#include <plasma/plasma_export.h>
#include <plasma/package.h>
namespace Plasma
{
class PackageStructurePrivate;
class PLASMA_EXPORT PackageStructure : public QObject
{
Q_OBJECT
public:
explicit PackageStructure(QObject *parent = 0, const QVariantList &args = QVariantList());
~PackageStructure();
/**
* Called when a the PackageStructure should initialize a Package with the initial
* structure. This allows setting paths before setPath is called.
*
* Note: one special value is "metadata" which can be set to the location of KPluginInfo
* compatible .desktop file within the package. If not defined, it is assumed that this file
* exists under the top level directory of the package.
*
* @arg package the Package to set up. The object is empty of all definition when
* first passed in.
*/
virtual void initPackage(Package *package);
/**
* Called whenever the path changes so that subclasses may take
* package specific actions.
*/
virtual void pathChanged(Package *package);
/**
* Installs a package matching this package structure. By default installs a
* native Plasma::Package.
*
* @param package the instance of Package that is being used for the install; useful for
* accessing file paths
* @param archivePath path to the package archive file
* @param packageRoot path to the directory where the package should be
* installed to
* @return KJob* to track the installation status
**/
virtual KJob* install(Package *package, const QString &archivePath, const QString &packageRoot);
/**
* Uninstalls a package matching this package structure.
*
* @param package the instance of Package that is being used for the install; useful for
* accessing file paths
* @param packageName the name of the package to remove
* @param packageRoot path to the directory where the package should be installed to
* @return KJob* to track the installation status
*/
virtual KJob* uninstall(Package *package, const QString &packageRoot);
private:
PackageStructurePrivate* d;
};
} // Plasma namespace
/**
* Register a Package class when it is contained in a loadable module
*/
#define K_EXPORT_PLASMA_PACKAGE(libname, classname) \
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN(factory("plasma_packagestructure_" #libname)) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
#endif

335
plasma/paintutils.cpp Normal file
View File

@ -0,0 +1,335 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Andrew Lake <jamboarder@yahoo.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <paintutils.h>
#include <QImage>
#include <QPainter>
#include <QPaintEngine>
#include <QPixmap>
#include "private/effects/blur.cpp"
#include "private/effects/halopainter_p.h"
#include "svg.h"
namespace Plasma
{
namespace PaintUtils
{
void shadowBlur(QImage &image, int radius, const QColor &color)
{
if (radius < 1) {
return;
}
if (image.isNull()) {
return;
}
expblur<16, 7>(image, radius);
QPainter p(&image);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(image.rect(), color);
p.end();
}
//TODO: we should have shadowText methods that paint the results directly into a QPainter passed in
QPixmap shadowText(QString text, QColor textColor, QColor shadowColor, QPoint offset, int radius)
{
return shadowText(text, qApp->font(), textColor, shadowColor, offset, radius);
}
QPixmap shadowText(QString text, const QFont &font, QColor textColor, QColor shadowColor, QPoint offset, int radius)
{
//don't try to paint stuff on a future null pixmap because the text is empty
if (text.isEmpty()) {
return QPixmap();
}
// Draw text
QFontMetrics fm(font);
QRect textRect = fm.boundingRect(text);
QPixmap textPixmap(textRect.width(), fm.height());
textPixmap.fill(Qt::transparent);
QPainter p(&textPixmap);
p.setPen(textColor);
p.setFont(font);
// FIXME: the center alignment here is odd: the rect should be the size needed by
// the text, but for some fonts and configurations this is off by a pixel or so
// and "centering" the text painting 'fixes' that. Need to research why
// this is the case and determine if we should be painting it differently here,
// doing soething different with the boundingRect call or if it's a problem
// in Qt itself
p.drawText(textPixmap.rect(), Qt::AlignCenter, text);
p.end();
//Draw blurred shadow
QImage img(textRect.size() + QSize(radius * 2, radius * 2), QImage::Format_ARGB32_Premultiplied);
img.fill(0);
p.begin(&img);
p.drawImage(QPoint(radius, radius), textPixmap.toImage());
p.end();
shadowBlur(img, radius, shadowColor);
//Compose text and shadow
int addSizeX = qMax(0, qAbs(offset.x()) - radius);
int addSizeY = qMax(0, qAbs(offset.y()) - radius);
QPixmap finalPixmap(img.size() + QSize(addSizeX, addSizeY));
finalPixmap.fill(Qt::transparent);
p.begin(&finalPixmap);
p.drawImage(qMax(0, offset.x()), qMax(0, offset.y()), img);
p.drawPixmap(radius + qMax(0, -offset.x()), radius + qMax(0, -offset.y()), textPixmap);
p.end();
return finalPixmap;
}
QPixmap texturedText(const QString &text, const QFont &font, Plasma::Svg *texture)
{
QFontMetrics fm(font);
//the text will be moved a bit from contentsRect
QRect contentsRect = fm.boundingRect(text).adjusted(0, 0, 2, 2);
contentsRect.moveTo(0,0);
QPixmap pixmap(contentsRect.size());
pixmap.fill(Qt::transparent);
QPainter buffPainter(&pixmap);
buffPainter.setPen(Qt::black);
buffPainter.setFont(font);
buffPainter.drawText(contentsRect, Qt::AlignCenter, text);
buffPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
texture->paint(&buffPainter, contentsRect, "foreground");
buffPainter.end();
//do the shadow
QImage image(pixmap.size() + QSize(2, 2), QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
buffPainter.begin(&image);
buffPainter.setFont(font);
buffPainter.drawText(contentsRect.translated(1, 1), Qt::AlignCenter, text);
buffPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
texture->paint(&buffPainter, contentsRect.adjusted(-1, -1, 1, 1), "shadow");
buffPainter.end();
expblur<16, 7>(image, 1);
//hole in the shadow
buffPainter.begin(&image);
buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationOut);
buffPainter.setFont(font);
buffPainter.drawText(contentsRect.translated(1, 1), Qt::AlignCenter, text);
buffPainter.end();
QPixmap ret(image.size());
ret.fill(Qt::transparent);
buffPainter.begin(&ret);
buffPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
buffPainter.drawImage(QPoint(0,0), image);
buffPainter.drawPixmap(QPoint(1,1), pixmap);
buffPainter.end();
return ret;
}
void drawHalo(QPainter *painter, const QRectF &rect)
{
HaloPainter::instance()->drawHalo(painter, rect.toRect());
}
QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
{
QPainterPath path(QPointF(rect.left(), rect.top() + radius));
path.quadTo(rect.left(), rect.top(), rect.left() + radius, rect.top()); // Top left corner
path.lineTo(rect.right() - radius, rect.top()); // Top side
path.quadTo(rect.right(), rect.top(), rect.right(), rect.top() + radius); // Top right corner
path.lineTo(rect.right(), rect.bottom() - radius); // Right side
path.quadTo(rect.right(), rect.bottom(), rect.right() - radius, rect.bottom()); // Bottom right corner
path.lineTo(rect.left() + radius, rect.bottom()); // Bottom side
path.quadTo(rect.left(), rect.bottom(), rect.left(), rect.bottom() - radius); // Bottom left corner
path.closeSubpath();
return path;
}
void centerPixmaps(QPixmap &from, QPixmap &to)
{
if (from.size() == to.size() && from.hasAlphaChannel() && to.hasAlphaChannel()) {
return;
}
QRect fromRect(from.rect());
QRect toRect(to.rect());
QRect actualRect = QRect(QPoint(0,0), fromRect.size().expandedTo(toRect.size()));
fromRect.moveCenter(actualRect.center());
toRect.moveCenter(actualRect.center());
if (from.size() != actualRect.size() || !from.hasAlphaChannel()) {
QPixmap result(actualRect.size());
result.fill(Qt::transparent);
QPainter p(&result);
p.setCompositionMode(QPainter::CompositionMode_Source);
p.drawPixmap(fromRect.topLeft(), from);
p.end();
from = result;
}
if (to.size() != actualRect.size() || !to.hasAlphaChannel()) {
QPixmap result(actualRect.size());
result.fill(Qt::transparent);
QPainter p(&result);
p.setCompositionMode(QPainter::CompositionMode_Source);
p.drawPixmap(toRect.topLeft(), to);
p.end();
to = result;
}
}
QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount)
{
if (from.isNull() && to.isNull()) {
return from;
}
if (qFuzzyCompare(amount + 1, qreal(1.0))) {
return from;
}
QRect startRect(from.rect());
QRect targetRect(to.rect());
QSize pixmapSize = startRect.size().expandedTo(targetRect.size());
QRect toRect = QRect(QPoint(0,0), pixmapSize);
targetRect.moveCenter(toRect.center());
startRect.moveCenter(toRect.center());
//paint to in the center of from
QColor color;
color.setAlphaF(amount);
// If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus
QPaintEngine *paintEngine = from.paintEngine();
if (paintEngine &&
paintEngine->hasFeature(QPaintEngine::PorterDuff) &&
paintEngine->hasFeature(QPaintEngine::BlendModes)) {
QPixmap startPixmap(pixmapSize);
startPixmap.fill(Qt::transparent);
QPixmap targetPixmap(pixmapSize);
targetPixmap.fill(Qt::transparent);
QPainter p;
p.begin(&targetPixmap);
p.drawPixmap(targetRect, to);
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.fillRect(targetRect, color);
p.end();
p.begin(&startPixmap);
p.drawPixmap(startRect, from);
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
p.fillRect(startRect, color);
p.setCompositionMode(QPainter::CompositionMode_Plus);
p.drawPixmap(targetRect, targetPixmap);
p.end();
return startPixmap;
}
#warning Cannot use XRender with QPixmap anymore. Find equivalent with Qt API.
#if 0 // HAVE_X11 && defined(HAVE_XRENDER)
// We have Xrender support
else if (paintEngine && paintEngine->hasFeature(QPaintEngine::PorterDuff)) {
// QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3,
// which we need to be able to do a transition from one pixmap to
// another.
//
// In order to avoid the overhead of converting the pixmaps to images
// and doing the operation entirely in software, this function has a
// specialized path for X11 that uses Xrender directly to do the
// transition. This operation can be fully accelerated in HW.
//
// This specialization can be removed when QX11PaintEngine supports
// CompositionMode_Plus.
QPixmap source(targetPixmap), destination(startPixmap);
source.detach();
destination.detach();
Display *dpy = QX11Info::display();
XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8);
XRenderPictureAttributes pa;
pa.repeat = 1; // RepeatNormal
// Create a 1x1 8 bit repeating alpha picture
Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8);
Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa);
XFreePixmap(dpy, pixmap);
// Fill the alpha picture with the opacity value
XRenderColor xcolor;
xcolor.alpha = quint16(0xffff * amount);
XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1);
// Reduce the alpha of the destination with 1 - opacity
XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(),
0, 0, 0, 0, 0, 0, destination.width(), destination.height());
// Add source * opacity to the destination
XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha,
destination.x11PictureHandle(),
toRect.x(), toRect.y(), 0, 0, 0, 0, destination.width(), destination.height());
XRenderFreePicture(dpy, alpha);
return destination;
}
#endif
else {
// Fall back to using QRasterPaintEngine to do the transition.
QImage under(pixmapSize, QImage::Format_ARGB32_Premultiplied);
under.fill(Qt::transparent);
QImage over(pixmapSize, QImage::Format_ARGB32_Premultiplied);
over.fill(Qt::transparent);
QPainter p;
p.begin(&over);
p.drawPixmap(targetRect, to);
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.fillRect(over.rect(), color);
p.end();
p.begin(&under);
p.drawPixmap(startRect, from);
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
p.fillRect(startRect, color);
p.setCompositionMode(QPainter::CompositionMode_Plus);
p.drawImage(toRect.topLeft(), over);
p.end();
return QPixmap::fromImage(under);
}
}
} // PaintUtils namespace
} // Plasma namespace

90
plasma/paintutils.h Normal file
View File

@ -0,0 +1,90 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Andrew Lake <jamboarder@yahoo.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_PAINTUTILS_H
#define PLASMA_PAINTUTILS_H
#include <QApplication>
#include <QPainterPath>
#include <QColor>
#include <plasma/plasma_export.h>
#include "theme.h"
/** @headerfile plasma/paintutils.h <Plasma/PaintUtils> */
namespace Plasma
{
class Svg;
/**
* Namespace for all Image Effects specific to Plasma
**/
namespace PaintUtils
{
/**
* Creates a blurred shadow of the supplied image.
*/
PLASMA_EXPORT void shadowBlur(QImage &image, int radius, const QColor &color);
/**
* Returns a pixmap containing text with blurred shadow.
* Text and shadow colors default to Plasma::Theme colors.
*/
PLASMA_EXPORT QPixmap shadowText(QString text,
const QFont &font,
QColor textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor),
QColor shadowColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor),
QPoint offset = QPoint(1,1),
int radius = 2);
PLASMA_EXPORT QPixmap shadowText(QString text,
QColor textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor),
QColor shadowColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor),
QPoint offset = QPoint(1,1),
int radius = 2);
PLASMA_EXPORT QPixmap texturedText(const QString &text, const QFont &font, Plasma::Svg *texture);
PLASMA_EXPORT void drawHalo(QPainter *painter, const QRectF &rect);
/**
* Returns a nicely rounded rectanglular path for painting.
*/
PLASMA_EXPORT QPainterPath roundedRectangle(const QRectF &rect, qreal radius);
/**
* center two pixmap together in the biggest rectangle
* @since 4.5
*/
PLASMA_EXPORT void centerPixmaps(QPixmap &from, QPixmap &to);
/**
* Blends a pixmap into another
*/
PLASMA_EXPORT QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount);
} // PaintUtils namespace
} // Plasma namespace
#endif

73
plasma/plasma.cpp Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <plasma/plasma.h>
#include <QAction>
#include <QMenu>
#include "containment.h"
#include "private/packages_p.h"
namespace Plasma
{
Direction locationToDirection(Location location)
{
switch (location) {
case Floating:
case Desktop:
case TopEdge:
case FullScreen:
//TODO: should we be smarter for floating and planer?
// perhaps we should take a QRect and/or QPos as well?
return Down;
case BottomEdge:
return Up;
case LeftEdge:
return Right;
case RightEdge:
return Left;
}
return Down;
}
Direction locationToInverseDirection(Location location)
{
switch (location) {
case Floating:
case Desktop:
case TopEdge:
case FullScreen:
//TODO: should we be smarter for floating and planer?
// perhaps we should take a QRect and/or QPos as well?
return Up;
case BottomEdge:
return Down;
case LeftEdge:
return Left;
case RightEdge:
return Right;
}
return Up;
}
} // Plasma namespace

294
plasma/plasma.h Normal file
View File

@ -0,0 +1,294 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DEFS_H
#define PLASMA_DEFS_H
/** @header plasma/plasma.h <Plasma/Plasma> */
#include <QPainterPath>
#include <plasma/plasma_export.h>
class QAction;
/**
* Namespace for everything in libplasma
*/
namespace Plasma
{
/**
* The Constraint enumeration lists the various constraints that Plasma
* objects have managed for them and which they may wish to react to,
* for instance in Applet::constraintsUpdated
*/
enum Constraint {
NoConstraint = 0, /**< No constraint; never passed in to Applet::constraintsEvent on its own */
FormFactorConstraint = 1, /**< The FormFactor for an object */
LocationConstraint = 2, /**< The Location of an object */
ScreenConstraint = 4, /**< Which screen an object is on */
SizeConstraint = 8, /**< the size of the applet was changed */
ImmutableConstraint = 16, /**< the immutability (locked) nature of the applet changed */
StartupCompletedConstraint = 32, /**< application startup has completed */
ContextConstraint = 64, /**< the context (e.g. activity) has changed */
PopupConstraint = 128, /**< the position of the popup needs to be recalculated*/
AllConstraints = FormFactorConstraint | LocationConstraint | ScreenConstraint |
SizeConstraint | ImmutableConstraint | PopupConstraint
};
Q_DECLARE_FLAGS(Constraints, Constraint)
/**
* The FormFactor enumeration describes how a Plasma::Applet should arrange
* itself. The value is derived from the container managing the Applet
* (e.g. in Plasma, a Corona on the desktop or on a panel).
**/
enum FormFactor {
Planar = 0, /**< The applet lives in a plane and has two
degrees of freedom to grow. Optimize for
desktop, laptop or tablet usage: a high
resolution screen 1-3 feet distant from the
viewer. */
MediaCenter, /**< As with Planar, the applet lives in a plane
but the interface should be optimized for
medium-to-high resolution screens that are
5-15 feet distant from the viewer. Sometimes
referred to as a "ten foot interface".*/
Horizontal, /**< The applet is constrained vertically, but
can expand horizontally. */
Vertical, /**< The applet is constrained horizontally, but
can expand vertically. */
Application /**< The Applet lives in a plane and should be optimized to look as a full application,
for the desktop or the particular device. */
};
/**
* The Direction enumeration describes in which direction, relative to the
* Applet (and its managing container), popup menus, expanders, balloons,
* message boxes, arrows and other such visually associated widgets should
* appear in. This is usually the oposite of the Location.
**/
enum Direction {
Down = 0, /**< Display downards */
Up, /**< Display upwards */
Left, /**< Display to the left */
Right /**< Display to the right */
};
/**
* The Location enumeration describes where on screen an element, such as an
* Applet or its managing container, is positioned on the screen.
**/
enum Location {
Floating = 0, /**< Free floating. Neither geometry or z-ordering
is described precisely by this value. */
Desktop, /**< On the planar desktop layer, extending across
the full screen from edge to edge */
FullScreen, /**< Full screen */
TopEdge, /**< Along the top of the screen*/
BottomEdge, /**< Along the bottom of the screen*/
LeftEdge, /**< Along the left side of the screen */
RightEdge /**< Along the right side of the screen */
};
/**
* The position enumeration
*
**/
enum Position {
LeftPositioned, /**< Positioned left */
RightPositioned, /**< Positioned right */
TopPositioned, /**< Positioned top */
BottomPositioned, /**< Positioned bottom */
CenterPositioned /**< Positioned in the center */
};
/**
* The popup position enumeration relatively to his attached widget
*
**/
enum PopupPlacement {
FloatingPopup = 0, /**< Free floating, non attached popup */
TopPosedLeftAlignedPopup, /**< Popup positioned on the top, aligned
to the left of the wigdet */
TopPosedRightAlignedPopup, /**< Popup positioned on the top, aligned
to the right of the widget */
LeftPosedTopAlignedPopup, /**< Popup positioned on the left, aligned
to the right of the wigdet */
LeftPosedBottomAlignedPopup, /**< Popup positioned on the left, aligned
to the bottom of the widget */
BottomPosedLeftAlignedPopup, /**< Popup positioned on the bottom, aligned
to the left of the wigdet */
BottomPosedRightAlignedPopup, /**< Popup positioned on the bottom, aligned
to the right of the widget */
RightPosedTopAlignedPopup, /**< Popup positioned on the right, aligned
to the top of the wigdet */
RightPosedBottomAlignedPopup /**< Popup positioned on the right, aligned
to the bottom of the widget */
};
/**
* Flip enumeration
*/
enum FlipDirection {
NoFlip = 0, /**< Do not flip */
HorizontalFlip = 1, /**< Flip horizontally */
VerticalFlip = 2 /**< Flip vertically */
};
Q_DECLARE_FLAGS(Flip, FlipDirection)
/**
* Possible timing alignments
**/
enum IntervalAlignment {
NoAlignment = 0, /**< No alignment **/
AlignToMinute, /**< Align to the minute **/
AlignToHour /**< Align to the hour **/
};
/**
* Defines the immutability of items like applets, corona and containments
* they can be free to modify, locked down by the user or locked down by the
* system (e.g. kiosk setups).
*/
enum ImmutabilityType {
Mutable = 1, /**< The item can be modified in any way **/
UserImmutable = 2, /**< The user has requested a lock down, and can undo
the lock down at any time **/
SystemImmutable = 4 /**< the item is locked down by the system, the user
can't unlock it **/
};
/**
* Defines the aspect ratio used when resizing an applet
*/
enum AspectRatioMode {
InvalidAspectRatioMode = -1, /**< Unset mode used for dev convenience
when there is a need to store the
aspectRatioMode somewhere */
IgnoreAspectRatio = 0, /**< The applet can be freely resized */
KeepAspectRatio = 1, /**< The applet keeps a fixed aspect ratio */
Square = 2, /**< The applet is always a square */
ConstrainedSquare = 3, /**< The applet is no wider (in horizontal
formfactors) or no higher (in vertical
ones) than a square */
FixedSize = 4 /** The applet cannot be resized */
};
/**
* The ComonentType enumeration refers to the various types of components,
* or plugins, supported by plasma.
*/
enum ComponentType {
AppletComponent = 1, /**< Plasma::Applet based plugins **/
DataEngineComponent = 2, /**< Plasma::DataEngine based plugins **/
RunnerComponent = 4, /**< Plasma::AbstractRunner based plugsin **/
AnimatorComponent = 8, /**< Plasma::Animator based plugins **/
ContainmentComponent = 16,/**< Plasma::Containment based plugins **/
WallpaperComponent = 32, /**< Plasma::Wallpaper based plugins **/
GenericComponent = 64 /** Generic repositories of files, usually they keep QML files and their assets **/
};
Q_DECLARE_FLAGS(ComponentTypes, ComponentType)
enum MarginEdge {
TopMargin = 0, /**< The top margin **/
BottomMargin, /**< The bottom margin **/
LeftMargin, /**< The left margin **/
RightMargin /**< The right margin **/
};
enum MessageButton {
ButtonNone = 0, /**< None **/
ButtonOk = 1, /**< OK Button **/
ButtonYes = 2, /**< Yes Button **/
ButtonNo = 4, /**< No Button **/
ButtonCancel = 8 /**< Cancel Button **/
};
Q_DECLARE_FLAGS(MessageButtons, MessageButton)
/**
* Status of an applet
* @since 4.3
*/
enum ItemStatus {
UnknownStatus = 0, /**< The status is unknown **/
PassiveStatus = 1, /**< The Item is passive **/
ActiveStatus = 2, /**< The Item is active **/
NeedsAttentionStatus = 3, /**< The Item needs attention **/
AcceptingInputStatus = 4 /**< The Item is accepting input **/
};
Q_ENUMS(ItemStatus)
enum AnnouncementMethod {
NoAnnouncement = 0, /**< No announcements **/
ZeroconfAnnouncement = 1 /**< Announcements via ZeroConf **/
};
Q_DECLARE_FLAGS(AnnouncementMethods, AnnouncementMethod)
enum TrustLevel {
UnverifiableTrust = 0, /**< The trust of the object can not be verified, usually because no
trust information (e.g. a cryptographic signature) was provided */
CompletelyUntrusted, /**< The signature is broken/expired/false */
UnknownTrusted, /**< The signature is valid, but the key is unknown */
UserTrusted, /**< The signature is valid and made with a key signed by one of the
user's own keys*/
SelfTrusted, /**< The signature is valid and made with one of the user's own keys*/
FullyTrusted, /**< The signature is valid and made with a key signed by the vendor's key*/
UltimatelyTrusted /**< The signature is valid and made with the vendor's key*/
};
Q_ENUMS(TrustLevel)
/**
* Description on how draw a background for the applet
*/
enum BackgroundHints {
NoBackground = 0, /**< Not drawing a background under the applet, the applet has its own implementation */
StandardBackground = 1, /**< The standard background from the theme is drawn */
TranslucentBackground = 2, /**< An alternate version of the background is drawn, usually more translucent */
DefaultBackground = StandardBackground /**< Default settings: both standard background */
};
Q_ENUMS(BackgroundHints)
/**
* Converts a location to a direction. Handy for figuring out which way to send a popup based on
* location or to point arrows and other directional items.
*
* @param location the location of the container the element will appear in
* @return the visual direction the element should be oriented in
**/
PLASMA_EXPORT Direction locationToDirection(Location location);
/**
* Converts a location to the direction facing it. Handy for figuring out which way to collapse
* a popup or to point arrows at the item itself.
*
* @param location the location of the container the element will appear in
* @return the visual direction the element should be oriented in
**/
PLASMA_EXPORT Direction locationToInverseDirection(Location location);
} // Plasma namespace
Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::Constraints)
Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::Flip)
Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::ComponentTypes)
Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::MessageButtons)
#endif // multiple inclusion guard

595
plasma/pluginloader.cpp Normal file
View File

@ -0,0 +1,595 @@
/*
* Copyright 2010 Ryan Rix <ry@n.rix.si>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "pluginloader.h"
#include <kdebug.h>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#include <kglobal.h>
#include <kplugininfo.h>
#include "config-plasma.h"
#if !PLASMA_NO_KIO
#include <kio/job.h>
#endif
#include "applet.h"
#include "abstractrunner.h"
#include "containment.h"
#include "containmentactions.h"
#include "dataengine.h"
#include "package.h"
#include "private/applet_p.h"
#include "private/packages_p.h"
#include "private/service_p.h" // for NullService
#include "private/storage_p.h"
namespace Plasma {
static PluginLoader *s_pluginLoader = 0;
class PluginLoaderPrivate
{
public:
QHash<QString, QWeakPointer<PackageStructure> > structures;
bool isDefaultLoader;
};
PluginLoader::PluginLoader()
: d(new PluginLoaderPrivate)
{
d->isDefaultLoader = false;
}
PluginLoader::~PluginLoader()
{
typedef QWeakPointer<PackageStructure> pswp;
foreach (pswp wp, d->structures) {
delete wp.data();
}
delete d;
}
void PluginLoader::setPluginLoader(PluginLoader* loader)
{
if (!s_pluginLoader) {
s_pluginLoader = loader;
} else {
#ifndef NDEBUG
kDebug() << "Cannot set pluginLoader, already set!" << s_pluginLoader;
#endif
}
}
PluginLoader *PluginLoader::self()
{
if (!s_pluginLoader) {
// we have been called before any PluginLoader was set, so just use the default
// implementation. this prevents plugins from nefariously injecting their own
// plugin loader if the app doesn't
s_pluginLoader = new PluginLoader;
s_pluginLoader->d->isDefaultLoader = true;
}
return s_pluginLoader;
}
Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVariantList &args)
{
// the application-specific appletLoader failed to create an applet, here we try with our own logic.
if (name.isEmpty()) {
return 0;
}
Applet *applet = d->isDefaultLoader ? 0 : internalLoadApplet(name, appletId, args);
if (applet) {
return applet;
}
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
bool isContainment = false;
if (offers.isEmpty()) {
//TODO: what would be -really- cool is offer to try and download the applet
// from the network at this point
offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
if (offers.count() > 0) {
isContainment = true;
}
}
#ifndef NDEBUG
if (offers.count() > 1) {
kDebug() << "hey! we got more than one! let's blindly take the first one";
}
#endif
AppletPrivate::filterOffers(offers);
if (offers.isEmpty()) {
#ifndef NDEBUG
kDebug() << "offers is empty for " << name;
#endif
return 0;
}
KService::Ptr offer = offers.first();
if (appletId == 0) {
appletId = ++AppletPrivate::s_maxAppletId;
}
QVariantList allArgs;
allArgs << offer->storageId() << appletId << args;
if (!offer->property("X-Plasma-API").toString().isEmpty()) {
#ifndef NDEBUG
kDebug() << "we have a script using the"
<< offer->property("X-Plasma-API").toString() << "API";
#endif
if (isContainment) {
return new Containment(0, allArgs);
} else {
if (offer->serviceTypes().contains("Plasma/Containment")) {
return new Containment(0, allArgs);
} else {
return new Applet(0, allArgs);
}
}
}
KPluginLoader plugin(*offer);
if (!Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
return 0;
}
QString error;
applet = offer->createInstance<Plasma::Applet>(0, allArgs, &error);
if (!applet) {
kWarning() << "Could not load applet" << name << "! reason given:" << error;
}
return applet;
}
DataEngine *PluginLoader::loadDataEngine(const QString &name)
{
DataEngine *engine = d->isDefaultLoader ? 0 : internalLoadDataEngine(name);
if (engine) {
return engine;
}
// load the engine, add it to the engines
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine",
constraint);
QString error;
if (offers.isEmpty()) {
#ifndef NDEBUG
kDebug() << "offers are empty for " << name << " with constraint " << constraint;
#endif
} else {
QVariantList allArgs;
allArgs << offers.first()->storageId();
QString api = offers.first()->property("X-Plasma-API").toString();
if (api.isEmpty()) {
if (offers.first()) {
KPluginLoader plugin(*offers.first());
if (Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
engine = offers.first()->createInstance<Plasma::DataEngine>(0, allArgs, &error);
}
}
} else {
engine = new DataEngine(0, offers.first());
}
}
if (!engine) {
#ifndef NDEBUG
kDebug() << "Couldn't load engine \"" << name << "\". Error given: " << error;
#endif
}
return engine;
}
AbstractRunner *PluginLoader::loadRunner(const QString &name)
{
// FIXME: RunnerManager is all wrapped around runner loading; that should be sorted out
// and the actual plugin loading added here
return d->isDefaultLoader ? 0 : internalLoadRunner(name);
}
Service *PluginLoader::loadService(const QString &name, const QVariantList &args, QObject *parent)
{
Service *service = d->isDefaultLoader ? 0 : internalLoadService(name, args, parent);
if (service) {
return service;
}
//TODO: scripting API support
if (name.isEmpty()) {
return new NullService(QString(), parent);
} else if (name == "org.kde.servicestorage") {
return new Storage(parent);
}
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Service", constraint);
if (offers.isEmpty()) {
#ifndef NDEBUG
kDebug() << "offers is empty for " << name;
#endif
return new NullService(name, parent);
}
KService::Ptr offer = offers.first();
QString error;
if (Plasma::isPluginVersionCompatible(KPluginLoader(*offer).pluginVersion())) {
service = offer->createInstance<Plasma::Service>(parent, args, &error);
}
if (!service) {
#ifndef NDEBUG
kDebug() << "Couldn't load Service \"" << name << "\"! reason given: " << error;
#endif
return new NullService(name, parent);
}
if (service->name().isEmpty()) {
service->setName(name);
}
return service;
}
ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, const QString &name, const QVariantList &args)
{
if (name.isEmpty()) {
return 0;
}
ContainmentActions *actions = d->isDefaultLoader ? 0 : internalLoadContainmentActions(parent, name, args);
if (actions) {
return actions;
}
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ContainmentActions", constraint);
if (offers.isEmpty()) {
#ifndef NDEBUG
kDebug() << "offers is empty for " << name;
#endif
return 0;
}
KService::Ptr offer = offers.first();
KPluginLoader plugin(*offer);
if (!Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
return 0;
}
QVariantList allArgs;
allArgs << offer->storageId() << args;
QString error;
actions = offer->createInstance<Plasma::ContainmentActions>(parent, allArgs, &error);
if (!actions) {
#ifndef NDEBUG
kDebug() << "Couldn't load containmentActions \"" << name << "\"! reason given: " << error;
#endif
}
return actions;
}
Package PluginLoader::loadPackage(const QString &packageFormat, const QString &specialization)
{
if (!d->isDefaultLoader) {
Package p = internalLoadPackage(packageFormat, specialization);
if (p.isValid()) {
return p;
}
}
if (packageFormat.isEmpty()) {
return Package();
}
const QString hashkey = packageFormat + '%' + specialization;
PackageStructure *structure = d->structures.value(hashkey).data();
if (structure) {
return Package(structure);
}
if (!specialization.isEmpty()) {
QRegExp re("[^a-zA-Z0-9\\-_]");
// check that the provided strings are safe to use in a ServiceType query
if (re.indexIn(specialization) == -1 && re.indexIn(packageFormat) == -1) {
// FIXME: The query below is rather spepcific to script engines. generify if possible
const QString component = packageFormat.right(packageFormat.size() - packageFormat.lastIndexOf('/') - 1);
const QString constraint = QString("[X-Plasma-API] == '%1' and " "'%2' in [X-Plasma-ComponentTypes]").arg(specialization, component);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint);
if (!offers.isEmpty()) {
KService::Ptr offer = offers.first();
QString packageFormat = offer->property("X-Plasma-PackageFormat").toString();
if (!packageFormat.isEmpty()) {
return loadPackage(packageFormat);
}
}
}
}
if (packageFormat.startsWith("Plasma")) {
if (packageFormat.endsWith("/Applet")) {
structure = new PlasmoidPackage();
} else if (packageFormat.endsWith("/DataEngine")) {
structure = new DataEnginePackage();
} else if (packageFormat.endsWith("/Runner")) {
structure = new RunnerPackage();
} else if (packageFormat.endsWith("/Theme")) {
structure = new ThemePackage();
} else if (packageFormat.endsWith("/ContainmentActions")) {
structure = new ContainmentActionsPackage();
} else if (packageFormat.endsWith("/Generic")) {
structure = new GenericPackage();
}
if (structure) {
d->structures.insert(hashkey, structure);
return Package(structure);
}
}
// first we check for plugins in sycoca
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/PackageStructure", constraint);
QVariantList args;
QString error;
foreach (const KService::Ptr &offer, offers) {
structure = qobject_cast<PackageStructure *>(offer->createInstance<PackageStructure>(0, args, &error));
if (structure) {
d->structures.insert(hashkey, structure);
return Package(structure);
}
#ifndef NDEBUG
kDebug() << "Couldn't load Package for" << packageFormat << "! reason given: " << error;
#endif
}
return Package();
}
KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QString &parentApp)
{
KPluginInfo::List list;
if (!d->isDefaultLoader && (parentApp.isEmpty() || parentApp == QCoreApplication::instance()->applicationName())) {
list = internalAppletInfo(category);
}
QString constraint = AppletPrivate::parentAppConstraint(parentApp);
//note: constraint guaranteed non-empty from here down
if (category.isEmpty()) { //use all but the excluded categories
KConfigGroup group(KSharedConfig::openConfig(), "General");
QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
foreach (const QString &category, excluded) {
constraint.append(" and [X-KDE-PluginInfo-Category] != '").append(category).append("'");
}
} else { //specific category (this could be an excluded one - is that bad?)
constraint.append(" and ").append("[X-KDE-PluginInfo-Category] == '").append(category).append("'");
if (category == "Miscellaneous") {
constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
}
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
//now we have to do some manual filtering because the constraint can't handle everything
AppletPrivate::filterOffers(offers);
//kDebug() << "Applet::listAppletInfo constraint was '" << constraint
// << "' which got us " << offers.count() << " matches";
return KPluginInfo::fromServices(offers);
}
KPluginInfo::List PluginLoader::listDataEngineInfo(const QString &parentApp)
{
KPluginInfo::List list;
if (!d->isDefaultLoader && (parentApp.isEmpty() || parentApp == QCoreApplication::instance()->applicationName())) {
list = internalDataEngineInfo();
}
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("not exist [X-KDE-ParentApp]");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
return list + KPluginInfo::fromServices(offers);
}
KPluginInfo::List PluginLoader::listRunnerInfo(const QString &parentApp)
{
KPluginInfo::List list;
if (!d->isDefaultLoader && (parentApp.isEmpty() || parentApp == QCoreApplication::instance()->applicationName())) {
list = internalRunnerInfo();
}
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("not exist [X-KDE-ParentApp]");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner", constraint);
return list + KPluginInfo::fromServices(offers);
}
KPluginInfo::List PluginLoader::listContainmentActionsInfo(const QString &parentApp)
{
KPluginInfo::List list;
if (!d->isDefaultLoader && (parentApp.isEmpty() || parentApp == QCoreApplication::instance()->applicationName())) {
list = internalContainmentActionsInfo();
}
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("not exist [X-KDE-ParentApp]");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ContainmentActions", constraint);
return KPluginInfo::fromServices(offers);
}
Applet* PluginLoader::internalLoadApplet(const QString &name, uint appletId, const QVariantList &args)
{
Q_UNUSED(name)
Q_UNUSED(appletId)
Q_UNUSED(args)
return 0;
}
DataEngine *PluginLoader::internalLoadDataEngine(const QString &name)
{
Q_UNUSED(name)
return 0;
}
AbstractRunner *PluginLoader::internalLoadRunner(const QString &name)
{
Q_UNUSED(name)
return 0;
}
ContainmentActions *PluginLoader::internalLoadContainmentActions(Containment *containment, const QString &name, const QVariantList &args)
{
Q_UNUSED(containment)
Q_UNUSED(name)
Q_UNUSED(args)
return 0;
}
Service *PluginLoader::internalLoadService(const QString &name, const QVariantList &args, QObject *parent)
{
Q_UNUSED(name)
Q_UNUSED(args)
Q_UNUSED(parent)
return 0;
}
Package PluginLoader::internalLoadPackage(const QString &name, const QString &specialization)
{
Q_UNUSED(name);
Q_UNUSED(specialization);
return Package();
}
KPluginInfo::List PluginLoader::internalAppletInfo(const QString &category) const
{
Q_UNUSED(category)
return KPluginInfo::List();
}
KPluginInfo::List PluginLoader::internalDataEngineInfo() const
{
return KPluginInfo::List();
}
KPluginInfo::List PluginLoader::internalRunnerInfo() const
{
return KPluginInfo::List();
}
KPluginInfo::List PluginLoader::internalServiceInfo() const
{
return KPluginInfo::List();
}
KPluginInfo::List PluginLoader::internalContainmentActionsInfo() const
{
return KPluginInfo::List();
}
static KPluginInfo::List standardInternalInfo(const QString &type, const QString &category = QString())
{
QStringList files = KGlobal::dirs()->findAllResources("appdata", "plasma/internal/" + type + "/*.desktop", KStandardDirs::NoDuplicates);
KPluginInfo::List allInfo = KPluginInfo::fromFiles(files);
if (category.isEmpty() || allInfo.isEmpty()) {
return allInfo;
}
KPluginInfo::List matchingInfo;
foreach (const KPluginInfo &info, allInfo) {
if (info.category().compare(category, Qt::CaseInsensitive) == 0) {
matchingInfo << info;
}
}
return matchingInfo;
}
KPluginInfo::List PluginLoader::standardInternalAppletInfo(const QString &category) const
{
return standardInternalInfo("applets", category);
}
KPluginInfo::List PluginLoader::standardInternalDataEngineInfo() const
{
return standardInternalInfo("dataengines");
}
KPluginInfo::List PluginLoader::standardInternalRunnerInfo() const
{
return standardInternalInfo("runners");
}
KPluginInfo::List PluginLoader::standardInternalServiceInfo() const
{
return standardInternalInfo("services");
}
} // Plasma Namespace

386
plasma/pluginloader.h Normal file
View File

@ -0,0 +1,386 @@
/*
* Copyright 2010 by Ryan Rix <ry@n.rix.si>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLUGIN_LOADER_H
#define PLUGIN_LOADER_H
#include <plasma/package.h>
#include <plasma/plasma.h>
#include <kplugininfo.h>
namespace Plasma {
class AbstractRunner;
class Applet;
class Containment;
class ContainmentActions;
class DataEngine;
class Service;
class PluginLoaderPrivate;
//TODO:
// * add loadWallpaper
// * add KPluginInfo listing support for Containments (already loaded via the applet loading code)
/**
* This is an abstract base class which defines an interface to which Plasma's
* Applet Loading logic can communicate with a parent application. The plugin loader
* must be set before any plugins are loaded, otherwise (for safety reasons), the
* default PluginLoader implementation will be used. The reimplemented version should
* not do more than simply returning a loaded plugin. It should not init() it, and it should not
* hang on to it. The associated methods will be called only when a component of Plasma
* needs to load a _new_ plugin. (e.g. DataEngine does its own caching).
*
* @author Ryan Rix <ry@n.rix.si>
* @since 4.6
**/
class PLASMA_EXPORT PluginLoader
{
public:
/**
* Load an Applet plugin.
*
* @param name the plugin name, as returned by KPluginInfo::pluginName()
* @param appletId unique ID to assign the applet, or zero to have one
* assigned automatically.
* @param args to send the applet extra arguments
* @return a pointer to the loaded applet, or 0 on load failure
**/
Applet *loadApplet(const QString &name, uint appletId = 0,
const QVariantList &args = QVariantList());
/**
* Load a DataEngine plugin.
*
* @param name the name of the engine
* @return the DataEngine that was loaded, or the NullEngine on failure.
**/
DataEngine *loadDataEngine(const QString &name);
/**
* Load a Runner plugin
*
* @return the Runner that was loaded, or 0 on failure.
*/
AbstractRunner *loadRunner(const QString &name);
/**
* Load a Service plugin.
*
* @param name the plugin name of the service to load
* @param args a list of arguments to supply to the service plugin when loading it
* @param parent the parent object, if any, for the service
*
* @return a Service object, unlike Plasma::Service::loadService, this can return null.
**/
Service *loadService(const QString &name, const QVariantList &args, QObject *parent = 0);
/**
* Load a ContainmentActions plugin.
*
* Returns a pointer to the containmentactions if successful.
* The caller takes responsibility for the containmentactions, including
* deleting it when no longer needed.
*
* @param parent the parent containment. @since 4.6 null is allowed.
* @param name the plugin name, as returned by KPluginInfo::pluginName()
* @param args to send the containmentactions extra arguments
* @return a ContaimentActions object
**/
ContainmentActions *loadContainmentActions(Containment *parent, const QString &containmentActionsName,
const QVariantList &args = QVariantList());
/**
* Load a Package plugin.
*
* @param name the plugin name of the package to load
* @param specialization used to find script extensions for the given format, e.g. "QML" for "Plasma/Applet"
*
* @return a Package object matching name, or an invalid package on failure
**/
Package loadPackage(const QString &packageFormat, const QString &specialization = QString());
/**
* Returns a list of all known applets.
* This may skip applets based on security settings and ExcludeCategories in the application's config.
*
* @param category Only applets matchin this category will be returned.
* Useful in conjunction with knownCategories.
* If "Misc" is passed in, then applets without a
* Categories= entry are also returned.
* If an empty string is passed in, all applets are
* returned.
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of applets
**/
KPluginInfo::List listAppletInfo(const QString &category, const QString &parentApp = QString());
/**
* Returns a list of all known DataEngines.
*
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of DataEngines
**/
KPluginInfo::List listDataEngineInfo(const QString &parentApp = QString());
/**
* Returns a list of all known Runner implementations
*
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of AbstractRunners
**/
KPluginInfo::List listRunnerInfo(const QString &parentApp = QString());
/**
* Returns a list of all known ContainmentActions.
*
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of applets
**/
KPluginInfo::List listContainmentActionsInfo(const QString &parentApp);
/**
* Set the plugin loader which will be queried for all loads.
*
* @param loader A subclass of PluginLoader which will be supplied
* by the application
**/
static void setPluginLoader(PluginLoader* loader);
/**
* Return the active plugin loader
**/
static PluginLoader *self();
protected:
/**
* A re-implementable method that allows subclasses to override
* the default behaviour of loadApplet. If the applet requested is not recognized,
* then the implementation should return a NULL pointer. This method is called
* by loadApplet prior to attempting to load an applet using the standard Plasma
* plugin mechanisms.
*
* @param name the plugin name, as returned by KPluginInfo::pluginName()
* @param appletId unique ID to assign the applet, or zero to have one
* assigned automatically.
* @param args to send the applet extra arguments
* @return a pointer to the loaded applet, or 0 on load failure
**/
virtual Applet *internalLoadApplet(const QString &name, uint appletId = 0,
const QVariantList &args = QVariantList());
/**
* A re-implementable method that allows subclasses to override
* the default behaviour of loadRunner. If the runner requested is not recognized,
* then the implementation should return a NULL pointer. This method is called
* by loadRunner prior to attempting to load a DataEgine using the standard Plasma
* plugin mechanisms.
*
* @param name the name of the engine
* @return the data engine that was loaded, or the NullEngine on failure.
**/
virtual AbstractRunner *internalLoadRunner(const QString &name);
/**
* A re-implementable method that allows subclasses to override
* the default behaviour of loadDataEngine. If the engine requested is not recognized,
* then the implementation should return a NULL pointer. This method is called
* by loadDataEngine prior to attempting to load a DataEgine using the standard Plasma
* plugin mechanisms.
*
* @param name the name of the engine
* @return the data engine that was loaded, or the NullEngine on failure.
**/
virtual DataEngine *internalLoadDataEngine(const QString &name);
/**
* A re-implementable method that allows subclasses to override
* the default behaviour of loadService. If the service requested is not recognized,
* then the implementation should return a NULL pointer. This method is called
* by loadService prior to attempting to load a Service using the standard Plasma
* plugin mechanisms.
*
* @param name the plugin name of the service to load
* @param args a list of arguments to supply to the service plugin when loading it
* @param parent the parent object, if any, for the service
*
* @return a Service object, unlike Plasma::Service::loadService, this can return null.
**/
virtual Service *internalLoadService(const QString &name, const QVariantList &args, QObject *parent = 0);
/**
* A re-implementable method that allows subclasses to override
* the default behaviour of loadContainmentActions. If the Containments Action requested is not recognized,
* then the implementation should return a NULL pointer. This method is called
* by loadService prior to attempting to load a Service using the standard Plasma
* plugin mechanisms.
*
* Returns a pointer to the containmentactions if successful.
* The caller takes responsibility for the containmentactions, including
* deleting it when no longer needed.
*
* @param parent the parent containment. @since 4.6 null is allowed.
* @param name the plugin name, as returned by KPluginInfo::pluginName()
* @param args to send the containmentactions extra arguments
* @return a ContaimentActions object
**/
virtual ContainmentActions *internalLoadContainmentActions(Containment *parent, const QString &containmentActionsName, const QVariantList &args);
/**
* A re-implementable method that allows subclasses to override
* the default behaviour of loadPackage. If the service requested is not recognized,
* then the implementation should return a NULL pointer. This method is called
* by loadService prior to attempting to load a Service using the standard Plasma
* plugin mechanisms.
*
* @param name the plugin name of the service to load
* @param args a list of arguments to supply to the service plugin when loading it
* @param parent the parent object, if any, for the service
*
* @return a Service object, unlike Plasma::Service::loadService, this can return null.
**/
virtual Package internalLoadPackage(const QString &name, const QString &specialization);
/**
* A re-implementable method that allows subclasses to provide additional applets
* for listAppletInfo. If the application has no applets to give to the application,
* then the implementation should return an empty list.
*
* This method is called by listAppletInfo prior to generating the list of applets installed
* on the system using the standard Plasma plugin mechanisms, and will try to find .desktop
* files for your applets.
*
* @param category Only applets matching this category will be returned.
* Useful in conjunction with knownCategories.
* If "Misc" is passed in, then applets without a
* Categories= entry are also returned.
* If an empty string is passed in, all applets are
* returned.
* @return list of applets
**/
virtual KPluginInfo::List internalAppletInfo(const QString &category) const;
/**
* A re-implementable method that allows subclasses to provide additional DataEngines
* for DataEngine::listDataEngines.
*
* @return list of DataEngines info, or an empty list if none
**/
virtual KPluginInfo::List internalDataEngineInfo() const;
/**
* Returns a list of all known Runner implementations
*
* @return list of AbstractRunners info, or an empty list if none
*/
virtual KPluginInfo::List internalRunnerInfo() const;
/**
* Returns a list of all known Runner implementations
*
* @return list of AbstractRunners info, or an empty list if none
*/
virtual KPluginInfo::List internalServiceInfo() const;
/**
* Returns a list of all known Runner implementations
*
* @return list of ContainmentActions info, or an empty list if none
*/
virtual KPluginInfo::List internalContainmentActionsInfo() const;
/**
* Standardized mechanism for providing internal Applets by install .desktop files
* in $APPPDATA/plasma/internal/applets/
*
* For applications that do this, internalAppletInfo can be implemented as a one-liner
* call to this method.
*
* @param category Only applets matching this category will be returned.
* Useful in conjunction with knownCategories.
* If "Misc" is passed in, then applets without a
* Categories= entry are also returned.
* If an empty string is passed in, all applets are
* returned.
* @return list of Applets, or an empty list if none
*/
KPluginInfo::List standardInternalAppletInfo(const QString &category) const;
/**
* Standardized mechanism for providing internal Applets by install .desktop files
* in $APPPDATA/plasma/internal/dataengines/
*
* For applications that do this, internalDataEngineInfo can be implemented as a one-liner
* call to this method.
*
* @return list of applets
*/
KPluginInfo::List standardInternalDataEngineInfo() const;
/**
* Standardized mechanism for providing internal Applets by install .desktop files
* in $APPPDATA/plasma/internal/runners/
*
* For applications that do this, internalRunnerInfo can be implemented as a one-liner
* call to this method.
*
* @return list of applets
*/
KPluginInfo::List standardInternalRunnerInfo() const;
/**
* Standardized mechanism for providing internal Applets by install .desktop files
* in $APPPDATA/plasma/internal/services/
*
* For applications that do this, internalRunnerInfo can be implemented as a one-liner
* call to this method.
*
* @return list of applets
*/
KPluginInfo::List standardInternalServiceInfo() const;
PluginLoader();
virtual ~PluginLoader();
private:
PluginLoaderPrivate * const d;
};
}
Q_DECLARE_METATYPE(Plasma::PluginLoader*)
#endif

View File

@ -0,0 +1,61 @@
/*
* Copyright 2006-2009 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef ABSTRACTRUNNER_P_H
#define ABSTRACTRUNNER_P_H
#include <QReadWriteLock>
#include "dataengineconsumer.h"
namespace Plasma
{
class AbstractRunner;
class AbstractRunnerPrivate : public DataEngineConsumer
{
public:
AbstractRunnerPrivate(AbstractRunner *r);
~AbstractRunnerPrivate();
void init(const KService::Ptr service);
void init(const QString &path);
void prepScripting(const QString &path, const QString &api);
void setupScriptSupport();
AbstractRunner::Priority priority;
AbstractRunner::Speed speed;
RunnerContext::Types blackListed;
RunnerScript *script;
KPluginInfo runnerDescription;
AbstractRunner *runner;
int fastRuns;
QReadWriteLock speedLock;
Package *package;
QHash<QString, QAction*> actions;
QList<RunnerSyntax> syntaxes;
RunnerSyntax *defaultSyntax;
bool hasRunOptions : 1;
bool suspendMatching : 1;
};
} // namespace Plasma
#endif

View File

@ -0,0 +1,54 @@
/*
* Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef ACCESSMANAGER_P_H
#define ACCESSMANAGER_P_H
#include <dnssd/remoteservice.h>
#include "../remote/accessmanager.h"
class KJob;
namespace DNSSD
{
class ServiceBrowser;
}
namespace Plasma
{
class AccessManagerPrivate
{
public:
AccessManagerPrivate(AccessManager *manager);
~AccessManagerPrivate();
void slotJobFinished(KJob *job);
void slotAddService(DNSSD::RemoteService::Ptr service);
void slotRemoveService(DNSSD::RemoteService::Ptr service);
AccessManager *q;
DNSSD::ServiceBrowser *browser;
QMap<QString, RemoteObjectDescription> services;
QMap<QString, DNSSD::RemoteService::Ptr> zeroconfServices;
};
}
#endif

View File

@ -0,0 +1,100 @@
/******************************************************************************
* Copyright 2009 by Aaron Seigo <aseigo@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 ACTIONWIDGETINTERFACE_P_H
#define ACTIONWIDGETINTERFACE_P_H
#include <QAction>
#include "private/themedwidgetinterface_p.h"
namespace Plasma
{
template <class T>
class ActionWidgetInterface : public ThemedWidgetInterface<T>
{
public:
ActionWidgetInterface(T *parent)
: ThemedWidgetInterface<T>(parent),
action(0)
{
}
virtual ~ActionWidgetInterface()
{
setAction(0);
}
virtual void changed()
{
}
void clearAction()
{
action = 0;
syncToAction();
changed();
}
void syncToAction()
{
if (!action) {
this->q->setIcon(QIcon());
this->q->setText(QString());
this->q->setEnabled(false);
return;
}
//we don't get told *what* changed, just that something changed
//so we update everything we care about
this->q->setIcon(action->icon());
this->q->setText(action->iconText());
this->q->setEnabled(action->isEnabled());
this->q->setVisible(action->isVisible());
if (!this->q->toolTip().isEmpty()) {
this->q->setToolTip(action->text());
}
changed();
}
void setAction(QAction *a)
{
if (action) {
QObject::disconnect(action, 0, this->q, 0);
QObject::disconnect(this->q, 0, action, 0);
}
action = a;
if (action) {
QObject::connect(action, SIGNAL(changed()), this->q, SLOT(syncToAction()));
QObject::connect(action, SIGNAL(destroyed(QObject*)), this->q, SLOT(clearAction()));
QObject::connect(this->q, SIGNAL(clicked()), action, SLOT(trigger()));
syncToAction();
}
}
QAction *action;
};
} // namespace Plasma
#endif

719
plasma/private/applet_p.cpp Normal file
View File

@ -0,0 +1,719 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
* Copyright 2012 by Marco Martin <mart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "private/applet_p.h"
#include <config-plasma.h>
#include <QFile>
#include <QHostInfo>
#include <qstandardpaths.h>
#include <kaction.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kkeysequencewidget.h>
#include <kstandarddirs.h>
#include <kglobal.h>
#include "containment.h"
#include "corona.h"
#include "pluginloader.h"
#include "scripting/scriptengine.h"
#include "scripting/appletscript.h"
#include "private/containment_p.h"
#if ENABLE_REMOTE_WIDGETS
#include "remote/authorizationmanager.h"
#include "remote/authorizationmanager_p.h"
#include "remote/authorizationrule.h"
#endif
namespace Plasma
{
AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet)
: appletId(uniqueID),
q(applet),
remotingService(0),
backgroundHints(StandardBackground),
aspectRatioMode(Plasma::KeepAspectRatio),
immutability(Mutable),
appletDescription(info ? *info : KPluginInfo(service)),
mainConfig(0),
pendingConstraints(NoConstraint),
script(0),
package(0),
configLoader(0),
actions(AppletPrivate::defaultActions(applet)),
activationAction(0),
itemStatus(UnknownStatus),
preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored),
modificationsTimer(0),
hasConfigurationInterface(false),
failed(false),
isContainment(false),
transient(false),
needsConfig(false),
started(false)
{
if (appletId == 0) {
appletId = ++s_maxAppletId;
} else if (appletId > s_maxAppletId) {
s_maxAppletId = appletId;
}
}
AppletPrivate::~AppletPrivate()
{
if (activationAction && activationAction->isGlobalShortcutEnabled()) {
//kDebug() << "reseting global action for" << q->name() << activationAction->objectName();
activationAction->forgetGlobalShortcut();
}
delete script;
script = 0;
delete package;
package = 0;
delete configLoader;
configLoader = 0;
delete mainConfig;
mainConfig = 0;
delete modificationsTimer;
}
void AppletPrivate::init(const QString &packagePath)
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
//set a default size before any saved settings are read
QSize size(200, 200);
q->setBackgroundHints(DefaultBackground);
q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor?
QAction *closeApplet = actions->action("remove");
if (closeApplet) {
closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name()));
}
QAction *configAction = actions->action("configure");
if (configAction) {
configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name()));
}
QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus()));
if (!appletDescription.isValid()) {
#ifndef NDEBUG
kDebug() << "Check your constructor! "
<< "You probably want to be passing in a Service::Ptr "
<< "or a QVariantList with a valid storageid as arg[0].";
#endif
return;
}
QVariant s = appletDescription.property("X-Plasma-DefaultSize");
if (s.isValid()) {
size = s.toSize();
}
//kDebug() << "size" << size;
QString api = appletDescription.property("X-Plasma-API").toString();
// we have a scripted plasmoid
if (api.isEmpty()) {
q->setFailedToLaunch(true, i18n("The %2 widget did not define which ScriptEngine to use.", appletDescription.name()));
return;
}
package = new Package(PluginLoader::self()->loadPackage("Plasma/Applet", api));
// find where the Package is
QString path = packagePath;
if (path.isEmpty()) {
const QString subPath = package->defaultPackageRoot() + appletDescription.pluginName() + '/';
path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath + "metadata.desktop");
if (path.isEmpty()) {
path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath);
} else {
path.remove(QString("metadata.desktop"));
}
} else if (!path.endsWith('/')) {
path.append('/');
}
if (path.isEmpty()) {
delete package;
package = 0;
q->setFailedToLaunch(true,
i18nc("Package file, name of the widget",
"Could not locate the %1 package required for the %2 widget.",
appletDescription.pluginName(), appletDescription.name()));
return;
}
package->setPath(path);
if (!package->isValid()) {
delete package;
package = 0;
q->setFailedToLaunch(true, i18nc("Package file, name of the widget",
"Could not open the %1 package required for the %2 widget.",
appletDescription.pluginName(), appletDescription.name()));
return;
}
// create the package and see if we have something real
//kDebug() << "trying for" << path;
// now we try and set up the script engine.
// it will be parented to this applet and so will get
// deleted when the applet does
script = Plasma::loadScriptEngine(api, q);
if (!script) {
delete package;
package = 0;
q->setFailedToLaunch(true,
i18nc("API or programming language the widget was written in, name of the widget",
"Could not create a %1 ScriptEngine for the %2 widget.",
api, appletDescription.name()));
}
}
void AppletPrivate::cleanUpAndDelete()
{
// reimplemented in the UI specific library
}
void AppletPrivate::showConfigurationRequiredMessage(bool show, const QString &reason)
{
// reimplemented in the UI specific library
Q_UNUSED(show)
Q_UNUSED(reason)
}
void AppletPrivate::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons)
{
// reimplemented in the UI specific library
Q_UNUSED(icon)
Q_UNUSED(message)
Q_UNUSED(buttons)
}
void AppletPrivate::positionMessageOverlay()
{
// reimplemented in the UI specific library
}
void AppletPrivate::setBusy(bool busy)
{
// reimplemented in the UI specific library
Q_UNUSED(busy)
}
bool AppletPrivate::isBusy() const
{
// reimplemented in the UI specific library
return false;
}
void AppletPrivate::updateFailedToLaunch(const QString &reason)
{
// reimplemented in the UI specific library
Q_UNUSED(reason)
}
void AppletPrivate::globalShortcutChanged()
{
if (!activationAction) {
return;
}
KConfigGroup shortcutConfig(mainConfigGroup(), "Shortcuts");
shortcutConfig.writeEntry("global", activationAction->globalShortcut().toString());
scheduleModificationNotification();
//kDebug() << "after" << shortcut.primary() << d->activationAction->globalShortcut().primary();
}
KActionCollection* AppletPrivate::defaultActions(QObject *parent)
{
KActionCollection *actions = new KActionCollection(parent);
actions->setConfigGroup("Shortcuts-Applet");
KAction *configAction = actions->addAction("configure");
configAction->setAutoRepeat(false);
configAction->setText(i18n("Widget Settings"));
configAction->setIcon(KDE::icon("configure"));
configAction->setShortcut(KShortcut("alt+d, s"));
configAction->setData(Containment::ConfigureTool);
KAction *closeApplet = actions->addAction("remove");
closeApplet->setAutoRepeat(false);
closeApplet->setText(i18n("Remove this Widget"));
closeApplet->setIcon(KDE::icon("edit-delete"));
closeApplet->setShortcut(KShortcut("alt+d, r"));
closeApplet->setData(Containment::DestructiveTool);
KAction *runAssociatedApplication = actions->addAction("run associated application");
runAssociatedApplication->setAutoRepeat(false);
runAssociatedApplication->setText(i18n("Run the Associated Application"));
runAssociatedApplication->setIcon(KDE::icon("system-run"));
runAssociatedApplication->setShortcut(KShortcut("alt+d, t"));
runAssociatedApplication->setVisible(false);
runAssociatedApplication->setEnabled(false);
runAssociatedApplication->setData(Containment::ControlTool);
return actions;
}
QString AppletPrivate::configDialogId() const
{
return QString("%1settings%2").arg(appletId).arg(q->name());
}
QString AppletPrivate::configWindowTitle() const
{
return i18nc("@title:window", "%1 Settings", q->name());
}
QSet<QString> AppletPrivate::knownCategories()
{
// this is to trick the tranlsation tools into making the correct
// strings for translation
QSet<QString> categories = s_customCategories;
categories << QString(I18N_NOOP("Accessibility")).toLower()
<< QString(I18N_NOOP("Application Launchers")).toLower()
<< QString(I18N_NOOP("Astronomy")).toLower()
<< QString(I18N_NOOP("Date and Time")).toLower()
<< QString(I18N_NOOP("Development Tools")).toLower()
<< QString(I18N_NOOP("Education")).toLower()
<< QString(I18N_NOOP("Environment and Weather")).toLower()
<< QString(I18N_NOOP("Examples")).toLower()
<< QString(I18N_NOOP("File System")).toLower()
<< QString(I18N_NOOP("Fun and Games")).toLower()
<< QString(I18N_NOOP("Graphics")).toLower()
<< QString(I18N_NOOP("Language")).toLower()
<< QString(I18N_NOOP("Mapping")).toLower()
<< QString(I18N_NOOP("Miscellaneous")).toLower()
<< QString(I18N_NOOP("Multimedia")).toLower()
<< QString(I18N_NOOP("Online Services")).toLower()
<< QString(I18N_NOOP("Productivity")).toLower()
<< QString(I18N_NOOP("System Information")).toLower()
<< QString(I18N_NOOP("Utilities")).toLower()
<< QString(I18N_NOOP("Windows and Tasks")).toLower();
return categories;
}
KConfigDialog *AppletPrivate::generateGenericConfigDialog()
{
KConfigSkeleton *nullManager = new KConfigSkeleton(0);
KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager);
nullManager->setParent(dialog);
dialog->setFaceType(KPageDialog::Auto);
dialog->setWindowTitle(configWindowTitle());
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
q->createConfigurationInterface(dialog);
dialog->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel);
QObject::connect(dialog->button(QDialogButtonBox::Apply), SIGNAL(clicked()), q, SLOT(configDialogFinished()));
QObject::connect(dialog->button(QDialogButtonBox::Ok), SIGNAL(clicked()), q, SLOT(configDialogFinished()));
return dialog;
}
void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog)
{
addGlobalShortcutsPage(dialog);
addPublishPage(dialog);
}
void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog)
{
#if !PLASMA_NO_GLOBAL_SHORTCUTS
if (isContainment) {
return;
}
QWidget *page = new QWidget;
QVBoxLayout *layout = new QVBoxLayout(page);
if (!shortcutEditor) {
shortcutEditor = new KKeySequenceWidget(page);
QObject::connect(shortcutEditor.data(), SIGNAL(keySequenceChanged(QKeySequence)), dialog, SLOT(settingsModified()));
}
shortcutEditor.data()->setKeySequence(q->globalShortcut().primary());
layout->addWidget(shortcutEditor.data());
layout->addStretch();
dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard");
QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
#endif
}
void AppletPrivate::addPublishPage(KConfigDialog *dialog)
{
#if ENABLE_REMOTE_WIDGETS
QWidget *page = new QWidget;
publishUI.setupUi(page);
publishUI.publishCheckbox->setChecked(q->isPublished());
QObject::connect(publishUI.publishCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
publishUI.allUsersCheckbox->setEnabled(q->isPublished());
QObject::connect(publishUI.allUsersCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
QString resourceName =
i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
"%1 on %2", q->name(), QHostInfo::localHostName());
if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
publishUI.allUsersCheckbox->setChecked(true);
} else {
publishUI.allUsersCheckbox->setChecked(false);
}
q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)),
q, SLOT(publishCheckboxStateChanged(int)));
dialog->addPage(page, i18n("Share"), "applications-internet");
#endif
}
void AppletPrivate::publishCheckboxStateChanged(int state)
{
if (state == Qt::Checked) {
publishUI.allUsersCheckbox->setEnabled(true);
} else {
publishUI.allUsersCheckbox->setEnabled(false);
}
}
void AppletPrivate::configDialogFinished()
{
if (shortcutEditor) {
QKeySequence sequence = shortcutEditor.data()->keySequence();
if (sequence != q->globalShortcut().primary()) {
q->setGlobalShortcut(KShortcut(sequence));
emit q->configNeedsSaving();
}
}
#if ENABLE_REMOTE_WIDGETS
if (KConfigDialog::exists(configDialogId()) && publishUI.publishCheckbox) {
q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked());
if (publishUI.publishCheckbox->isChecked()) {
QString resourceName =
i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
"%1 on %2", q->name(), QHostInfo::localHostName());
q->publish(Plasma::ZeroconfAnnouncement, resourceName);
if (publishUI.allUsersCheckbox->isChecked()) {
if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
AuthorizationRule *rule = new AuthorizationRule(resourceName, "");
rule->setPolicy(AuthorizationRule::Allow);
rule->setTargets(AuthorizationRule::AllUsers);
AuthorizationManager::self()->d->rules.append(rule);
}
} else {
AuthorizationRule *matchingRule =
AuthorizationManager::self()->d->matchingRule(resourceName, Credentials());
if (matchingRule) {
AuthorizationManager::self()->d->rules.removeAll(matchingRule);
}
}
} else {
q->unpublish();
}
}
#endif
if (!configLoader) {
// the config loader will trigger this for us, so we don't need to.
propagateConfigChanged();
if (KConfigDialog *dialog = qobject_cast<KConfigDialog *>(q->sender())) {
dialog->button(QDialogButtonBox::Apply)->setEnabled(false);
}
}
}
void AppletPrivate::updateShortcuts()
{
if (isContainment) {
//a horrible hack to avoid clobbering corona settings
//we pull them out, then read, then put them back
QList<QString> names;
QList<QAction*> qactions;
names << "add sibling containment" << "configure shortcuts" << "lock widgets";
foreach (const QString &name, names) {
QAction *a = actions->action(name);
actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method
qactions << a;
}
actions->readSettings();
for (int i = 0; i < names.size(); ++i) {
QAction *a = qactions.at(i);
if (a) {
actions->addAction(names.at(i), a);
}
}
} else {
actions->readSettings();
}
}
void AppletPrivate::propagateConfigChanged()
{
if (isContainment) {
Containment *c = qobject_cast<Containment *>(q);
if (c) {
c->d->configChanged();
}
}
q->configChanged();
}
void AppletPrivate::filterOffers(QList<KService::Ptr> &offers)
{
KConfigGroup constraintGroup(KSharedConfig::openConfig(), "Constraints");
foreach (const QString &key, constraintGroup.keyList()) {
//kDebug() << "security constraint" << key;
if (constraintGroup.readEntry(key, true)) {
continue;
}
//ugh. a qlist of ksharedptr<kservice>
QMutableListIterator<KService::Ptr> it(offers);
while (it.hasNext()) {
KService::Ptr p = it.next();
QString prop = QString("X-Plasma-Requires-").append(key);
QVariant req = p->property(prop, QVariant::String);
//valid values: Required/Optional/Unused
QString reqValue;
if (req.isValid()) {
reqValue = req.toString();
} else if (p->property("X-Plasma-API").toString().toLower() == "javascript") {
//TODO: be able to check whether or not a script engine provides "controled"
//bindings; for now we just give a pass to the qscript ones
reqValue = "Unused";
}
if (!(reqValue == "Optional" || reqValue == "Unused")) {
//if (reqValue == "Required") {
it.remove();
}
}
}
}
QString AppletPrivate::parentAppConstraint(const QString &parentApp)
{
if (parentApp.isEmpty()) {
QCoreApplication *app = QCoreApplication::instance();
if (!app) {
return QString();
}
return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')")
.arg(app->applicationName());
}
return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp);
}
void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate)
{
if (isContainment == nowIsContainment && !forceUpdate) {
return;
}
isContainment = nowIsContainment;
//FIXME I do not like this function.
//currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way.
//if someone calls it at some other time it'll cause headaches. :P
delete mainConfig;
mainConfig = 0;
Containment *c = q->containment();
if (c) {
c->d->checkContainmentFurniture();
}
}
// put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engine
void AppletPrivate::setupScriptSupport()
{
if (!package) {
return;
}
#ifndef NDEBUG
kDebug() << "setting up script support, package is in" << package->path()
<< ", main script is" << package->filePath("mainscript");
#endif
const QString translationsPath = package->filePath("translations");
if (!translationsPath.isEmpty()) {
KGlobal::dirs()->addResourceDir("locale", translationsPath);
KLocalizedString::insertCatalog(appletDescription.pluginName());
}
const QString xmlPath = package->filePath("mainconfigxml");
if (!xmlPath.isEmpty()) {
QFile file(xmlPath);
KConfigGroup config = q->config();
configLoader = new ConfigLoader(&config, &file);
QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged()));
}
if (!package->filePath("mainconfigui").isEmpty()) {
q->setHasConfigurationInterface(true);
}
}
QString AppletPrivate::globalName() const
{
if (!appletDescription.isValid()) {
return QString();
}
return appletDescription.service()->library();
}
QString AppletPrivate::instanceName()
{
if (!appletDescription.isValid()) {
return QString();
}
return appletDescription.service()->library() + QString::number(appletId);
}
void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c)
{
// Don't start up a timer if we're just starting up
// flushPendingConstraints will be called by Corona
if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) {
constraintsTimer.start(0, q);
}
if (c & Plasma::StartupCompletedConstraint) {
started = true;
}
pendingConstraints |= c;
}
void AppletPrivate::scheduleModificationNotification()
{
// modificationsTimer is not allocated until we get our notice of being started
if (modificationsTimer) {
// schedule a save
if (modificationsTimer->isActive()) {
modificationsTimer->stop();
}
modificationsTimer->start(1000, q);
}
}
KConfigGroup *AppletPrivate::mainConfigGroup()
{
if (mainConfig) {
return mainConfig;
}
if (isContainment) {
Corona *corona = static_cast<Containment*>(q)->corona();
KConfigGroup containmentConfig;
//kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q;
if (corona) {
containmentConfig = KConfigGroup(corona->config(), "Containments");
} else {
containmentConfig = KConfigGroup(KSharedConfig::openConfig(), "Containments");
}
mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId));
} else {
KConfigGroup appletConfig;
Containment *c = q->containment();
Applet *parentApplet = qobject_cast<Applet *>(q->parent());
if (parentApplet && parentApplet != static_cast<Applet *>(c)) {
// this applet is nested inside another applet! use it's config
// as the parent group in the config
appletConfig = parentApplet->config();
appletConfig = KConfigGroup(&appletConfig, "Applets");
} else if (c) {
// applet directly in a Containment, as usual
appletConfig = c->config();
appletConfig = KConfigGroup(&appletConfig, "Applets");
} else {
kWarning() << "requesting config for" << q->name() << "without a containment!";
appletConfig = KConfigGroup(KSharedConfig::openConfig(), "Applets");
}
mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId));
}
return mainConfig;
}
QString AppletPrivate::visibleFailureText(const QString &reason)
{
QString text;
if (reason.isEmpty()) {
text = i18n("This object could not be created.");
} else {
text = i18n("This object could not be created for the following reason:<p><b>%1</b></p>", reason);
}
return text;
}
void AppletPrivate::resetConfigurationObject()
{
// make sure mainConfigGroup exists in all cases
mainConfigGroup();
mainConfig->deleteGroup();
delete mainConfig;
mainConfig = 0;
if (!q->containment()) {
return;
}
Corona * corona = q->containment()->corona();
if (corona) {
corona->requireConfigSync();
}
}
uint AppletPrivate::s_maxAppletId = 0;
QSet<QString> AppletPrivate::s_customCategories;
} //namespace Plasma

188
plasma/private/applet_p.h Normal file
View File

@ -0,0 +1,188 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_APPLET_P_H
#define PLASMA_APPLET_P_H
#include <QBasicTimer>
#include <kactioncollection.h>
#include <kconfigdialog.h>
#include <kconfigskeleton.h>
#include <kservice.h>
#include <kplugininfo.h>
#include "plasma/applet.h"
#include "plasma/dataengineconsumer.h"
#include "plasma/ui_publish.h"
class KKeySequenceWidget;
namespace Plasma
{
class Dialog;
class FrameSvg;
class AppletScript;
class Wallpaper;
class BusyWidget;
class PushButton;
class Service;
class AppletConfigDialog : public KConfigDialog
{
Q_OBJECT
public:
AppletConfigDialog(QWidget* parent, const QString &id, KConfigSkeleton *s)
: KConfigDialog(parent, id, s),
m_changed(false)
{
}
public Q_SLOTS:
void settingsModified(bool modified = true)
{
m_changed = modified;
updateButtons();
}
protected:
bool hasChanged()
{
return m_changed || KConfigDialog::hasChanged();
}
private:
bool m_changed;
};
class PLASMA_EXPORT AppletPrivate : public DataEngineConsumer
{
public:
AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet);
virtual ~AppletPrivate();
void init(const QString &packagePath = QString());
// the interface
virtual void showConfigurationRequiredMessage(bool show, const QString &reason);
virtual void cleanUpAndDelete();
virtual void showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons);
virtual void positionMessageOverlay();
virtual void setBusy(bool busy);
virtual bool isBusy() const;
virtual void updateFailedToLaunch(const QString &reason);
// put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engin
void setupScriptSupport();
/**
* Sets whether or not this Applet is acting as a Containment
*/
void setIsContainment(bool isContainment, bool forceUpdate = false);
QString globalName() const;
QString instanceName();
void scheduleConstraintsUpdate(Plasma::Constraints c);
void scheduleModificationNotification();
KConfigGroup *mainConfigGroup();
QString visibleFailureText(const QString &reason);
void resetConfigurationObject();
void addGlobalShortcutsPage(KConfigDialog *dialog);
void addPublishPage(KConfigDialog *dialog);
void configDialogFinished();
KConfigDialog *generateGenericConfigDialog();
void addStandardConfigurationPages(KConfigDialog *dialog);
QString configDialogId() const;
QString configWindowTitle() const;
void updateShortcuts();
void publishCheckboxStateChanged(int state);
void globalShortcutChanged();
void propagateConfigChanged();
static KActionCollection* defaultActions(QObject *parent);
static QSet<QString> knownCategories();
static void filterOffers(QList<KService::Ptr> &offers);
static QString parentAppConstraint(const QString &parentApp = QString());
static uint s_maxAppletId;
static QSet<QString> s_customCategories;
// number of members at this point.
uint appletId;
Applet *q;
// applet attributes
Service *remotingService;
BackgroundHints backgroundHints;
AspectRatioMode aspectRatioMode;
ImmutabilityType immutability;
// applet info we keep around in case its needed
KPluginInfo appletDescription;
QVariantList args;
QString customName;
// bookkeeping
KConfigGroup *mainConfig;
Plasma::Constraints pendingConstraints;
// sripting and package stuff
AppletScript *script;
Package *package;
ConfigLoader *configLoader;
// actions stuff; put activationAction into actions?
KActionCollection *actions;
KAction *activationAction;
// configuration
QWeakPointer<KKeySequenceWidget> shortcutEditor; //TODO: subclass KConfigDialog and encapsulate this in there
ItemStatus itemStatus;
KUrl remoteLocation;
Ui::publishWidget publishUI;
// the applet can change size policy by itself, so save the old one for eventual restore
QSizePolicy preferredSizePolicy;
//keep last sizes for formfactors, useful when the containment changes
QHash<FormFactor, QSizeF> sizeForFormFactor;
// timerEvent bookkeeping
QBasicTimer constraintsTimer;
QBasicTimer *modificationsTimer;
// a great green field of booleans :)
bool hasConfigurationInterface : 1;
bool failed : 1;
bool isContainment : 1;
bool square : 1;
bool transient : 1;
bool needsConfig : 1;
bool started : 1;
};
} // Plasma namespace
#endif

View File

@ -0,0 +1,155 @@
/*
* Copyright 2009 Marco Martin <notmart@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "associatedapplicationmanager_p.h"
#include "config-plasma.h"
#include <QHash>
#include <QFile>
#include <qstandardpaths.h>
#include <klocalizedstring.h>
#include <kiconloader.h>
#if !PLASMA_NO_KIO
#include <krun.h>
#else
#include <QProcess>
#include <QDesktopServices>
#endif
#include "plasma/applet.h"
namespace Plasma
{
class AssociatedApplicationManagerPrivate
{
public:
AssociatedApplicationManagerPrivate()
{
}
~AssociatedApplicationManagerPrivate()
{
}
void cleanupApplet(QObject *obj)
{
Plasma::Applet *applet = static_cast<Plasma::Applet *>(obj);
applicationNames.remove(applet);
urlLists.remove(applet);
}
QHash<const Plasma::Applet *, QString> applicationNames;
QHash<const Plasma::Applet *, QList<QUrl> > urlLists;
};
class AssociatedApplicationManagerSingleton
{
public:
AssociatedApplicationManager self;
};
Q_GLOBAL_STATIC(AssociatedApplicationManagerSingleton, privateAssociatedApplicationManagerSelf)
AssociatedApplicationManager::AssociatedApplicationManager(QObject *parent)
: QObject(parent),
d(new AssociatedApplicationManagerPrivate())
{
}
AssociatedApplicationManager::~AssociatedApplicationManager()
{
delete d;
}
AssociatedApplicationManager *AssociatedApplicationManager::self()
{
return &privateAssociatedApplicationManagerSelf()->self;
}
void AssociatedApplicationManager::setApplication(Plasma::Applet *applet, const QString &application)
{
KService::Ptr service = KService::serviceByDesktopName(application);
if (service || !QStandardPaths::findExecutable(application).isNull() || QFile::exists(application)) {
d->applicationNames[applet] = application;
if (!d->urlLists.contains(applet)) {
connect(applet, SIGNAL(destroyed(QObject*)), this, SLOT(cleanupApplet(QObject*)));
}
}
}
QString AssociatedApplicationManager::application(const Plasma::Applet *applet) const
{
return d->applicationNames.value(applet);
}
void AssociatedApplicationManager::setUrls(Plasma::Applet *applet, const QList<QUrl> &urls)
{
d->urlLists[applet] = urls;
}
QList<QUrl> AssociatedApplicationManager::urls(const Plasma::Applet *applet) const
{
return d->urlLists.value(applet);
}
void AssociatedApplicationManager::run(Plasma::Applet *applet)
{
if (d->applicationNames.contains(applet)) {
#if !PLASMA_NO_KIO
bool success = KRun::run(d->applicationNames.value(applet), d->urlLists.value(applet), 0);
#else
QString execCommand = d->applicationNames.value(applet);
// Clean-up the %u and friends from the exec command (KRun expect them, not QProcess)
execCommand = execCommand.replace(QRegExp("%[a-z]"), QString());
execCommand = execCommand.trimmed();
QStringList parameters = d->urlLists.value(applet).toStringList();
bool success = QProcess::startDetached(execCommand, parameters);
#endif
if (!success) {
applet->showMessage(KDE::icon("application-exit"), i18n("There was an error attempting to exec the associated application with this widget."), ButtonOk);
}
} else if (d->urlLists.contains(applet) && !d->urlLists.value(applet).isEmpty()) {
#if !PLASMA_NO_KIO
KRun *krun = new KRun(d->urlLists.value(applet).first(), 0);
krun->setAutoDelete(true);
#else
QDesktopServices::openUrl(d->urlLists.value(applet).first());
#endif
}
}
bool AssociatedApplicationManager::appletHasValidAssociatedApplication(const Plasma::Applet *applet) const
{
return (d->applicationNames.contains(applet) || d->urlLists.contains(applet));
}
} // namespace Plasma
#include <moc_associatedapplicationmanager_p.cpp>

View File

@ -0,0 +1,67 @@
/*
* Copyright 2009 Marco Martin <notmart@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_ASSOCIATEDAPPLICATIONMANAGER_P_H
#define PLASMA_ASSOCIATEDAPPLICATIONMANAGER_P_H
#include <QObject>
#include <kurl.h>
namespace Plasma
{
class Applet;
class AssociatedApplicationManagerPrivate;
class AssociatedApplicationManager : public QObject
{
Q_OBJECT
public:
static AssociatedApplicationManager *self();
//set an application name for an applet
void setApplication(Plasma::Applet *applet, const QString &application);
//returns the application name associated to an applet
QString application(const Plasma::Applet *applet) const;
//sets the urls associated to an applet
void setUrls(Plasma::Applet *applet, const QList<QUrl> &urls);
//returns the urls associated to an applet
QList<QUrl> urls(const Plasma::Applet *applet) const;
//run the associated application or the urls if no app is associated
void run(Plasma::Applet *applet);
//returns true if the applet has a valid associated application or urls
bool appletHasValidAssociatedApplication(const Plasma::Applet *applet) const;
private:
AssociatedApplicationManager(QObject *parent = 0);
~AssociatedApplicationManager();
AssociatedApplicationManagerPrivate *const d;
friend class AssociatedApplicationManagerSingleton;
Q_PRIVATE_SLOT(d, void cleanupApplet(QObject *obj))
};
} // namespace Plasma
#endif // multiple inclusion guard

View File

@ -0,0 +1,101 @@
/*
* Copyright 2011 Kevin Kofler <kevin.kofler@chello.at>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "private/componentinstaller_p.h"
#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT
#include <QSet>
#include <QDBusInterface>
#include <QDBusPendingCall>
#include <QWidget>
#include <QLatin1String>
#include <QStringList>
#endif
namespace Plasma
{
class ComponentInstallerPrivate
{
public:
#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT
QSet<QString> alreadyPrompted;
#endif
};
class ComponentInstallerSingleton
{
public:
ComponentInstaller self;
};
Q_GLOBAL_STATIC(ComponentInstallerSingleton, privateComponentInstallerSelf)
ComponentInstaller *ComponentInstaller::self()
{
return &privateComponentInstallerSelf()->self;
}
ComponentInstaller::ComponentInstaller()
: d(new ComponentInstallerPrivate)
{
}
ComponentInstaller::~ComponentInstaller()
{
delete d;
}
void ComponentInstaller::installMissingComponent(const QString &type,
const QString &name,
QWidget *parent, bool force)
{
#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT
QString searchString = type + '-' + name;
if (!force) {
if (d->alreadyPrompted.contains(searchString)) {
return;
}
}
d->alreadyPrompted.insert(searchString);
QDBusInterface packageKit(QLatin1String("org.freedesktop.PackageKit"),
QLatin1String("/org/freedesktop/PackageKit"),
QLatin1String("org.freedesktop.PackageKit.Modify"));
// We don't check packageKit.isValid() because the service is activated on
// demand, so it will show up as "not valid".
WId wid = 0;
if (parent) {
wid = parent->winId();
}
QStringList resources;
resources.append(searchString);
packageKit.asyncCall(QLatin1String("InstallResources"), (unsigned int) wid,
QLatin1String("plasma-service"), resources, QString());
#else
Q_UNUSED(type);
Q_UNUSED(name);
Q_UNUSED(parent);
Q_UNUSED(force);
#endif
}
} // namespace Plasma

View File

@ -0,0 +1,94 @@
/*
* Copyright 2011 Kevin Kofler <kevin.kofler@chello.at>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_COMPONENTINSTALLER_H
#define PLASMA_COMPONENTINSTALLER_H
class QString;
class QWidget;
namespace Plasma
{
class ComponentInstallerPrivate;
/**
* @class ComponentInstaller plasma/private/componentinstaller_p.h
*
* @short This class provides a generic API for installation of components.
*
* @internal
*
* Plasma::ComponentInstaller allows searching for a missing data or script
* engine by name, and allowing the user to install the missing service.
* Currently, PackageKit is supported as the mechanism to install components,
* but more mechanisms could be supported in the future through the same API.
*
* @since 4.8
*/
class ComponentInstaller
{
public:
/**
* Singleton pattern accessor.
*/
static ComponentInstaller *self();
/**
* Installs a missing component asynchronously.
*
* By default, this method will cache requested components and not
* prompt again for the same engine in the same session. The force
* parameter can be used to disable this mechanism, e.g. when the user
* just installed a new widget written in a scripting language, and so
* is likely to want the script engine installed after all.
*
* In the case of on-demand installation, this will unfortunately not
* allow the call which triggered the missing component lookup to
* succeed, but we cannot afford to block all of Plasma until the
* mechanism is done installing the service.
*
* This function does nothing if PackageKit integration was disabled at
* compile time.
*
* @param type the type of the component, should be "scriptengine" or
* "dataengine"
* @param name the name of the component
* @param parent a parent widget, used to set the wid for PackageKit
* @param force whether to always prompt, even if recently prompted
*/
void installMissingComponent(const QString &type, const QString &name,
QWidget *parent = 0, bool force = false);
private:
/**
* Default constructor. The singleton method self() is the
* preferred access mechanism.
*/
ComponentInstaller();
~ComponentInstaller();
ComponentInstallerPrivate *const d;
friend class ComponentInstallerSingleton;
};
} // namespace Plasma
#endif // multiple inclusion guard

View File

@ -0,0 +1,223 @@
/*
* Copyright 2007-2008 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CONFIGLOADER_P_H
#define PLASMA_CONFIGLOADER_P_H
#include <kurl.h>
namespace Plasma
{
class ConfigLoaderPrivate
{
public:
ConfigLoaderPrivate()
: saveDefaults(false)
{
}
~ConfigLoaderPrivate()
{
qDeleteAll(bools);
qDeleteAll(strings);
qDeleteAll(stringlists);
qDeleteAll(colors);
qDeleteAll(fonts);
qDeleteAll(ints);
qDeleteAll(uints);
qDeleteAll(urls);
qDeleteAll(dateTimes);
qDeleteAll(doubles);
qDeleteAll(intlists);
qDeleteAll(longlongs);
qDeleteAll(points);
qDeleteAll(rects);
qDeleteAll(sizes);
qDeleteAll(ulonglongs);
qDeleteAll(urllists);
}
bool *newBool()
{
bool *v = new bool;
bools.append(v);
return v;
}
QString *newString()
{
QString *v = new QString;
strings.append(v);
return v;
}
QStringList *newStringList()
{
QStringList *v = new QStringList;
stringlists.append(v);
return v;
}
QColor *newColor()
{
QColor *v = new QColor;
colors.append(v);
return v;
}
QFont *newFont()
{
QFont *v = new QFont;
fonts.append(v);
return v;
}
qint32 *newInt()
{
qint32 *v = new qint32;
ints.append(v);
return v;
}
quint32 *newUint()
{
quint32 *v = new quint32;
uints.append(v);
return v;
}
KUrl *newUrl()
{
KUrl *v = new KUrl;
urls.append(v);
return v;
}
QDateTime *newDateTime()
{
QDateTime *v = new QDateTime;
dateTimes.append(v);
return v;
}
double *newDouble()
{
double *v = new double;
doubles.append(v);
return v;
}
QList<qint32>* newIntList()
{
QList<qint32> *v = new QList<qint32>;
intlists.append(v);
return v;
}
qint64 *newLongLong()
{
qint64 *v = new qint64;
longlongs.append(v);
return v;
}
QPoint *newPoint()
{
QPoint *v = new QPoint;
points.append(v);
return v;
}
QRect *newRect()
{
QRect *v = new QRect;
rects.append(v);
return v;
}
QSize *newSize()
{
QSize *v = new QSize;
sizes.append(v);
return v;
}
quint64 *newULongLong()
{
quint64 *v = new quint64;
ulonglongs.append(v);
return v;
}
QList<QUrl> *newUrlList()
{
QList<QUrl> *v = new QList<QUrl>();
urllists.append(v);
return v;
}
void parse(ConfigLoader *loader, QIODevice *xml);
/**
* Whether or not to write out default values.
*
* @param writeDefaults true if defaults should be written out
*/
void setWriteDefaults(bool writeDefaults)
{
saveDefaults = writeDefaults;
}
/**
* @return true if default values will also be written out
*/
bool writeDefaults() const
{
return saveDefaults;
}
QList<bool *> bools;
QList<QString *> strings;
QList<QStringList *> stringlists;
QList<QColor *> colors;
QList<QFont *> fonts;
QList<qint32 *> ints;
QList<quint32 *> uints;
QList<KUrl *> urls;
QList<QDateTime *> dateTimes;
QList<double *> doubles;
QList<QList<qint32> *> intlists;
QList<qint64 *> longlongs;
QList<QPoint *> points;
QList<QRect *> rects;
QList<QSize *> sizes;
QList<quint64 *> ulonglongs;
QList<QList<QUrl> *> urllists;
QString baseGroup;
QStringList groups;
QHash<QString, QString> keysToNames;
bool saveDefaults;
};
} // namespace Plasma
#endif

View File

@ -0,0 +1,500 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
* Copyright 2009 Chani Armitage <chani@kde.org>
* Copyright 2012 Marco Martin <notmart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "private/containment_p.h"
#include <QApplication>
#include <QClipboard>
#include <QMimeData>
#include <QMimeDatabase>
#include <QDropEvent>
#include <qtemporaryfile.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <kcoreauthorized.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kurlmimedata.h>
#include <kwindowsystem.h>
#include "config-plasma.h"
#if !PLASMA_NO_KIO
#include "kio/jobclasses.h" // for KIO::JobFlags
#include "kio/job.h"
#include "kio/scheduler.h"
#endif
#include "containmentactions.h"
#include "containmentactionspluginsconfig.h"
#include "corona.h"
#include "pluginloader.h"
#include "svg.h"
#include "remote/accessappletjob.h"
#include "remote/accessmanager.h"
#include "private/applet_p.h"
#include "private/containmentactionspluginsconfig_p.h"
namespace Plasma
{
bool ContainmentPrivate::s_positioningPanels = false;
QHash<QString, ContainmentActions*> ContainmentPrivate::globalActionPlugins;
const char ContainmentPrivate::defaultWallpaper[] = "image";
const char ContainmentPrivate::defaultWallpaperMode[] = "SingleImage";
void ContainmentPrivate::addDefaultActions(KActionCollection *actions, Containment *c)
{
actions->setConfigGroup("Shortcuts-Containment");
//adjust applet actions
KAction *appAction = qobject_cast<KAction*>(actions->action("remove"));
appAction->setShortcut(KShortcut("alt+d, alt+r"));
if (c && c->d->isPanelContainment()) {
appAction->setText(i18n("Remove this Panel"));
} else {
appAction->setText(i18n("Remove this Activity"));
}
appAction = qobject_cast<KAction*>(actions->action("configure"));
if (appAction) {
appAction->setShortcut(KShortcut("alt+d, alt+s"));
appAction->setText(i18n("Activity Settings"));
}
//add our own actions
KAction *appletBrowserAction = actions->addAction("add widgets");
appletBrowserAction->setAutoRepeat(false);
appletBrowserAction->setText(i18n("Add Widgets..."));
appletBrowserAction->setIcon(KDE::icon("list-add"));
appletBrowserAction->setShortcut(KShortcut("alt+d, a"));
appletBrowserAction->setData(Containment::AddTool);
KAction *action = actions->addAction("next applet");
action->setText(i18n("Next Widget"));
//no icon
action->setShortcut(KShortcut("alt+d, n"));
action->setData(Containment::ControlTool);
action = actions->addAction("previous applet");
action->setText(i18n("Previous Widget"));
//no icon
action->setShortcut(KShortcut("alt+d, p"));
action->setData(Containment::ControlTool);
}
void ContainmentPrivate::initApplets()
{
foreach (Applet *applet, applets) {
applet->restore(*applet->d->mainConfigGroup());
applet->init();
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Applet" << applet->name();
#endif
}
q->flushPendingConstraintsEvents();
foreach (Applet *applet, applets) {
applet->flushPendingConstraintsEvents();
}
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Containment's applets initialized" << q->name();
#endif
}
void ContainmentPrivate::checkContainmentFurniture()
{
if (q->isContainment() &&
(type == Containment::DesktopContainment || type == Containment::PanelContainment)) {
}
}
void ContainmentPrivate::addContainmentActions(KMenu &desktopMenu, QEvent *event)
{
if (q->corona()->immutability() != Mutable &&
!KAuthorized::authorizeKAction("plasma/containment_actions")) {
//kDebug() << "immutability";
return;
}
const QString trigger = ContainmentActions::eventToString(event);
prepareContainmentActions(trigger, QPoint(), &desktopMenu);
}
void ContainmentPrivate::addAppletActions(KMenu &desktopMenu, Applet *applet, QEvent *event)
{
foreach (QAction *action, applet->contextualActions()) {
if (action) {
desktopMenu.addAction(action);
}
}
if (!applet->d->failed) {
QAction *configureApplet = applet->d->actions->action("configure");
if (configureApplet && configureApplet->isEnabled()) {
desktopMenu.addAction(configureApplet);
}
QAction *runAssociatedApplication = applet->d->actions->action("run associated application");
if (runAssociatedApplication && runAssociatedApplication->isEnabled()) {
desktopMenu.addAction(runAssociatedApplication);
}
}
KMenu *containmentMenu = new KMenu(i18nc("%1 is the name of the containment", "%1 Options", q->name()), &desktopMenu);
addContainmentActions(*containmentMenu, event);
if (!containmentMenu->isEmpty()) {
int enabled = 0;
//count number of real actions
QListIterator<QAction *> actionsIt(containmentMenu->actions());
while (enabled < 3 && actionsIt.hasNext()) {
QAction *action = actionsIt.next();
if (action->isVisible() && !action->isSeparator()) {
++enabled;
}
}
if (enabled) {
//if there is only one, don't create a submenu
if (enabled < 2) {
foreach (QAction *action, containmentMenu->actions()) {
if (action->isVisible() && !action->isSeparator()) {
desktopMenu.addAction(action);
}
}
} else {
desktopMenu.addMenu(containmentMenu);
}
}
}
if (q->immutability() == Mutable) {
QAction *closeApplet = applet->d->actions->action("remove");
//kDebug() << "checking for removal" << closeApplet;
if (closeApplet) {
if (!desktopMenu.isEmpty()) {
desktopMenu.addSeparator();
}
//kDebug() << "adding close action" << closeApplet->isEnabled() << closeApplet->isVisible();
desktopMenu.addAction(closeApplet);
}
}
}
void ContainmentPrivate::setScreen(int newScreen, int newDesktop, bool preventInvalidDesktops)
{
// What we want to do in here is:
// * claim the screen as our own
// * signal whatever may be watching this containment about the switch
// * if we are a full screen containment, then:
// * resize to match the screen if we're that kind of containment
// * kick other full-screen containments off this screen
// * if we had a screen, then give our screen to the containment
// we kick out
//
// a screen of -1 means no associated screen.
Corona *corona = q->corona();
Q_ASSERT(corona);
//if it's an offscreen widget, don't allow to claim a screen, after all it's *off*screen
//TODO: port away qgv
/* should decide in a different way if this is a dashboard containment
if (corona->offscreenWidgets().contains(q)) {
return;
}*/
if (newScreen < -1) {
newScreen = -1;
}
// -1 == All desktops
if (newDesktop < -1 || (preventInvalidDesktops && newDesktop > KWindowSystem::numberOfDesktops() - 1)) {
newDesktop = -1;
}
//kDebug() << activity() << "setting screen to " << newScreen << newDesktop << "and type is" << type;
Containment *swapScreensWith(0);
const bool isDesktopContainment = type == Containment::DesktopContainment ||
type == Containment::CustomContainment;
if (isDesktopContainment) {
if (newScreen > -1) {
// sanity check to make sure someone else doesn't have this screen already!
Containment *currently = corona->containmentForScreen(newScreen, newDesktop);
if (currently && currently != q) {
#ifndef NDEBUG
kDebug() << "currently is on screen" << currently->screen()
<< "desktop" << currently->desktop()
<< "and is" << currently->activity()
<< (QObject*)currently << "i'm" << (QObject*)q;
#endif
currently->setScreen(-1, currently->desktop());
swapScreensWith = currently;
}
}
}
int oldDesktop = desktop;
desktop = newDesktop;
int oldScreen = screen;
screen = newScreen;
q->updateConstraints(Plasma::ScreenConstraint);
if (oldScreen != newScreen || oldDesktop != newDesktop) {
/*
#ifndef NDEBUG
kDebug() << "going to signal change for" << q
#endif
<< ", old screen & desktop:" << oldScreen << oldDesktop
<< ", new:" << screen << desktop;
*/
KConfigGroup c = q->config();
c.writeEntry("screen", screen);
c.writeEntry("desktop", desktop);
if (newScreen != -1) {
lastScreen = newScreen;
lastDesktop = newDesktop;
c.writeEntry("lastScreen", lastScreen);
c.writeEntry("lastDesktop", lastDesktop);
}
emit q->configNeedsSaving();
emit q->screenChanged(oldScreen, newScreen, q);
}
if (swapScreensWith) {
//kDebug() << "setScreen due to swap, part 2";
swapScreensWith->setScreen(oldScreen, oldDesktop);
}
checkRemoveAction();
if (newScreen >= 0) {
emit q->activate();
}
}
KActionCollection* ContainmentPrivate::actions()
{
return static_cast<Applet*>(q)->d->actions;
}
void ContainmentPrivate::configChanged()
{
if (drawWallpaper) {
KConfigGroup group = q->config();
q->setWallpaper(group.readEntry("wallpaperplugin", defaultWallpaper),
group.readEntry("wallpaperpluginmode", defaultWallpaperMode));
}
}
void ContainmentPrivate::requestConfiguration()
{
emit q->configureRequested(q);
}
void ContainmentPrivate::checkStatus(Plasma::ItemStatus appletStatus)
{
//kDebug() << "================== "<< appletStatus << q->status();
if (appletStatus == q->status()) {
emit q->newStatus(appletStatus);
return;
}
if (appletStatus < q->status()) {
// check to see if any other applet has a higher status, and stick with that
// if we do
foreach (Applet *applet, applets) {
if (applet->status() > appletStatus) {
appletStatus = applet->status();
}
}
}
q->setStatus(appletStatus);
}
void ContainmentPrivate::triggerShowAddWidgets()
{
emit q->showAddWidgetsInterface(QPointF());
}
void ContainmentPrivate::containmentConstraintsEvent(Plasma::Constraints constraints)
{
if (!q->isContainment()) {
return;
}
//kDebug() << "got containmentConstraintsEvent" << constraints << (QObject*)toolBox;
if (constraints & Plasma::ImmutableConstraint) {
//update actions
checkRemoveAction();
const bool unlocked = q->immutability() == Mutable;
q->enableAction("add widgets", unlocked);
// tell the applets too
foreach (Applet *a, applets) {
a->setImmutability(q->immutability());
a->updateConstraints(ImmutableConstraint);
}
}
// pass on the constraints that are relevant here
Constraints appletConstraints = NoConstraint;
if (constraints & FormFactorConstraint) {
appletConstraints |= FormFactorConstraint;
}
if (constraints & ScreenConstraint) {
appletConstraints |= ScreenConstraint;
}
if (appletConstraints != NoConstraint) {
foreach (Applet *applet, applets) {
applet->updateConstraints(appletConstraints);
}
}
if (constraints & Plasma::StartupCompletedConstraint && type < Containment::CustomContainment) {
q->addToolBoxAction(q->action("remove"));
checkRemoveAction();
}
}
Applet *ContainmentPrivate::addApplet(const QString &name, const QVariantList &args,
const QRectF &appletGeometry, uint id, bool delayInit)
{
if (!q->isContainment()) {
return 0;
}
if (!delayInit && q->immutability() != Mutable) {
#ifndef NDEBUG
kDebug() << "addApplet for" << name << "requested, but we're currently immutable!";
#endif
return 0;
}
Applet *applet = PluginLoader::self()->loadApplet(name, id, args);
if (!applet) {
#ifndef NDEBUG
kDebug() << "Applet" << name << "could not be loaded.";
#endif
applet = new Applet(0, QString(), id);
applet->setFailedToLaunch(true, i18n("Could not find requested component: %1", name));
}
//kDebug() << applet->name() << "sizehint:" << applet->sizeHint() << "geometry:" << applet->geometry();
q->addApplet(applet, appletGeometry.topLeft(), delayInit);
return applet;
}
void ContainmentPrivate::appletDeleted(Plasma::Applet *applet)
{
applets.removeAll(applet);
emit q->appletRemoved(applet);
emit q->configNeedsSaving();
}
void ContainmentPrivate::appletAppeared(Applet *applet)
{
//kDebug() << type << Containment::DesktopContainment;
KConfigGroup *cg = applet->d->mainConfigGroup();
applet->save(*cg);
emit q->configNeedsSaving();
}
bool ContainmentPrivate::isPanelContainment() const
{
return type == Containment::PanelContainment || type == Containment::CustomPanelContainment;
}
bool ContainmentPrivate::prepareContainmentActions(const QString &trigger, const QPoint &screenPos, KMenu *menu)
{
ContainmentActions *plugin = actionPlugins()->value(trigger);
if (!plugin) {
return false;
}
if (plugin->containment() != q) {
plugin->setContainment(q);
// now configure it
KConfigGroup cfg = q->containmentActionsConfig();
KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
plugin->restore(pluginConfig);
}
if (plugin->configurationRequired()) {
KMenu *localMenu = menu ? menu : new KMenu();
localMenu->addTitle(i18n("This plugin needs to be configured"));
localMenu->addAction(q->action("configure"));
if (!menu) {
localMenu->exec(screenPos);
delete localMenu;
}
return false;
} else if (menu) {
QList<QAction*> actions = plugin->contextualActions();
if (actions.isEmpty()) {
//it probably didn't bother implementing the function. give the user a chance to set
//a better plugin. note that if the user sets no-plugin this won't happen...
if (!isPanelContainment() && q->action("configure")) {
menu->addAction(q->action("configure"));
}
} else {
menu->addActions(actions);
}
}
return true;
}
QHash<QString, ContainmentActions*> * ContainmentPrivate::actionPlugins()
{
switch (containmentActionsSource) {
case Activity:
//FIXME
case Local:
return &localActionPlugins;
default:
return &globalActionPlugins;
}
}
}

View File

@ -0,0 +1,155 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef CONTAINMENT_P_H
#define CONTAINMENT_P_H
#include <kactioncollection.h>
#include <kmenu.h>
#include "plasma.h"
#include "applet.h"
#include "corona.h"
static const int INTER_CONTAINMENT_MARGIN = 6;
static const int CONTAINMENT_COLUMNS = 2;
static const int VERTICAL_STACKING_OFFSET = 10000;
class KJob;
namespace KIO
{
class Job;
}
namespace Plasma
{
class AccessAppletJob;
class Containment;
class ContainmentPrivate
{
public:
ContainmentPrivate(Containment *c)
: q(c),
formFactor(Planar),
location(Floating),
screen(-1), // no screen
lastScreen(-1),
desktop(-1), // all desktops
lastDesktop(-1),
type(Containment::NoContainmentType),
drawWallpaper(true),
containmentActionsSource(Global)
{
}
~ContainmentPrivate()
{
// qDeleteAll is broken with Qt4.8, delete it by hand
while (!applets.isEmpty()) {
delete applets.first();
}
applets.clear();
}
void triggerShowAddWidgets();
void requestConfiguration();
void checkStatus(Plasma::ItemStatus status);
void setScreen(int newScreen, int newDesktop, bool preventInvalidDesktops = true);
/**
* Called when constraints have been updated on this containment to provide
* constraint services common to all containments. Containments should still
* implement their own constraintsEvent method
*/
void containmentConstraintsEvent(Plasma::Constraints constraints);
void initApplets();
void checkContainmentFurniture();
bool isPanelContainment() const;
void setLockToolText();
void appletDeleted(Applet*);
void appletAppeared(Applet*);
void addContainmentActions(KMenu &desktopMenu, QEvent *event);
void addAppletActions(KMenu &desktopMenu, Applet *applet, QEvent *event);
void checkRemoveAction();
void configChanged();
Applet *addApplet(const QString &name, const QVariantList &args = QVariantList(),
const QRectF &geometry = QRectF(-1, -1, -1, -1), uint id = 0,
bool delayedInit = false);
KActionCollection *actions();
/**
* add the regular actions & keyboard shortcuts onto Applet's collection
*/
static void addDefaultActions(KActionCollection *actions, Containment *c = 0);
/**
* inits the containmentactions if necessary
* if it needs configuring, this warns the user and returns false
* if a menu is passed in, then it populates that menu with the actions from the plugin
* @param trigger the string to identify the correct plugin with
* @param screenPos used to show the configure menu, only used if no menu is passed in
* @param menu an optional menu to use to populate with actions, instead of triggering the
* action directly
* @return true if it's ok to run the action
*/
bool prepareContainmentActions(const QString &trigger, const QPoint &screenPos, KMenu *menu = 0);
QHash<QString, ContainmentActions*> *actionPlugins();
static bool s_positioningPanels;
Containment *q;
FormFactor formFactor;
Location location;
Applet::List applets;
QString wallpaper;
QString wallpaperMode;
QHash<QString, ContainmentActions*> localActionPlugins;
int screen;
int lastScreen;
int desktop;
int lastDesktop;
QList<QAction *> toolBoxActions;
QString activityId;
Containment::Type type;
bool drawWallpaper : 1;
enum ContainmentActionsSource {
Global = 0,
Activity,
Local
};
ContainmentActionsSource containmentActionsSource;
static QHash<QString, ContainmentActions*> globalActionPlugins;
static const char defaultWallpaper[];
static const char defaultWallpaperMode[];
};
} // Plasma namespace
#endif

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CONTAINMENTACTIONSPRIVATE_H
#define PLASMA_CONTAINMENTACTIONSPRIVATE_H
#include "dataengineconsumer.h"
namespace Plasma
{
class ContainmentActionsPrivate : public DataEngineConsumer
{
public:
ContainmentActionsPrivate(KService::Ptr service, ContainmentActions *containmentActions) :
q(containmentActions),
containmentActionsDescription(service),
package(0),
containment(0),
needsConfig(false)
{
};
ContainmentActions *q;
KPluginInfo containmentActionsDescription;
Package *package;
KServiceAction mode;
Containment *containment;
bool needsConfig;
};
} // namespace Plasma
#endif //PLASMA_CONTAINMENTACTIONSPRIVATE_H

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CONTAINMENTACTIONSPLUGINSCONFIGPRIVATE_H
#define PLASMA_CONTAINMENTACTIONSPLUGINSCONFIGPRIVATE_H
#include <QHash>
namespace Plasma
{
class ContainmentActionsPluginsConfigPrivate
{
public:
ContainmentActionsPluginsConfigPrivate(ContainmentActionsPluginsConfig *config)
: q(config)
{
}
~ContainmentActionsPluginsConfigPrivate()
{
}
ContainmentActionsPluginsConfig *q;
//map trigger -> pluginname
QHash<QString, QString> plugins;
};
} // namespace Plasma
#endif

76
plasma/private/corona_p.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright 2007-2011 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_CORONA_P_H
#define PLASMA_CORONA_P_H
#include <QTimer>
#include <kactioncollection.h>
class KShortcutsDialog;
class QGraphicsWidget;
namespace Plasma
{
class Containment;
class CoronaPrivate
{
public:
CoronaPrivate(Corona *corona);
~CoronaPrivate();
void init();
void showShortcutConfig();
void toggleImmutability();
void saveLayout(KSharedConfigPtr cg) const;
void updateContainmentImmutability();
void containmentDestroyed(QObject *obj);
void syncConfig();
Containment *addContainment(const QString &name, const QVariantList &args, uint id);
void delayedContainmentInit();
void offscreenWidgetDestroyed(QObject *);
QList<Plasma::Containment *> importLayout(const KConfigGroup &conf, bool mergeConfig);
static bool s_positioningContainments;
Corona *q;
ImmutabilityType immutability;
QString mimetype;
QString configName;
QString defaultContainmentPlugin;
KSharedConfigPtr config;
QTimer *configSyncTimer;
QTimer *delayedInitTimer;
QList<Containment*> containments;
QList<QWeakPointer<Containment> > containmentsNeedingInit;
QHash<uint, QGraphicsWidget*> offscreenWidgets;
KActionCollection actions;
QMap<Containment::Type, ContainmentActionsPluginsConfig> containmentActionsDefaults;
QWeakPointer<KShortcutsDialog> shortcutsDlg;
QWeakPointer<AbstractDialogManager> dialogManager;
QHash<Containment::Type, QString> toolBoxPlugins;
QList<QWeakPointer<KActionCollection> > actionCollections;
};
}
#endif

View File

@ -0,0 +1,171 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "datacontainer.h" //krazy:exclude=includes
#include "datacontainer_p.h" //krazy:exclude=includes
namespace Plasma
{
SignalRelay *DataContainerPrivate::signalRelay(const DataContainer *dc, QObject *visualization,
uint pollingInterval,
Plasma::IntervalAlignment align,
bool immediateUpdate)
{
QMap<uint, SignalRelay *>::const_iterator relayIt = relays.constFind(pollingInterval);
SignalRelay *relay = 0;
//FIXME what if we have two applets with the same interval and different alignment?
if (relayIt == relays.constEnd()) {
relay = new SignalRelay(const_cast<DataContainer*>(dc), this,
pollingInterval, align, immediateUpdate);
relays[pollingInterval] = relay;
} else {
relay = relayIt.value();
}
relayObjects[visualization] = relay;
return relay;
}
bool DataContainerPrivate::hasUpdates()
{
if (cached) {
// SignalRelay needs us to pretend we did an update
cached = false;
return true;
}
return dirty;
}
SignalRelay::SignalRelay(DataContainer *parent, DataContainerPrivate *data, uint ival,
Plasma::IntervalAlignment align, bool immediateUpdate)
: QObject(parent),
dc(parent),
d(data),
m_interval(ival),
m_align(align),
m_resetTimer(true),
m_queued(true)
{
//kDebug() << "signal relay with time of" << m_timerId << "being set up";
m_timerId = startTimer(immediateUpdate ? 0 : m_interval);
if (m_align != Plasma::NoAlignment) {
checkAlignment();
}
}
int SignalRelay::receiverCount() const
{
return receivers(SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)));
}
bool SignalRelay::isUnused() const
{
return receivers(SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data))) < 1;
}
void SignalRelay::checkAlignment()
{
int newTime = 0;
QTime t = QTime::currentTime();
if (m_align == Plasma::AlignToMinute) {
int seconds = t.second();
if (seconds > 2) {
newTime = ((60 - seconds) * 1000) + 500;
}
} else if (m_align == Plasma::AlignToHour) {
int minutes = t.minute();
int seconds = t.second();
if (minutes > 1 || seconds > 10) {
newTime = ((60 - minutes) * 1000 * 60) +
((60 - seconds) * 1000) + 500;
}
}
if (newTime) {
killTimer(m_timerId);
m_timerId = startTimer(newTime);
m_resetTimer = true;
}
}
void SignalRelay::checkQueueing()
{
//kDebug() << m_queued;
if (m_queued) {
emit dataUpdated(dc->objectName(), d->data);
m_queued = false;
//TODO: should we re-align our timer at this point, to avoid
// constant queueing due to more-or-less constant time
// async update time? this might make sense for
// staggered accesses to the same source by multiple
// visualizations causing a minimumPollingInterval violation.
// it may not make sense for purely async-and-takes-a-while
// type operations (e.g. network fetching).
// we need more real world data before making such a change
// change
//
// killTimer(m_timerId);
// m_timerId = startTime(m_interval);
}
}
void SignalRelay::forceImmediateUpdate()
{
emit dataUpdated(dc->objectName(), d->data);
}
void SignalRelay::timerEvent(QTimerEvent *event)
{
if (event->timerId() != m_timerId) {
QObject::timerEvent(event);
return;
}
if (m_resetTimer) {
killTimer(m_timerId);
m_timerId = startTimer(m_interval);
m_resetTimer = false;
}
if (m_align != Plasma::NoAlignment) {
checkAlignment();
}
emit dc->updateRequested(dc);
if (d->hasUpdates()) {
//kDebug() << "emitting data updated directly" << d->data;
emit dataUpdated(dc->objectName(), d->data);
m_queued = false;
} else {
// the source wasn't actually updated; so let's put ourselves in the queue
// so we get a dataUpdated() call when the data does arrive
//kDebug() << "queued";
m_queued = true;
}
}
} // Plasma namespace
#include "moc_datacontainer_p.cpp"

View File

@ -0,0 +1,130 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DATACONTAINER_P_H
#define PLASMA_DATACONTAINER_P_H
#include "servicejob.h"
#include "storage_p.h"
#include <QtCore/QTimerEvent>
#include <QtCore/QTime>
#include <QtCore/QBasicTimer>
class QTimer;
namespace Plasma
{
class ServiceJob;
class SignalRelay;
class DataContainerPrivate
{
public:
DataContainerPrivate(DataContainer *container)
: q(container),
storage(NULL),
storageCount(0),
dirty(false),
cached(false),
enableStorage(false),
isStored(true)
{
}
/**
* Check if the DataContainer is still in use.
*
* If not the signal "becameUnused" will be emitted.
*
* Warning: The DataContainer may be invalid after calling this function, because a listener
* to becameUnused() may have deleted it.
**/
void checkUsage();
SignalRelay *signalRelay(const DataContainer *dc, QObject *visualization,
uint pollingInterval, Plasma::IntervalAlignment align,
bool immediateUpdate);
bool hasUpdates();
/**
* Deletes the store member of DataContainerPrivate if
* there are no more references to it.
*/
void storeJobFinished(KJob *job);
/**
* Does the work of putting the data from disk into the DataContainer
* after retrieve() sets it up.
*/
void populateFromStoredData(KJob *job);
void store();
void retrieve();
DataContainer *q;
DataEngine::Data data;
QMap<QObject *, SignalRelay *> relayObjects;
QMap<uint, SignalRelay *> relays;
QTime updateTs;
Storage* storage;
QBasicTimer storageTimer;
QBasicTimer checkUsageTimer;
int storageCount;
bool dirty : 1;
bool cached : 1;
bool enableStorage : 1;
bool isStored : 1;
};
class SignalRelay : public QObject
{
Q_OBJECT
public:
SignalRelay(DataContainer *parent, DataContainerPrivate *data,
uint ival, Plasma::IntervalAlignment align, bool immediateUpdate);
int receiverCount() const;
bool isUnused() const;
void checkAlignment();
void checkQueueing();
void forceImmediateUpdate();
DataContainer *dc;
DataContainerPrivate *d;
uint m_interval;
Plasma::IntervalAlignment m_align;
int m_timerId;
bool m_resetTimer;
bool m_queued;
signals:
void dataUpdated(const QString &, const Plasma::DataEngine::Data &);
protected:
void timerEvent(QTimerEvent *event);
};
} // Plasma namespace
#endif // multiple inclusion guard

View File

@ -0,0 +1,122 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DATAENGINE_P_H
#define DATAENGINE_P_H
#include <QTime>
#include <kplugininfo.h>
class QTime;
namespace Plasma
{
class Service;
class DataEnginePrivate
{
public:
DataEnginePrivate(DataEngine *e, const KPluginInfo &info);
~DataEnginePrivate();
DataContainer *source(const QString &sourceName, bool createWhenMissing = true);
void connectSource(DataContainer *s, QObject *visualization, uint pollingInterval,
Plasma::IntervalAlignment align, bool immediateCall = true);
DataContainer *requestSource(const QString &sourceName, bool *newSource = 0);
void internalUpdateSource(DataContainer*);
void setupScriptSupport();
/**
* Reference counting method. Calling this method increases the count
* by one.
**/
void ref();
/**
* Reference counting method. Calling this method decreases the count
* by one.
**/
void deref();
/**
* Reference counting method. Used to determine if this DataEngine is
* used.
* @return true if the reference count is non-zero
**/
bool isUsed() const;
/**
* @param methods ways to announce this engine on the network.
*/
void publish(AnnouncementMethods methods, const QString &name);
/**
* remove this engine from the network.
*/
void unpublish(const QString &name = QString());
/**
* @return whether or not this engine is published.
*/
bool isPublished() const;
/**
* a datacontainer has been destroyed, clean up stuff
*/
void sourceDestroyed(QObject *object);
/**
* stores the source
* @param sourceName the name of the source to store
*/
void storeSource(DataContainer *source) const;
/**
* stores all sources marked for storage
*/
void storeAllSources();
/**
* retrieves source data
* @param the data container to populate
*/
void retrieveStoredData(DataContainer *s);
DataEngine *q;
KPluginInfo dataEngineDescription;
int refCount;
int checkSourcesTimerId;
int updateTimerId;
int minPollingInterval;
QTime updateTimestamp;
DataEngine::SourceDict sources;
QString icon;
bool valid;
DataEngineScript *script;
QString engineName;
QString serviceName;
Package *package;
Service *publishedService;
QString waitingSourceRequest;
};
} // Plasma namespace
#endif // multiple inclusion guard

View File

@ -0,0 +1,56 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DATAENGINECONSUMER_P_H
#define PLASMA_DATAENGINECONSUMER_P_H
#include <QMap>
#include <QSet>
#include <QUrl>
namespace Plasma
{
class DataEngineConsumer;
class RemoteDataEngine;
class Service;
class ServiceMonitor;
class ServiceJob;
class DataEngineConsumerPrivate : public QObject
{
Q_OBJECT
public:
QSet<QString> loadedEngines;
QMap<QPair<QString, QString>, RemoteDataEngine*> remoteEngines;
QMap<Service*, QString> engineNameForService;
DataEngine *remoteDataEngine(const QString &name, const QUrl &location);
public Q_SLOTS:
void slotJobFinished(Plasma::ServiceJob *job);
void slotServiceReady(Plasma::Service *service);
};
} // namespace Plasma
#endif

View File

@ -0,0 +1,213 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "dataenginemanager_p.h"
#include <QFile>
#include <QTextStream>
#include <kdebug.h>
#include <klocale.h>
#include <kservicetypetrader.h>
#include <qstandardpaths.h>
#include "datacontainer.h"
#include "pluginloader.h"
#include "private/componentinstaller_p.h"
#include "private/dataengine_p.h"
#include "private/datacontainer_p.h"
#include "scripting/scriptengine.h"
namespace Plasma
{
class NullEngine : public DataEngine
{
public:
NullEngine(QObject *parent = 0)
: DataEngine(parent)
{
setValid(false);
// ref() ourselves to ensure we never get deleted
d->ref();
}
};
class DataEngineManagerPrivate
{
public:
DataEngineManagerPrivate()
: nullEng(0)
{}
~DataEngineManagerPrivate()
{
foreach (Plasma::DataEngine *engine, engines) {
delete engine;
}
engines.clear();
delete nullEng;
}
DataEngine *nullEngine()
{
if (!nullEng) {
nullEng = new NullEngine;
}
return nullEng;
}
DataEngine::Dict engines;
DataEngine *nullEng;
};
class DataEngineManagerSingleton
{
public:
DataEngineManager self;
};
Q_GLOBAL_STATIC(DataEngineManagerSingleton, privateDataEngineManagerSelf)
DataEngineManager *DataEngineManager::self()
{
return &privateDataEngineManagerSelf()->self;
}
DataEngineManager::DataEngineManager()
: d(new DataEngineManagerPrivate)
{
//startTimer(30000);
}
DataEngineManager::~DataEngineManager()
{
delete d;
}
Plasma::DataEngine *DataEngineManager::engine(const QString &name) const
{
if (name.isEmpty()) {
return d->nullEngine();
}
Plasma::DataEngine::Dict::const_iterator it = d->engines.constFind(name);
if (it != d->engines.constEnd()) {
// ref and return the engine
//Plasma::DataEngine *engine = *it;
return *it;
}
return d->nullEngine();
}
Plasma::DataEngine *DataEngineManager::loadEngine(const QString &name)
{
Plasma::DataEngine::Dict::const_iterator it = d->engines.constFind(name);
if (it != d->engines.constEnd()) {
DataEngine *engine = *it;
engine->d->ref();
return engine;
}
DataEngine *engine = PluginLoader::self()->loadDataEngine(name);
if (!engine) {
// Try installing the engine. However, it's too late for this request.
ComponentInstaller::self()->installMissingComponent("dataengine", name);
return d->nullEngine();
}
engine->init();
d->engines[name] = engine;
return engine;
}
void DataEngineManager::unloadEngine(const QString &name)
{
Plasma::DataEngine::Dict::iterator it = d->engines.find(name);
if (it != d->engines.end()) {
Plasma::DataEngine *engine = *it;
engine->d->deref();
if (!engine->d->isUsed()) {
d->engines.erase(it);
delete engine;
}
}
}
void DataEngineManager::timerEvent(QTimerEvent *)
{
#ifndef NDEBUG
QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + "plasma_dataenginemanager_log";
QFile f(path);
if (!f.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
kDebug() << "faild to open" << path;
return;
}
QTextStream out(&f);
QHashIterator<QString, DataEngine*> it(d->engines);
out << "================================== " << KLocale::global()->formatDateTime(QDateTime::currentDateTime()) << endl;
while (it.hasNext()) {
it.next();
DataEngine *engine = it.value();
out << "DataEngine: " << it.key() << ' ' << engine << endl;
out << " Claimed # of sources: " << engine->sources().count() << endl;
out << " Actual # of sources: " << engine->containerDict().count() << endl;
out << endl << " Source Details" << endl;
foreach (DataContainer *dc, engine->containerDict()) {
out << " * " << dc->objectName() << endl;
out << " Data count: " << dc->d->data.count() << endl;
out << " Stored: " << dc->isStorageEnabled() << ' ' << endl;
const int directs = dc->receivers(SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)));
if (directs > 0) {
out << " Direction Connections: " << directs << ' ' << endl;
}
const int relays = dc->d->relays.count();
if (relays > 0) {
out << " Relays: " << dc->d->relays.count() << endl;
QString times;
foreach (SignalRelay *relay, dc->d->relays) {
times.append(' ').append(QString::number(relay->m_interval));
}
out << " Relay Timeouts: " << times << ' ' << endl;
}
}
out << endl << "-----" << endl;
}
out << endl << endl;
#endif
// killTimer(event->timerId());
}
} // namespace Plasma
#include "moc_dataenginemanager_p.cpp"

View File

@ -0,0 +1,99 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DATAENGINEMANAGER_H
#define PLASMA_DATAENGINEMANAGER_H
#include <QtCore/QHash>
#include <kplugininfo.h>
#include <plasma/dataengine.h>
namespace Plasma
{
class DataEngineManagerPrivate;
/**
* @class DataEngineManager plasma/dataenginemanager.h <Plasma/DataEngineManager>
*
* @short DataEngine loader and life time manager
*
* Plasma::DataEngineManager provides facilities for listing, loading and
* according to reference count unloading of DataEngines.
**/
class PLASMA_EXPORT DataEngineManager: public QObject
{
Q_OBJECT
public:
/**
* Singleton pattern accessor.
*/
static DataEngineManager *self();
/**
* Returns a data engine object if one is loaded and available.
* On failure, the fallback NullEngine (which does nothing and
* !isValid()) is returned.
*
* @param name the name of the engine
*/
Plasma::DataEngine *engine(const QString &name) const;
/**
* Loads a data engine and increases the reference count on it.
* This should be called once per object (or set of objects) using the
* DataEngine. Afterwards, dataEngine should be used or the return
* value cached. Call unloadDataEngine when finished with the engine.
*
* @param name the name of the engine
* @return the data engine that was loaded, or the NullEngine on failure.
*/
Plasma::DataEngine *loadEngine(const QString &name);
/**
* Decreases the reference count on the engine. If the count reaches
* zero, then the engine is deleted to save resources.
*/
void unloadEngine(const QString &name);
protected:
/**
* Reimplemented from QObject
**/
void timerEvent(QTimerEvent *event);
private:
/**
* Default constructor. The singleton method self() is the
* preferred access mechanism.
*/
DataEngineManager();
~DataEngineManager();
DataEngineManagerPrivate *const d;
friend class DataEngineManagerSingleton;
};
} // namespace Plasma
#endif // multiple inclusion guard

View File

@ -0,0 +1,59 @@
/*
* Copyright © 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This program 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "dataengineservice_p.h"
#include "../dataengine.h"
#include "getsource_p.h"
#include <kdebug.h>
namespace Plasma
{
DataEngineService::DataEngineService(DataEngine *engine)
: Plasma::Service(engine),
m_engine(engine)
{
setName("dataengineservice");
engine->connectAllSources(this, 1000);
connect(engine, SIGNAL(sourceAdded(QString)), this, SLOT(sourceAdded(QString)));
}
Plasma::ServiceJob* DataEngineService::createJob(const QString& operation, QHash<QString,QVariant>& parameters)
{
return new GetSource(m_engine, operation, parameters, this);
}
void DataEngineService::dataUpdated(QString source, Plasma::DataEngine::Data data)
{
if (data != m_data[source]) {
m_data[source] = data;
m_peersAlreadyUpdated[source] = QStringList();
}
}
void DataEngineService::sourceAdded(QString source)
{
m_engine->connectSource(source, this, 1000);
}
}
#include "moc_dataengineservice_p.cpp"

View File

@ -0,0 +1,60 @@
/*
* Copyright © 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This program 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_DATAENGINESERVICE_P_H
#define PLASMA_DATAENGINESERVICE_P_H
#include <QStringList>
#include "../dataengine.h"
#include "../service.h"
namespace Plasma
{
class DataEngine;
class GetSource;
class DataEngineService : public Plasma::Service
{
Q_OBJECT
public:
DataEngineService(DataEngine *engine);
public Q_SLOTS:
void dataUpdated(QString source, Plasma::DataEngine::Data data);
protected:
Plasma::ServiceJob* createJob(const QString& operation,
QHash<QString,QVariant>& parameters);
private Q_SLOTS:
void sourceAdded(QString source);
private:
DataEngine *m_engine;
QHash<QString, QStringList> m_peersAlreadyUpdated;
QHash<QString, DataEngine::Data> m_data;
friend class GetSource;
};
}
#endif // PLASMA_DATAENGINESERVICE_P_H

View File

@ -0,0 +1,66 @@
/*
* Copyright 2007 Richard J. Moore <rich@kde.org>
*
* This program 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "dataenginebindings_p.h"
typedef Plasma::Service *ServicePtr;
QScriptValue qScriptValueFromService(QScriptEngine *engine, const ServicePtr &service)
{
return engine->newQObject(const_cast<Plasma::Service *>(service), QScriptEngine::AutoOwnership, QScriptEngine::PreferExistingWrapperObject);
}
void serviceFromQScriptValue(const QScriptValue &scriptValue, ServicePtr &service)
{
QObject *obj = scriptValue.toQObject();
service = static_cast<Plasma::Service *>(obj);
}
typedef Plasma::DataEngine *DataEnginePtr;
QScriptValue qScriptValueFromDataEngine(QScriptEngine *engine, const DataEnginePtr &dataEngine)
{
return engine->newQObject(const_cast<Plasma::DataEngine *>(dataEngine), QScriptEngine::AutoOwnership, QScriptEngine::PreferExistingWrapperObject);
}
void dataEngineFromQScriptValue(const QScriptValue &scriptValue, DataEnginePtr &dataEngine)
{
QObject *obj = scriptValue.toQObject();
dataEngine = static_cast<Plasma::DataEngine *>(obj);
}
typedef Plasma::ServiceJob *ServiceJobPtr;
QScriptValue qScriptValueFromServiceJob(QScriptEngine *engine, const ServiceJobPtr &serviceJob)
{
return engine->newQObject(const_cast<Plasma::ServiceJob *>(serviceJob), QScriptEngine::AutoOwnership, QScriptEngine::PreferExistingWrapperObject);
}
void serviceJobFromQScriptValue(const QScriptValue &scriptValue, ServiceJobPtr &serviceJob)
{
QObject *obj = scriptValue.toQObject();
serviceJob = static_cast<Plasma::ServiceJob *>(obj);
}
void registerDataEngineMetaTypes(QScriptEngine *engine)
{
qRegisterMetaType<Plasma::DataEngine::Data>("Plasma::DataEngine::Data");
qRegisterMetaType<Plasma::DataEngine::Data>("DataEngine::Data");
qScriptRegisterMapMetaType<Plasma::DataEngine::Data>(engine);
qScriptRegisterMetaType<Plasma::Service *>(engine, qScriptValueFromService, serviceFromQScriptValue);
qScriptRegisterMetaType<Plasma::DataEngine *>(engine, qScriptValueFromDataEngine, dataEngineFromQScriptValue);
qScriptRegisterMetaType<Plasma::ServiceJob *>(engine, qScriptValueFromServiceJob, serviceJobFromQScriptValue);
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2007 Richard J. Moore <rich@kde.org>
*
* This program 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DATAENGINE_H
#define DATAENGINE_H
#include <QScriptEngine>
#include <QScriptValue>
#include <QScriptValueIterator>
#include <kdebug.h>
#include <dataengine.h>
#include <service.h>
#include <servicejob.h>
using namespace Plasma;
Q_DECLARE_METATYPE(DataEngine::Dict)
Q_DECLARE_METATYPE(DataEngine::Data)
template <class M>
QScriptValue qScriptValueFromMap(QScriptEngine *eng, const M &map)
{
//kDebug() << "qScriptValueFromMap called";
QScriptValue obj = eng->newObject();
typename M::const_iterator begin = map.constBegin();
typename M::const_iterator end = map.constEnd();
typename M::const_iterator it;
for (it = begin; it != end; ++it) {
if (it.value().type() == QVariant::Hash) {
obj.setProperty(it.key(), qScriptValueFromMap(eng, it.value().toHash()));
} else if (it.value().type() == QVariant::Map) {
obj.setProperty(it.key(), qScriptValueFromMap(eng, it.value().toMap()));
} else {
obj.setProperty(it.key(), qScriptValueFromValue(eng, it.value()));
}
}
return obj;
}
template <class M>
void qScriptValueToMap(const QScriptValue &value, M &map)
{
//kDebug() << "qScriptValueToMap called";
QScriptValueIterator it(value);
while (it.hasNext()) {
it.next();
map[it.name()] = qscriptvalue_cast<typename M::mapped_type>(it.value());
}
}
template<typename T>
int qScriptRegisterMapMetaType(
QScriptEngine *engine,
const QScriptValue &prototype = QScriptValue()
#ifndef qdoc
, T * /* dummy */ = 0
#endif
)
{
return qScriptRegisterMetaType<T>(engine, qScriptValueFromMap, qScriptValueToMap, prototype);
}
void registerDataEngineMetaTypes(QScriptEngine *engine);
#endif // DATAENGINE_H

View File

@ -0,0 +1,39 @@
/*
* Copyright 2010 Marco Martin <notmart@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "declarativenetworkaccessmanagerfactory_p.h"
#include "config-plasma.h"
#if !PLASMA_NO_KIO
#include <kio/accessmanager.h>
#else
#include <QtNetwork/QNetworkAccessManager>
#endif
QNetworkAccessManager *DeclarativeNetworkAccessManagerFactory::create(QObject *parent)
{
#if !PLASMA_NO_KIO
return new KIO::AccessManager(parent);
#else
return new QNetworkAccessManager(parent);
#endif
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2010 Marco Martin <notmart@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DECLARATIVENETWORKACCESSMANAGERFACTORY_H
#define DECLARATIVENETWORKACCESSMANAGERFACTORY_H
#include <QDeclarativeNetworkAccessManagerFactory>
class DeclarativeNetworkAccessManagerFactory : public QDeclarativeNetworkAccessManagerFactory
{
public:
QNetworkAccessManager *create(QObject *parent);
};
#endif

View File

@ -0,0 +1,154 @@
#ifndef BLUR_CPP
#define BLUR_CPP
/*
* Copyright 2007 Jani Huhtanen <jani.huhtanen@tut.fi>
*
* This program 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <cmath>
// Exponential blur, Jani Huhtanen, 2006
//
template<int aprec, int zprec>
static inline void blurinner(unsigned char *bptr, int &zR, int &zG, int &zB, int &zA, int alpha);
template<int aprec,int zprec>
static inline void blurrow(QImage &im, int line, int alpha);
template<int aprec, int zprec>
static inline void blurcol(QImage &im, int col, int alpha);
/*
* expblur(QImage &img, int radius)
*
* In-place blur of image 'img' with kernel
* of approximate radius 'radius'.
*
* Blurs with two sided exponential impulse
* response.
*
* aprec = precision of alpha parameter
* in fixed-point format 0.aprec
*
* zprec = precision of state parameters
* zR,zG,zB and zA in fp format 8.zprec
*/
template<int aprec,int zprec>
void expblur(QImage &img, int radius)
{
if (radius < 1) {
return;
}
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
/* Calculate the alpha such that 90% of
the kernel is within the radius.
(Kernel extends to infinity)
*/
int alpha = (int)((1 << aprec) * (1.0f - std::exp(-2.3f / (radius + 1.f))));
int height = img.height();
int width = img.width();
for (int row=0; row<height; row++) {
blurrow<aprec,zprec>(img, row, alpha);
}
for (int col=0; col<width; col++) {
blurcol<aprec,zprec>(img, col, alpha);
}
return;
}
template<int aprec, int zprec>
static inline void blurinner(unsigned char *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
{
int R, G, B, A;
R = *bptr;
G = *(bptr + 1);
B = *(bptr + 2);
A = *(bptr + 3);
zR += (alpha * ((R << zprec) - zR)) >> aprec;
zG += (alpha * ((G << zprec) - zG)) >> aprec;
zB += (alpha * ((B << zprec) - zB)) >> aprec;
zA += (alpha * ((A << zprec) - zA)) >> aprec;
*bptr = zR >> zprec;
*(bptr+1) = zG >> zprec;
*(bptr+2) = zB >> zprec;
*(bptr+3) = zA >> zprec;
}
template<int aprec,int zprec>
static inline void blurrow(QImage &im, int line, int alpha)
{
int zR, zG, zB, zA;
QRgb *ptr = (QRgb *)im.scanLine(line);
int width = im.width();
zR = *((unsigned char *)ptr ) << zprec;
zG = *((unsigned char *)ptr + 1) << zprec;
zB = *((unsigned char *)ptr + 2) << zprec;
zA = *((unsigned char *)ptr + 3) << zprec;
for (int index=1; index<width; index++) {
blurinner<aprec,zprec>((unsigned char *)&ptr[index],zR,zG,zB,zA,alpha);
}
for (int index=width-2; index>=0; index--) {
blurinner<aprec,zprec>((unsigned char *)&ptr[index],zR,zG,zB,zA,alpha);
}
}
template<int aprec, int zprec>
static inline void blurcol(QImage &im, int col, int alpha)
{
int zR, zG, zB, zA;
QRgb *ptr = (QRgb *)im.bits();
ptr += col;
int height = im.height();
int width = im.width();
zR = *((unsigned char *)ptr ) << zprec;
zG = *((unsigned char *)ptr + 1) << zprec;
zB = *((unsigned char *)ptr + 2) << zprec;
zA = *((unsigned char *)ptr + 3) << zprec;
for (int index=width; index<(height-1)*width; index+=width) {
blurinner<aprec,zprec>((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
}
for (int index=(height-2)*width; index>=0; index-=width) {
blurinner<aprec,zprec>((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
}
}
template<class T>
inline const T &qClamp(const T &x, const T &low, const T &high)
{
if (x < low) {
return low;
} else if (x > high) {
return high;
} else {
return x;
}
}
#endif

View File

@ -0,0 +1,250 @@
/*
* Copyright © 2009 Fredrik Höglund <fredrik@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 "halopainter_p.h"
#include <QPainter>
#include <cmath>
namespace Plasma
{
static inline qreal gaussian(qreal x, qreal sigma)
{
return (1.0 / std::sqrt(2.0 * M_PI) * sigma)
* std::exp(-((x * x) / (2.0 * sigma * sigma)));
}
static void gaussianBlur(QImage &image, int radius)
{
// The gaussian curve is effectively zero after 3 standard deviations.
qreal sigma = radius / 3.;
int size = radius * 2 + 1;
int center = size / 2;
qreal *kernel = new qreal[size];
qreal total = 0;
// Generate the gaussian kernel
for (int i = 0; i < size; i++) {
kernel[i] = gaussian(i - center, sigma);
total += kernel[i];
}
// Normalize the kernel
for (int i = 0; i < size; i++)
kernel[i] = kernel[i] / total;
quint32 *buf = new quint32[image.width() * image.height()];
memset(buf, 0, image.width() * image.height() * sizeof(quint32));
// Blur the image horizontally
for (int y = 0; y < image.height(); y++)
{
quint32 *src = (quint32*)image.scanLine(y);
quint32 *dst = buf + image.width() * y;
for (int x = 0, start = center; x < center; x++, start--) {
double a = 0;
for (int i = start; i < size; i++)
a += qAlpha(src[x - center + i]) * kernel[i];
dst[x] = qRound(a) << 24;
}
for (int x = center; x < image.width() - center; x++) {
double a = 0;
for (int i = 0; i < size; i++)
a += qAlpha(src[x - center + i]) * kernel[i];
dst[x] = qRound(a) << 24;
}
for (int x = image.width() - center, stop = size - 1; x < image.width(); x++, stop--) {
double a = 0;
for (int i = 0; i < stop; i++)
a += qAlpha(src[x - center + i]) * kernel[i];
dst[x] = qRound(a) << 24;
}
}
// Blur the image vertically
quint32 *src = buf;
quint32 *dst = (quint32*)image.bits();
for (int x = 0; x < image.width(); x++)
{
int di = x;
for (int y = 0, start = center; y < center; y++, start--) {
double a = 0;
int si = (y - center + start) * image.width() + x;
for (int i = start; i < size; i++) {
a += qAlpha(src[si]) * kernel[i];
si += image.width();
}
dst[di] = qRound(a) << 24;
di += image.width();
}
for (int y = center; y < image.height() - center; y++) {
double a = 0;
int si = (y - center) * image.width() + x;
for (int i = 0; i < size; i++) {
a += qAlpha(src[si]) * kernel[i];
si += image.width();
}
dst[di] = qRound(a) << 24;
di += image.width();
}
for (int y = image.height() - center, stop = size - 1; y < image.height(); y++, stop--) {
double a = 0;
int si = (y - center) * image.width() + x;
for (int i = 0; i < stop; i++) {
a += qAlpha(src[si]) * kernel[i];
si += image.width();
}
dst[di] = qRound(a) << 24;
di += image.width();
}
}
delete [] buf;
delete [] kernel;
}
// -----------------------------------------------------------------------
TileSet::TileSet(const QPixmap &pixmap)
{
int tw = pixmap.width() / 3;
int th = pixmap.height();
for (int x = 0; x < 3; x++)
tiles[x] = pixmap.copy(x * tw, 0, tw, th);
}
void TileSet::paint(QPainter *p, const QRect &r)
{
int tw = tiles[Left].width();
int th = tiles[Left].height();
int tw2 = tw * 2;
if (r.width() < tw2) {
int sw = r.width() / 2;
p->drawPixmap(r.x(), r.y(), tiles[Left], 0, 0, sw, tiles[Left].height());
p->drawPixmap(r.x() + sw, r.y(), tiles[Right], tw - sw, 0, sw, tiles[Right].height());
} else {
p->drawPixmap(r.topLeft(), tiles[Left]);
if (r.width() - tw2 > 0)
p->drawTiledPixmap(r.x() + tw, r.y(), r.width() - tw2, th, tiles[Center]);
p->drawPixmap(r.right() - tw + 1, r.y(), tiles[Right]);
}
}
// -----------------------------------------------------------------------
HaloPainter *HaloPainter::s_instance = 0;
HaloPainter::HaloPainter()
: m_tileCache(16), m_haloCache(30)
{
}
HaloPainter::~HaloPainter()
{
}
TileSet *HaloPainter::tiles(int height) const
{
TileSet *tiles = m_tileCache.object(height);
if (!tiles) {
QImage image(64 * 3, height + 16, QImage::Format_ARGB32_Premultiplied);
image.fill(0);
QPainter p(&image);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(Qt::NoPen);
p.setBrush(Qt::white);
p.drawRoundedRect(image.rect().adjusted(8, 8, -8, -8), height, height / 2);
p.end();
gaussianBlur(image, 8);
p.begin(&image);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(image.rect(), QColor(255, 255, 255, 255));
p.end();
tiles = new TileSet(QPixmap::fromImage(image));
m_tileCache.insert(height, tiles);
}
return tiles;
}
void HaloPainter::paint(QPainter *painter, const QRect &textRect) const
{
int radius = textRect.height() / 2;
const QRect hr = textRect.adjusted(-8 - radius, -9, 8 + radius, 9);
int key = hr.width() << 16 | hr.height();
QPixmap *pixmap = m_haloCache.object(key);
if (!pixmap) {
TileSet *halo = tiles(hr.height() - 16);
pixmap = new QPixmap(hr.size());
pixmap->fill(Qt::transparent);
QPainter p(pixmap);
p.setCompositionMode(QPainter::CompositionMode_Source);
halo->paint(&p, pixmap->rect());
QLinearGradient g(0, 0, pixmap->width(), 0);
if (hr.width() < 80) {
for (int i = 0; i <= 16; i++) {
g.setColorAt(i / 16., QColor(0, 0, 0, 164 * (1 - std::pow((i - 8) / 8., 2))));
}
} else {
const qreal pixel = 1. / hr.width();
for (int i = 0; i <= 8; i++) {
const QColor color(0, 0, 0, 164 * (1 - std::pow((i - 8) / 8., 2)));
g.setColorAt(i * (pixel * 40) / 8, color);
g.setColorAt(1 - i * (pixel * 40) / 8, color);
}
}
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.fillRect(pixmap->rect(), g);
p.end();
m_haloCache.insert(key, pixmap);
}
painter->drawPixmap(hr.topLeft(), *pixmap);
}
} // namespace Plasma

View File

@ -0,0 +1,80 @@
/*
* Copyright © 2009 Fredrik Höglund <fredrik@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 HALOPAINTER_H
#define HALOPAINTER_H
#include <QCache>
#include <QPixmap>
class QRect;
class QPainter;
namespace Plasma {
class TileSet
{
public:
enum Tile {
Left, Center, Right, NTiles
};
TileSet(const QPixmap &pixmap);
~TileSet() {}
void paint(QPainter *painter, const QRect &rect);
protected:
QPixmap tiles[NTiles];
};
// -----------------------------------------------------------------------
class HaloPainter : public QObject
{
public:
~HaloPainter();
static HaloPainter *instance() {
if (!s_instance) {
s_instance = new HaloPainter;
}
return s_instance;
}
static void drawHalo(QPainter *painter, const QRect &textRect) {
instance()->paint(painter, textRect);
}
private:
HaloPainter();
TileSet *tiles(int height) const;
void paint(QPainter *painter, const QRect &textRect) const;
private:
static HaloPainter *s_instance;
mutable QCache<int, TileSet> m_tileCache;
mutable QCache<int, QPixmap> m_haloCache;
};
} // namespace Plasma
#endif

View File

@ -0,0 +1,86 @@
/*
* Copyright 2011 Marco Martin <mart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "effectwatcher_p.h"
#include <QCoreApplication>
#include <X11/Xlib.h>
#include <xcb/xcb.h>
#include <qx11info_x11.h>
namespace Plasma
{
EffectWatcher::EffectWatcher(const QString& property, QObject *parent)
: QObject(parent),
m_property(property)
{
m_effectActive = isEffectActive();
QCoreApplication::instance()->installNativeEventFilter(this);
Display *dpy = QX11Info::display();
Window root = DefaultRootWindow(dpy);
XWindowAttributes attrs;
//Don't reset eventual other masks already there
XGetWindowAttributes(dpy, root, &attrs);
attrs.your_event_mask |= PropertyChangeMask;
XSelectInput(dpy, root, attrs.your_event_mask);
}
bool EffectWatcher::nativeEventFilter(const QByteArray& eventType, void *message, long *result)
{
Q_UNUSED(result);
if (eventType != "xcb_generic_event_t")
return false;
xcb_generic_event_t* event = reinterpret_cast<xcb_generic_event_t *>(message);
uint response_type = event->response_type & ~0x80;
if (response_type != XCB_PROPERTY_NOTIFY)
return false;
xcb_property_notify_event_t* prop_event = reinterpret_cast<xcb_property_notify_event_t *>(event);
Display *dpy = QX11Info::display();
Atom testAtom = XInternAtom(dpy, m_property.toLatin1(), False);
if (prop_event->atom == testAtom) {
bool nowEffectActive = isEffectActive();
if (m_effectActive != nowEffectActive) {
m_effectActive = nowEffectActive;
emit effectChanged(m_effectActive);
}
}
return false;
}
bool EffectWatcher::isEffectActive() const
{
Display *dpy = QX11Info::display();
Atom testAtom = XInternAtom(dpy, m_property.toLatin1(), False);
bool nowEffectActive = false;
int cnt;
Atom *list = XListProperties(dpy, DefaultRootWindow(dpy), &cnt);
if (list != NULL) {
nowEffectActive = (qFind(list, list + cnt, testAtom) != list + cnt);
XFree(list);
}
return nowEffectActive;
}
} // namespace Plasma

View File

@ -0,0 +1,52 @@
/*
* Copyright 2011 Marco Martin <mart@kde.org>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef BLURWATCHER_H
#define BLURWATCHER_H
#include <QObject>
#include <QAbstractNativeEventFilter>
namespace Plasma
{
class EffectWatcher: public QObject, public QAbstractNativeEventFilter
{
Q_OBJECT
public:
EffectWatcher(const QString& property, QObject *parent = 0);
protected:
bool isEffectActive() const;
bool nativeEventFilter(const QByteArray& eventType, void *message, long *result) Q_DECL_OVERRIDE;
Q_SIGNALS:
void effectChanged(bool on);
private:
QString m_property;
bool m_effectActive;
};
} // namespace Plasma
#endif

149
plasma/private/framesvg_p.h Normal file
View File

@ -0,0 +1,149 @@
/*
* Copyright 2008 by Aaron Seigo <aseigo@kde.org>
* Copyright 2009 Marco Martin <notmart@gmail.com>
*
* This program 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, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_FRAMESVG_P_H
#define PLASMA_FRAMESVG_P_H
#include <QHash>
#include <QStringBuilder>
#include <kdebug.h>
namespace Plasma
{
class FrameData
{
public:
FrameData(FrameSvg *svg)
: enabledBorders(FrameSvg::AllBorders),
frameSize(-1,-1),
topHeight(0),
leftWidth(0),
rightWidth(0),
bottomHeight(0),
topMargin(0),
leftMargin(0),
rightMargin(0),
bottomMargin(0),
noBorderPadding(false),
stretchBorders(false),
tileCenter(false),
composeOverBorder(false)
{
ref(svg);
}
FrameData(const FrameData &other, FrameSvg *svg)
: enabledBorders(other.enabledBorders),
frameSize(other.frameSize),
topHeight(0),
leftWidth(0),
rightWidth(0),
bottomHeight(0),
topMargin(0),
leftMargin(0),
rightMargin(0),
bottomMargin(0),
noBorderPadding(false),
stretchBorders(false),
tileCenter(false),
composeOverBorder(false)
{
ref(svg);
}
~FrameData()
{
}
void ref(FrameSvg *svg);
bool deref(FrameSvg *svg);
bool removeRefs(FrameSvg *svg);
bool isUsed() const;
int refcount() const;
FrameSvg::EnabledBorders enabledBorders;
QPixmap cachedBackground;
QHash<QString, QRegion> cachedMasks;
static const int MAX_CACHED_MASKS = 10;
QSize frameSize;
//measures
int topHeight;
int leftWidth;
int rightWidth;
int bottomHeight;
//margins, are equal to the measures by default
int topMargin;
int leftMargin;
int rightMargin;
int bottomMargin;
//size of the svg where the size of the "center"
//element is contentWidth x contentHeight
bool noBorderPadding : 1;
bool stretchBorders : 1;
bool tileCenter : 1;
bool composeOverBorder : 1;
QHash<FrameSvg *, int> references;
};
class FrameSvgPrivate
{
public:
FrameSvgPrivate(FrameSvg *psvg)
: q(psvg),
cacheAll(false),
overlayPos(0,0)
{
}
~FrameSvgPrivate();
QPixmap alphaMask();
void generateBackground(FrameData *frame);
void generateFrameBackground(FrameData *frame);
QString cacheId(FrameData *frame, const QString &prefixToUse) const;
void cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay);
void updateSizes() const;
void updateNeeded();
void updateAndSignalSizes();
QSizeF frameSize(FrameData *frame) const;
Location location;
QString prefix;
FrameSvg *q;
bool cacheAll : 1;
QPoint overlayPos;
QHash<QString, FrameData*> frames;
static QHash<QString, FrameData *> s_sharedFrames;
};
}
#endif

View File

@ -0,0 +1,83 @@
/*
* Copyright © 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This program 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "getsource_p.h"
#include "authorizationmanager_p.h"
#include "dataengineservice_p.h"
#include "service_p.h"
#include "../remote/authorizationmanager.h"
#include "../remote/authorizationrule.h"
#include "../dataengine.h"
#include "../service.h"
#include <kdebug.h>
namespace Plasma
{
GetSource::GetSource(DataEngine *engine, const QString& operation,
QHash<QString,QVariant>& parameters,
DataEngineService *service)
: ServiceJob(QString("publickey"), operation, parameters, service),
m_engine(engine),
m_service(service)
{
}
void GetSource::start()
{
#ifndef NDEBUG
kDebug() << "Trying to perform the action" << operationName();
#endif
//TODO: check with capabilities before performing actions.
if (operationName() == "GetSource") {
QString source = parameters().value("SourceName").toString();
QString UUID = parameters().value("UUID").toString();
if (!m_service->m_peersAlreadyUpdated[source].contains(UUID)) {
m_service->m_peersAlreadyUpdated[source].append(UUID);
setResult(m_service->m_data[source]);
} else {
setResult(false); //no update needed
}
} else if (operationName() == "GetSourceNames") {
setResult(m_engine->sources());
} else if (operationName() == "ServiceForSource") {
QString source = parameters().value("SourceName").toString();
Service *service = m_engine->serviceForSource(source);
QString serviceName = "plasma-service-" + service->name();
#ifndef NDEBUG
kDebug() << "serviceForSource: getting source " << serviceName;
#endif
service->d->publish(Plasma::NoAnnouncement, serviceName);
if (!AuthorizationManager::self()->d->matchingRule(serviceName, identity())) {
AuthorizationRule *rule = new AuthorizationRule(serviceName, identity().id());
rule->setPolicy(AuthorizationRule::Allow);
AuthorizationManager::self()->d->rules.append(rule);
}
setResult(serviceName);
}
}
}
#include "moc_getsource_p.cpp"

View File

@ -0,0 +1,48 @@
/*
* Copyright © 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This program 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef GETSOURCE_H
#define GETSOURCE_H
#include "../servicejob.h"
namespace Plasma
{
class DataEngine;
class DataEngineService;
class GetSource : public Plasma::ServiceJob
{
Q_OBJECT
public:
GetSource(DataEngine *engine, const QString& operation,
QHash<QString,QVariant>& parameters,
DataEngineService *service = 0);
void start();
private:
DataEngine *m_engine;
DataEngineService *m_service;
};
}
#endif //JOBVIEW_H

View File

@ -0,0 +1,122 @@
/*
* Copyright © 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This program 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef JOLIEMESSAGEHELPER_H
#define JOLIEMESSAGEHELPER_H
#include <QByteArray>
#include <QtJolie/Message>
#include <QtJolie/Value>
#include <kdebug.h>
#include <klocalizedstring.h>
namespace JolieMessage {
namespace Field {
static const QByteArray DESTINATION = "Destination";
static const QByteArray ENABLEDOPERATIONS
= "EnabledOperations";
static const QByteArray IDENTITY = "Credentials";
static const QByteArray IDENTITYID = "CredentialsID";
static const QByteArray PARAMETERS = "Parameters";
static const QByteArray PIN = "PIN";
static const QByteArray RESULT = "Result";
static const QByteArray SIGNATURE = "Signature";
static const QByteArray TOKEN = "Token";
static const QByteArray UUID = "UUID";
static const QByteArray OPERATION = "Operation";
static const QByteArray OPERATIONSDESCRIPTION
= "OperationsDescription";
}
namespace Error {
static const QByteArray INVALIDTOKEN = "InvalidToken";
static const QByteArray REQUIREPIN = "RequirePIN";
static const QByteArray ACCESSDENIED = "AccessDenied";
}
inline QString errorMessage(const QByteArray &error)
{
if (error == Error::INVALIDTOKEN) {
return i18nc("Error message, access to a remote service failed.",
"Invalid token.");
} else if (error == Error::REQUIREPIN) {
return i18nc("Error message, access to a remote service failed.",
"Matching password required.");
} else if (error == Error::ACCESSDENIED) {
return i18nc("Error message, access to a remote service failed.",
"Access denied.");
}
return i18n("Unknown error.");
}
inline QByteArray field(const QByteArray &fieldName, const Jolie::Message &message)
{
if (!message.data().children(fieldName).isEmpty()) {
return message.data().children(fieldName).first().toByteArray();
} else {
return QByteArray();
}
}
inline QByteArray payload(const Jolie::Message &message)
{
QByteArray result;
//result = "payload!";
result.append(message.operationName());
result.append(field(Field::PARAMETERS, message));
result.append(field(Field::IDENTITY, message));
result.append(field(Field::IDENTITYID, message));
result.append(field(Field::OPERATION, message));
result.append(field(Field::OPERATIONSDESCRIPTION, message));
result.append(field(Field::PIN, message));
result.append(field(Field::TOKEN, message));
return result;
}
inline QString print(const Jolie::Message &message)
{
QString result;
result =
QString("\n=== JOLIE MESSAGE ===\nId = %1\nOperation = %2\nResource = %3\nData= %4\n")
.arg(QString::number(message.id()))
.arg(QString(message.operationName()))
.arg(QString(message.resourcePath()))
.arg(QString(message.data().toByteArray()));
result += "=====================\n";
foreach (const QByteArray &child, message.data().childrenNames()) {
result += "\n******" + child + "******\n";
foreach (const Jolie::Value &value, message.data().children(child)) {
if (child == Field::TOKEN || child == Field::PARAMETERS
|| child == Field::SIGNATURE) {
result += value.toByteArray().toBase64();
} else {
result += value.toByteArray();
}
}
}
result += "\n== END OF MESSAGE ==\n";
return result;
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More