ok, this time JUST the plasma dir ;)
svn path=/trunk/KDE/kdelibs/; revision=879759
This commit is contained in:
parent
44f44ebfea
commit
1b523b9054
299
CMakeLists.txt
Normal file
299
CMakeLists.txt
Normal file
@ -0,0 +1,299 @@
|
||||
find_package(Nepomuk REQUIRED)
|
||||
include (KDE4Defaults)
|
||||
include(NepomukMacros)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs ${CMAKE_CURRENT_SOURCE_DIR}/.. ${KDE4_INCLUDES})
|
||||
if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
|
||||
add_subdirectory(tests)
|
||||
add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1209)
|
||||
|
||||
########### next target ###############
|
||||
|
||||
set(plasmagik_SRCS
|
||||
packagemetadata.cpp
|
||||
packagestructure.cpp
|
||||
package.cpp
|
||||
)
|
||||
|
||||
set(plasma_LIB_SRCS
|
||||
${plasmagik_SRCS}
|
||||
abstractrunner.cpp
|
||||
animationdriver.cpp
|
||||
animator.cpp
|
||||
applet.cpp
|
||||
configloader.cpp
|
||||
containment.cpp
|
||||
context.cpp
|
||||
corona.cpp
|
||||
datacontainer.cpp
|
||||
dataengine.cpp
|
||||
dataenginemanager.cpp
|
||||
delegate.cpp
|
||||
dialog.cpp
|
||||
extender.cpp
|
||||
extenderitem.cpp
|
||||
paintutils.cpp
|
||||
framesvg.cpp
|
||||
plasma.cpp
|
||||
popupapplet.cpp
|
||||
private/applethandle.cpp
|
||||
private/datacontainer_p.cpp
|
||||
private/desktoptoolbox.cpp
|
||||
private/extenderapplet.cpp
|
||||
private/nativetabbar.cpp
|
||||
private/packages.cpp
|
||||
private/paneltoolbox.cpp
|
||||
private/style.cpp
|
||||
private/toolbox.cpp
|
||||
private/tooltip.cpp
|
||||
private/windowpreview.cpp
|
||||
querymatch.cpp
|
||||
runnercontext.cpp
|
||||
runnermanager.cpp
|
||||
scripting/appletscript.cpp
|
||||
scripting/dataenginescript.cpp
|
||||
scripting/runnerscript.cpp
|
||||
scripting/scriptengine.cpp
|
||||
scripting/uiloader.cpp
|
||||
service.cpp
|
||||
servicejob.cpp
|
||||
svg.cpp
|
||||
theme.cpp
|
||||
tooltipcontent.cpp
|
||||
tooltipmanager.cpp
|
||||
version.cpp
|
||||
view.cpp
|
||||
wallpaper.cpp
|
||||
widgets/checkbox.cpp
|
||||
widgets/combobox.cpp
|
||||
widgets/flashinglabel.cpp
|
||||
widgets/frame.cpp
|
||||
widgets/groupbox.cpp
|
||||
widgets/iconwidget.cpp
|
||||
widgets/label.cpp
|
||||
widgets/lineedit.cpp
|
||||
widgets/meter.cpp
|
||||
widgets/pushbutton.cpp
|
||||
widgets/radiobutton.cpp
|
||||
widgets/scrollbar.cpp
|
||||
widgets/signalplotter.cpp
|
||||
widgets/slider.cpp
|
||||
widgets/busywidget.cpp
|
||||
widgets/svgwidget.cpp
|
||||
widgets/tabbar.cpp
|
||||
widgets/treeview.cpp
|
||||
widgets/textedit.cpp
|
||||
widgets/webview.cpp
|
||||
)
|
||||
|
||||
#NEPOMUK_GENERATE_FROM_ONTOLOGY(
|
||||
# nwc.nrl
|
||||
# ${metadata_test_BINARY_DIR}
|
||||
# TEST_HEADERS
|
||||
# TEST_SOURCES
|
||||
# TEST_INCLUDES
|
||||
#)
|
||||
|
||||
if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
MESSAGE(STATUS "Adding support for OpenGL applets to libplasma")
|
||||
set(plasma_LIB_SRCS
|
||||
${plasma_LIB_SRCS}
|
||||
glapplet.cpp)
|
||||
endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
|
||||
kde4_add_library(plasma SHARED ${plasma_LIB_SRCS})
|
||||
|
||||
target_link_libraries(plasma ${KDE4_KIO_LIBS} ${KDE4_KFILE_LIBS} ${KDE4_KNEWSTUFF2_LIBS}
|
||||
${QT_QTUITOOLS_LIBRARY} ${QT_QTWEBKIT_LIBRARY}
|
||||
${KDE4_THREADWEAVER_LIBRARIES} ${KDE4_SOLID_LIBS} ${X11_LIBRARIES})
|
||||
if(DL_LIBRARY)
|
||||
target_link_libraries(plasma ${DL_LIBRARY})
|
||||
endif(DL_LIBRARY)
|
||||
|
||||
if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
target_link_libraries(plasma ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY})
|
||||
endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
|
||||
set_target_properties(plasma PROPERTIES
|
||||
VERSION 3.0.0
|
||||
SOVERSION 3
|
||||
${KDE4_DISABLE_PROPERTY_}LINK_INTERFACE_LIBRARIES "${KDE4_KDEUI_LIBS}"
|
||||
)
|
||||
|
||||
install(TARGETS plasma ${INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
|
||||
########### install files ###############
|
||||
|
||||
set(plasmagik_HEADERS
|
||||
packagemetadata.h
|
||||
packagestructure.h
|
||||
package.h
|
||||
)
|
||||
|
||||
install(FILES ${plasmagik_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/ COMPONENT Devel)
|
||||
|
||||
set(plasma_LIB_INCLUDES
|
||||
abstractrunner.h
|
||||
animationdriver.h
|
||||
animator.h
|
||||
applet.h
|
||||
configloader.h
|
||||
containment.h
|
||||
context.h
|
||||
corona.h
|
||||
datacontainer.h
|
||||
dataengine.h
|
||||
dataenginemanager.h
|
||||
delegate.h
|
||||
dialog.h
|
||||
extender.h
|
||||
extenderitem.h
|
||||
paintutils.h
|
||||
framesvg.h
|
||||
plasma.h
|
||||
plasma_export.h
|
||||
popupapplet.h
|
||||
querymatch.h
|
||||
runnercontext.h
|
||||
runnermanager.h
|
||||
service.h
|
||||
servicejob.h
|
||||
svg.h
|
||||
theme.h
|
||||
tooltipcontent.h
|
||||
tooltipmanager.h
|
||||
tooltipmanager.h
|
||||
version.h
|
||||
view.h
|
||||
wallpaper.h)
|
||||
|
||||
if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
set(plasma_LIB_INCLUDES
|
||||
${plasma_LIB_INCLUDES}
|
||||
glapplet.h)
|
||||
endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
|
||||
install(FILES
|
||||
${plasma_LIB_INCLUDES}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/plasma COMPONENT Devel)
|
||||
|
||||
install(FILES
|
||||
widgets/checkbox.h
|
||||
widgets/combobox.h
|
||||
widgets/flashinglabel.h
|
||||
widgets/frame.h
|
||||
widgets/groupbox.h
|
||||
widgets/iconwidget.h
|
||||
widgets/label.h
|
||||
widgets/lineedit.h
|
||||
widgets/meter.h
|
||||
widgets/pushbutton.h
|
||||
widgets/radiobutton.h
|
||||
widgets/scrollbar.h
|
||||
widgets/signalplotter.h
|
||||
widgets/slider.h
|
||||
widgets/busywidget.h
|
||||
widgets/svgwidget.h
|
||||
widgets/tabbar.h
|
||||
widgets/treeview.h
|
||||
widgets/textedit.h
|
||||
widgets/webview.h
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/widgets COMPONENT Devel)
|
||||
|
||||
install(FILES
|
||||
scripting/appletscript.h
|
||||
scripting/dataenginescript.h
|
||||
scripting/runnerscript.h
|
||||
scripting/scriptengine.h
|
||||
scripting/uiloader.h
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/scripting COMPONENT Devel)
|
||||
|
||||
|
||||
install(FILES
|
||||
includes/AbstractRunner
|
||||
includes/AnimationDriver
|
||||
includes/Animator
|
||||
includes/Applet
|
||||
includes/AppletScript
|
||||
includes/CheckBox
|
||||
includes/ComboBox
|
||||
includes/ConfigLoader
|
||||
includes/Containment
|
||||
includes/Context
|
||||
includes/Corona
|
||||
includes/DataContainer
|
||||
includes/DataEngine
|
||||
includes/DataEngineManager
|
||||
includes/DataEngineScript
|
||||
includes/Delegate
|
||||
includes/Dialog
|
||||
includes/Extender
|
||||
includes/ExtenderItem
|
||||
includes/FlashingLabel
|
||||
includes/Frame
|
||||
includes/FrameSvg
|
||||
includes/GroupBox
|
||||
includes/IconWidget
|
||||
includes/Label
|
||||
includes/LineEdit
|
||||
includes/Meter
|
||||
includes/Package
|
||||
includes/PackageMetadata
|
||||
includes/PackageStructure
|
||||
includes/PaintUtils
|
||||
includes/Plasma
|
||||
includes/PopupApplet
|
||||
includes/PushButton
|
||||
includes/QueryMatch
|
||||
includes/RadioButton
|
||||
includes/RunnerContext
|
||||
includes/RunnerManager
|
||||
includes/RunnerScript
|
||||
includes/ScriptEngine
|
||||
includes/ScrollBar
|
||||
includes/Service
|
||||
includes/ServiceJob
|
||||
includes/SignalPlotter
|
||||
includes/Slider
|
||||
includes/BusyWidget
|
||||
includes/Svg
|
||||
includes/SvgWidget
|
||||
includes/TabBar
|
||||
includes/TextEdit
|
||||
includes/ToolTipManager
|
||||
includes/Theme
|
||||
includes/TreeView
|
||||
includes/UiLoader
|
||||
includes/View
|
||||
includes/Version
|
||||
includes/Wallpaper
|
||||
includes/WebView
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Plasma COMPONENT Devel)
|
||||
|
||||
if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
install(FILES
|
||||
includes/GLApplet
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Plasma COMPONENT Devel)
|
||||
endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
|
||||
|
||||
install(FILES
|
||||
servicetypes/plasma-animator.desktop
|
||||
servicetypes/plasma-applet.desktop
|
||||
servicetypes/plasma-containment.desktop
|
||||
servicetypes/plasma-dataengine.desktop
|
||||
servicetypes/plasma-packagestructure.desktop
|
||||
servicetypes/plasma-runner.desktop
|
||||
servicetypes/plasma-scriptengine.desktop
|
||||
servicetypes/plasma-wallpaper.desktop
|
||||
DESTINATION ${SERVICETYPES_INSTALL_DIR})
|
||||
|
||||
install(FILES
|
||||
servicetypes/plasma-applet-extenderapplet.desktop
|
||||
DESTINATION ${SERVICES_INSTALL_DIR})
|
||||
|
||||
install(FILES scripting/plasmoids.knsrc DESTINATION ${CONFIG_INSTALL_DIR})
|
||||
|
100
Mainpage.dox
Normal file
100
Mainpage.dox
Normal 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 Plasma, the new desktop shell in
|
||||
KDE 4, it is general enough to be useful in other applications.
|
||||
<a href="http://amarok.kde.org">Amarok</a> is already 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. Also, infrastructure such as a dialog to install
|
||||
new widgets and even download them from the web (Plasma::AppletBrowser) is also
|
||||
included.
|
||||
|
||||
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 OpneGL-rendered Plasma::Applet
|
||||
- Plasma::PackageStructure: 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>
|
||||
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 = libplasma
|
||||
// DOXYGEN_SET_RECURSIVE = YES
|
||||
// vim:ts=4:sw=4:expandtab:filetype=doxygen
|
2
Messages.sh
Normal file
2
Messages.sh
Normal file
@ -0,0 +1,2 @@
|
||||
#! /usr/bin/env bash
|
||||
$XGETTEXT *.cpp *.h */*.h */*.cpp -o $podir/libplasma.pot
|
23
README
Normal file
23
README
Normal file
@ -0,0 +1,23 @@
|
||||
libplasma
|
||||
|
||||
Commit Rules:
|
||||
* If your patch is not an obvious or trivial bug fix, have it peer reviewed
|
||||
by another Plasma developer
|
||||
* 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
|
||||
|
||||
Unit tests are next to godliness. (Though as you can see, right now libplasma
|
||||
is hellbound.)
|
||||
|
||||
This directory contains the classes making up libplasma, which provides the
|
||||
core framework used by Plasma and its components. This includes applet and
|
||||
extension definitions and loading, common GUI elements, etc.
|
||||
|
||||
Domain specific sets of functionality, e.g. for network awareness or sensors,
|
||||
are not found here but in one of the Plasma Engines.
|
||||
|
||||
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.
|
||||
|
318
abstractrunner.cpp
Normal file
318
abstractrunner.cpp
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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 <QMutex>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <KDebug>
|
||||
#include <KPluginInfo>
|
||||
#include <KServiceTypeTrader>
|
||||
#include <KStandardDirs>
|
||||
#include <QTimer>
|
||||
|
||||
#include <plasma/querymatch.h>
|
||||
#include <plasma/package.h>
|
||||
|
||||
#include "scripting/runnerscript.h"
|
||||
|
||||
#include "runnercontext.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class AbstractRunnerPrivate
|
||||
{
|
||||
public:
|
||||
AbstractRunnerPrivate(AbstractRunner *r, KService::Ptr service)
|
||||
: priority(AbstractRunner::NormalPriority),
|
||||
speed(AbstractRunner::NormalSpeed),
|
||||
blackListed(0),
|
||||
script(0),
|
||||
runnerDescription(service),
|
||||
runner(r),
|
||||
fastRuns(0),
|
||||
package(0)
|
||||
{
|
||||
if (runnerDescription.isValid()) {
|
||||
const QString api = runnerDescription.property("X-Plasma-API").toString();
|
||||
if (!api.isEmpty()) {
|
||||
const QString path = KStandardDirs::locate("data",
|
||||
"plasma/runners/" + runnerDescription.pluginName() + '/');
|
||||
PackageStructure::Ptr structure =
|
||||
Plasma::packageStructure(api, Plasma::RunnerComponent);
|
||||
structure->setPath(path);
|
||||
package = new Package(path, structure);
|
||||
|
||||
script = Plasma::loadScriptEngine(api, runner);
|
||||
if (!script) {
|
||||
kDebug() << "Could not create a(n)" << api << "ScriptEngine for the"
|
||||
<< runnerDescription.name() << "Runner.";
|
||||
delete package;
|
||||
package = 0;
|
||||
} else {
|
||||
QTimer::singleShot(0, runner, SLOT(init()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~AbstractRunnerPrivate()
|
||||
{
|
||||
delete script;
|
||||
script = 0;
|
||||
delete package;
|
||||
package = 0;
|
||||
}
|
||||
|
||||
bool hasRunOptions;
|
||||
bool hasConfig;
|
||||
AbstractRunner::Priority priority;
|
||||
AbstractRunner::Speed speed;
|
||||
RunnerContext::Types blackListed;
|
||||
RunnerScript *script;
|
||||
KPluginInfo runnerDescription;
|
||||
AbstractRunner *runner;
|
||||
QTime runtime;
|
||||
int fastRuns;
|
||||
Package *package;
|
||||
QHash<QString, QAction*> actions;
|
||||
};
|
||||
|
||||
K_GLOBAL_STATIC(QMutex, s_bigLock)
|
||||
|
||||
AbstractRunner::AbstractRunner(QObject *parent, const QString &serviceId)
|
||||
: QObject(parent),
|
||||
d(new AbstractRunnerPrivate(this, KService::serviceByStorageId(serviceId)))
|
||||
{
|
||||
}
|
||||
|
||||
AbstractRunner::AbstractRunner(QObject *parent, const QVariantList &args)
|
||||
: QObject(parent),
|
||||
d(new AbstractRunnerPrivate(this, KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString())))
|
||||
{
|
||||
}
|
||||
|
||||
AbstractRunner::~AbstractRunner()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
KConfigGroup AbstractRunner::config() const
|
||||
{
|
||||
QString group = objectName();
|
||||
if (group.isEmpty()) {
|
||||
group = "UnnamedRunner";
|
||||
}
|
||||
|
||||
KConfigGroup runners(KGlobal::config(), "Runners");
|
||||
return KConfigGroup(&runners, group);
|
||||
}
|
||||
|
||||
void AbstractRunner::reloadConfiguration()
|
||||
{
|
||||
}
|
||||
|
||||
void AbstractRunner::performMatch(Plasma::RunnerContext &globalContext)
|
||||
{
|
||||
static const int reasonableRunTime = 1500;
|
||||
static const int fastEnoughTime = 250;
|
||||
|
||||
d->runtime.restart();
|
||||
//TODO :this is a copy ctor
|
||||
RunnerContext localContext(globalContext, 0);
|
||||
match(localContext);
|
||||
// automatically rate limit runners that become slooow
|
||||
const int runtime = d->runtime.elapsed();
|
||||
bool slowed = speed() == SlowSpeed;
|
||||
|
||||
if (!slowed && runtime > reasonableRunTime) {
|
||||
// we punish runners that return too slowly, even if they don't bring
|
||||
// back matches
|
||||
kDebug() << id() << "runner is too slow, putting it on the back burner.";
|
||||
d->fastRuns = 0;
|
||||
setSpeed(SlowSpeed);
|
||||
}
|
||||
|
||||
//If matches were not added, delete items on the heap
|
||||
if (slowed && runtime < fastEnoughTime) {
|
||||
++d->fastRuns;
|
||||
|
||||
if (d->fastRuns > 2) {
|
||||
// we reward slowed runners who bring back matches fast enough
|
||||
// 3 times in a row
|
||||
kDebug() << id() << "runner is faster than we thought, kicking it up a notch";
|
||||
setSpeed(NormalSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QAction*> AbstractRunner::actionsForMatch(const Plasma::QueryMatch &match)
|
||||
{
|
||||
Q_UNUSED(match)
|
||||
QList<QAction*> 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();
|
||||
}
|
||||
|
||||
bool AbstractRunner::hasRunOptions()
|
||||
{
|
||||
return d->hasRunOptions;
|
||||
}
|
||||
|
||||
void AbstractRunner::setHasRunOptions(bool hasRunOptions)
|
||||
{
|
||||
d->hasRunOptions = hasRunOptions;
|
||||
}
|
||||
|
||||
void AbstractRunner::createRunOptions(QWidget *parent)
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
}
|
||||
|
||||
AbstractRunner::Speed AbstractRunner::speed() const
|
||||
{
|
||||
return d->speed;
|
||||
}
|
||||
|
||||
void AbstractRunner::setSpeed(Speed speed)
|
||||
{
|
||||
d->speed = speed;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
KService::List AbstractRunner::serviceQuery(const QString &serviceType, const QString &constraint) const
|
||||
{
|
||||
QMutexLocker lock(s_bigLock);
|
||||
return KServiceTypeTrader::self()->query(serviceType, constraint);
|
||||
}
|
||||
|
||||
QMutex* AbstractRunner::bigLock() const
|
||||
{
|
||||
return s_bigLock;
|
||||
}
|
||||
|
||||
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 objectName();
|
||||
}
|
||||
return d->runnerDescription.name();
|
||||
}
|
||||
|
||||
QString AbstractRunner::id() const
|
||||
{
|
||||
if (!d->runnerDescription.isValid()) {
|
||||
return objectName();
|
||||
}
|
||||
return d->runnerDescription.pluginName();
|
||||
}
|
||||
|
||||
QString AbstractRunner::description() const
|
||||
{
|
||||
if (!d->runnerDescription.isValid()) {
|
||||
return objectName();
|
||||
}
|
||||
return d->runnerDescription.property("Comment").toString();
|
||||
}
|
||||
|
||||
const Package* AbstractRunner::package() const
|
||||
{
|
||||
return d->package;
|
||||
}
|
||||
|
||||
void AbstractRunner::init()
|
||||
{
|
||||
if (d->script) {
|
||||
d->script->init();
|
||||
}
|
||||
}
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "abstractrunner.moc"
|
349
abstractrunner.h
Normal file
349
abstractrunner.h
Normal file
@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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_ABSTRACTRUNNER_H
|
||||
#define PLASMA_ABSTRACTRUNNER_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include <KDE/KConfigGroup>
|
||||
#include <KDE/KService>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
#include <plasma/runnercontext.h>
|
||||
#include <plasma/querymatch.h>
|
||||
#include <plasma/version.h>
|
||||
|
||||
class QAction;
|
||||
|
||||
class KCompletion;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
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.
|
||||
*/
|
||||
class PLASMA_EXPORT AbstractRunner : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
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. Asyncroneous 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!
|
||||
* @see actionsForMatch
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @caution 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.
|
||||
*
|
||||
* @arg 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 fillMatches
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Returns the user visible engine name for the Runner
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* Returns an id string for the Runner
|
||||
*/
|
||||
QString id() const;
|
||||
|
||||
/**
|
||||
* Returns the description of this Runner
|
||||
*/
|
||||
QString description() 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, or 0 if none
|
||||
**/
|
||||
const Package *package() const;
|
||||
|
||||
/**
|
||||
* Signal runner to reload its configuration.
|
||||
*/
|
||||
virtual void reloadConfiguration();
|
||||
|
||||
protected:
|
||||
friend class RunnerManager;
|
||||
friend class RunnerManagerPrivate;
|
||||
|
||||
/**
|
||||
* Constructs a Runner object. Since AbstractRunner has pure virtuals,
|
||||
* this constructor can not be called directly. Rather a subclass must
|
||||
* be created
|
||||
*/
|
||||
explicit AbstractRunner(QObject *parent = 0, const QString &serviceId = QString());
|
||||
AbstractRunner(QObject *parent, const QVariantList &args);
|
||||
|
||||
/**
|
||||
* 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 blocking method to do queries of installed Services which can provide
|
||||
* a measure of safety for runners running their own threads. This should
|
||||
* be used instead of calling KServiceTypeTrader::query(..) directly.
|
||||
*
|
||||
* @arg serviceType a service type like "Plasma/Applet" or "KFilePlugin"
|
||||
* @arg constraint a constraint to limit the choices returned.
|
||||
* @see KServiceTypeTrader::query(const QString&, const QString&)
|
||||
*
|
||||
* @return a list of services that satisfy the query.
|
||||
*/
|
||||
KService::List serviceQuery(const QString &serviceType,
|
||||
const QString &constraint = QString()) const;
|
||||
|
||||
QMutex *bigLock() const;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void init();
|
||||
|
||||
private:
|
||||
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)
|
||||
|
||||
#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
|
146
animationdriver.cpp
Normal file
146
animationdriver.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
|
||||
* 2007 Alexis Ménard <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 "animationdriver.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QGraphicsItem>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
AnimationDriver::AnimationDriver(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(0)
|
||||
{
|
||||
}
|
||||
|
||||
AnimationDriver::~AnimationDriver()
|
||||
{
|
||||
}
|
||||
|
||||
int AnimationDriver::animationFps(Plasma::Animator::Animation animation) const
|
||||
{
|
||||
Q_UNUSED(animation)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AnimationDriver::movementAnimationFps(Plasma::Animator::Movement movement) const
|
||||
{
|
||||
Q_UNUSED(movement)
|
||||
return 40;
|
||||
}
|
||||
|
||||
int AnimationDriver::elementAnimationFps(Plasma::Animator::Animation animation) const
|
||||
{
|
||||
Q_UNUSED(animation)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AnimationDriver::animationDuration(Plasma::Animator::Animation) const
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
|
||||
int AnimationDriver::movementAnimationDuration(Plasma::Animator::Movement movement) const
|
||||
{
|
||||
switch (movement) {
|
||||
case Animator::FastSlideInMovement:
|
||||
case Animator::FastSlideOutMovement:
|
||||
return 150;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 250;
|
||||
}
|
||||
|
||||
int AnimationDriver::elementAnimationDuration(Plasma::Animator::Animation) const
|
||||
{
|
||||
return 333;
|
||||
}
|
||||
|
||||
Animator::CurveShape AnimationDriver::animationCurve(Plasma::Animator::Animation) const
|
||||
{
|
||||
return Animator::EaseInOutCurve;
|
||||
}
|
||||
|
||||
Animator::CurveShape AnimationDriver::movementAnimationCurve(Plasma::Animator::Movement) const
|
||||
{
|
||||
return Animator::EaseInOutCurve;
|
||||
}
|
||||
|
||||
Animator::CurveShape AnimationDriver::elementAnimationCurve(Plasma::Animator::Animation) const
|
||||
{
|
||||
return Animator::EaseInOutCurve;
|
||||
}
|
||||
|
||||
QPixmap AnimationDriver::elementAppear(qreal progress, const QPixmap &pixmap)
|
||||
{
|
||||
Q_UNUSED(progress)
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
QPixmap AnimationDriver::elementDisappear(qreal progress, const QPixmap &pixmap)
|
||||
{
|
||||
Q_UNUSED(progress)
|
||||
QPixmap pix(pixmap.size());
|
||||
pix.fill(Qt::transparent);
|
||||
|
||||
return pix;
|
||||
}
|
||||
|
||||
void AnimationDriver::itemAppear(qreal frame, QGraphicsItem *item)
|
||||
{
|
||||
Q_UNUSED(frame)
|
||||
Q_UNUSED(item)
|
||||
}
|
||||
|
||||
void AnimationDriver::itemDisappear(qreal frame, QGraphicsItem *item)
|
||||
{
|
||||
Q_UNUSED(frame)
|
||||
Q_UNUSED(item)
|
||||
}
|
||||
|
||||
void AnimationDriver::itemActivated(qreal frame, QGraphicsItem *item)
|
||||
{
|
||||
Q_UNUSED(frame)
|
||||
Q_UNUSED(item)
|
||||
}
|
||||
|
||||
void AnimationDriver::itemSlideIn(qreal progress, QGraphicsItem *item, const QPoint &start, const QPoint &destination)
|
||||
{
|
||||
double x = start.x() + (destination.x() - start.x()) * progress;
|
||||
double y = start.y() + (destination.y() - start.y()) * progress;
|
||||
item->setPos(x, y);
|
||||
}
|
||||
|
||||
void AnimationDriver::itemSlideOut(qreal progress, QGraphicsItem *item, const QPoint &start, const QPoint &destination)
|
||||
{
|
||||
//kDebug();
|
||||
double x = start.x() + (destination.x() - start.x()) * progress;
|
||||
double y = start.y() + (destination.y() - start.y()) * progress;
|
||||
item->setPos(x, y);
|
||||
}
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "animationdriver.moc"
|
85
animationdriver.h
Normal file
85
animationdriver.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
|
||||
* Copyright 2007 Alexis Ménard <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_ANIMATIONDRIVER_H
|
||||
#define PLASMA_ANIMATIONDRIVER_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtGui/QRegion>
|
||||
#include <QtGui/QPixmap>
|
||||
|
||||
#include <kgenericfactory.h>
|
||||
|
||||
#include <plasma/version.h>
|
||||
#include <plasma/animator.h>
|
||||
|
||||
class QGraphicsItem;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class AnimationDriverPrivate;
|
||||
|
||||
class PLASMA_EXPORT AnimationDriver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AnimationDriver(QObject *parent = 0);
|
||||
~AnimationDriver();
|
||||
|
||||
// Parameter definitions
|
||||
virtual int animationFps(Plasma::Animator::Animation) const;
|
||||
virtual int movementAnimationFps(Plasma::Animator::Movement) const;
|
||||
virtual int elementAnimationFps(Plasma::Animator::Animation) const;
|
||||
virtual int animationDuration(Plasma::Animator::Animation) const;
|
||||
virtual int movementAnimationDuration(Plasma::Animator::Movement) const;
|
||||
virtual int elementAnimationDuration(Plasma::Animator::Animation) const;
|
||||
virtual Animator::CurveShape animationCurve(Plasma::Animator::Animation) const;
|
||||
virtual Animator::CurveShape movementAnimationCurve(Plasma::Animator::Movement) const;
|
||||
virtual Animator::CurveShape elementAnimationCurve(Plasma::Animator::Animation) const;
|
||||
|
||||
// Element animations
|
||||
virtual QPixmap elementAppear(qreal progress, const QPixmap &pixmap);
|
||||
virtual QPixmap elementDisappear(qreal progress, const QPixmap &pixmap);
|
||||
|
||||
// Item animations
|
||||
virtual void itemAppear(qreal progress, QGraphicsItem *item);
|
||||
virtual void itemDisappear(qreal progress, QGraphicsItem *item);
|
||||
virtual void itemActivated(qreal progress, QGraphicsItem *item);
|
||||
|
||||
// Item movements
|
||||
virtual void itemSlideIn(qreal progress, QGraphicsItem *item,
|
||||
const QPoint &start, const QPoint &destination);
|
||||
virtual void itemSlideOut(qreal progress, QGraphicsItem *item,
|
||||
const QPoint &start, const QPoint &destination);
|
||||
|
||||
private:
|
||||
AnimationDriverPrivate *const d;
|
||||
};
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#define K_EXPORT_PLASMA_ANIMATOR(libname, classname) \
|
||||
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
|
||||
K_EXPORT_PLUGIN(factory("plasma_animator_" #libname)) \
|
||||
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
|
||||
|
||||
#endif // multiple inclusion guard
|
729
animator.cpp
Normal file
729
animator.cpp
Normal file
@ -0,0 +1,729 @@
|
||||
/*
|
||||
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
|
||||
* 2007 Alexis Ménard <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 "animator.h"
|
||||
|
||||
#include <QGraphicsItem>
|
||||
#include <QTimeLine>
|
||||
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KService>
|
||||
#include <KServiceTypeTrader>
|
||||
#include <KGlobalSettings>
|
||||
|
||||
#include "animationdriver.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
static const int MIN_TICK_RATE_INT = 10;
|
||||
static const qreal MIN_TICK_RATE = 10;
|
||||
|
||||
struct AnimationState
|
||||
{
|
||||
QGraphicsItem *item;
|
||||
QObject *qobj;
|
||||
Animator::Animation animation;
|
||||
Animator::CurveShape curve;
|
||||
int interval;
|
||||
int currentInterval;
|
||||
int frames;
|
||||
int currentFrame;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct ElementAnimationState
|
||||
{
|
||||
QGraphicsItem *item;
|
||||
QObject *qobj;
|
||||
Animator::CurveShape curve;
|
||||
Animator::Animation animation;
|
||||
int interval;
|
||||
int currentInterval;
|
||||
int frames;
|
||||
int currentFrame;
|
||||
int id;
|
||||
QPixmap pixmap;
|
||||
};
|
||||
|
||||
struct MovementState
|
||||
{
|
||||
QGraphicsItem *item;
|
||||
QObject *qobj;
|
||||
Animator::CurveShape curve;
|
||||
Animator::Movement movement;
|
||||
int interval;
|
||||
int currentInterval;
|
||||
int frames;
|
||||
int currentFrame;
|
||||
QPoint start;
|
||||
QPoint destination;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct CustomAnimationState
|
||||
{
|
||||
Animator::CurveShape curve;
|
||||
int frames;
|
||||
int currentFrame;
|
||||
int interval;
|
||||
int currentInterval;
|
||||
int id;
|
||||
QObject *receiver;
|
||||
char *slot;
|
||||
};
|
||||
|
||||
class AnimatorPrivate
|
||||
{
|
||||
public:
|
||||
|
||||
AnimatorPrivate()
|
||||
: driver(0),
|
||||
animId(0),
|
||||
timerId(0)
|
||||
{
|
||||
}
|
||||
|
||||
~AnimatorPrivate()
|
||||
{
|
||||
qDeleteAll(animatedItems);
|
||||
qDeleteAll(animatedElements);
|
||||
qDeleteAll(movingItems);
|
||||
|
||||
QMutableMapIterator<int, CustomAnimationState*> it(customAnims);
|
||||
while (it.hasNext()) {
|
||||
delete it.value()->slot;
|
||||
delete it.value();
|
||||
it.remove();
|
||||
}
|
||||
|
||||
// Animator is a QObject
|
||||
// and we don't own the items
|
||||
}
|
||||
|
||||
qreal calculateProgress(int time, int duration, Animator::CurveShape curve)
|
||||
{
|
||||
if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
|
||||
return qreal(1.0);
|
||||
}
|
||||
|
||||
timeline.setCurveShape(static_cast<QTimeLine::CurveShape>(curve));
|
||||
timeline.setDuration(duration);
|
||||
qreal progress = timeline.valueForTime(time);
|
||||
return progress;
|
||||
}
|
||||
|
||||
void performAnimation(qreal amount, const AnimationState *state)
|
||||
{
|
||||
switch (state->animation) {
|
||||
case Animator::AppearAnimation:
|
||||
driver->itemAppear(amount, state->item);
|
||||
break;
|
||||
case Animator::DisappearAnimation:
|
||||
driver->itemDisappear(amount, state->item);
|
||||
if (amount >= 1) {
|
||||
state->item->hide();
|
||||
}
|
||||
break;
|
||||
case Animator::ActivateAnimation:
|
||||
driver->itemActivated(amount, state->item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void performMovement(qreal amount, const MovementState *state)
|
||||
{
|
||||
switch (state->movement) {
|
||||
case Animator::SlideInMovement:
|
||||
case Animator::FastSlideInMovement:
|
||||
//kDebug() << "performMovement, SlideInMovement";
|
||||
driver->itemSlideIn(amount, state->item, state->start, state->destination);
|
||||
break;
|
||||
case Animator::SlideOutMovement:
|
||||
case Animator::FastSlideOutMovement:
|
||||
//kDebug() << "performMovement, SlideOutMovement";
|
||||
driver->itemSlideOut(amount, state->item, state->start, state->destination);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void init(Animator *q);
|
||||
void animatedItemDestroyed(QObject*);
|
||||
void movingItemDestroyed(QObject*);
|
||||
void animatedElementDestroyed(QObject*);
|
||||
void customAnimReceiverDestroyed(QObject*);
|
||||
|
||||
AnimationDriver *driver;
|
||||
int animId;
|
||||
int timerId;
|
||||
QTime time;
|
||||
QTimeLine timeline;
|
||||
|
||||
//TODO: eventually perhaps we should allow multiple animations simulataneously
|
||||
// which would imply changing this to a QMap<QGraphicsItem*, QList<QTimeLine*> >
|
||||
// and really making the code fun ;)
|
||||
QMap<QGraphicsItem*, AnimationState*> animatedItems;
|
||||
QMap<QGraphicsItem*, MovementState*> movingItems;
|
||||
QMap<int, ElementAnimationState*> animatedElements;
|
||||
QMap<int, CustomAnimationState*> customAnims;
|
||||
};
|
||||
|
||||
class AnimatorSingleton
|
||||
{
|
||||
public:
|
||||
Animator self;
|
||||
};
|
||||
|
||||
K_GLOBAL_STATIC(AnimatorSingleton, privateSelf)
|
||||
|
||||
Animator *Animator::self()
|
||||
{
|
||||
return &privateSelf->self;
|
||||
}
|
||||
|
||||
Animator::Animator(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new AnimatorPrivate)
|
||||
{
|
||||
d->init(this);
|
||||
}
|
||||
|
||||
Animator::~Animator()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void AnimatorPrivate::animatedItemDestroyed(QObject *o)
|
||||
{
|
||||
//kDebug() << "testing for" << (void*)o;
|
||||
QMutableMapIterator<QGraphicsItem*, AnimationState*> it(animatedItems);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
//kDebug() << "comparing against" << it.value()->qobj;
|
||||
if (it.value()->qobj == o) {
|
||||
kDebug() << "found deleted animated item";
|
||||
delete it.value();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimatorPrivate::movingItemDestroyed(QObject *o)
|
||||
{
|
||||
QMutableMapIterator<QGraphicsItem*, MovementState*> it(movingItems);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value()->qobj == o) {
|
||||
delete it.value();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimatorPrivate::animatedElementDestroyed(QObject *o)
|
||||
{
|
||||
QMutableMapIterator<int, ElementAnimationState*> it(animatedElements);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value()->qobj == o) {
|
||||
delete it.value();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimatorPrivate::customAnimReceiverDestroyed(QObject *o)
|
||||
{
|
||||
QMutableMapIterator<int, CustomAnimationState*> it(customAnims);
|
||||
while (it.hasNext()) {
|
||||
if (it.next().value()->receiver == o) {
|
||||
delete it.value()->slot;
|
||||
delete it.value();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Animator::animateItem(QGraphicsItem *item, Animation animation)
|
||||
{
|
||||
//kDebug();
|
||||
// get rid of any existing animations on this item.
|
||||
//TODO: shoudl we allow multiple anims per item?
|
||||
QMap<QGraphicsItem*, AnimationState*>::iterator it = d->animatedItems.find(item);
|
||||
if (it != d->animatedItems.end()) {
|
||||
delete it.value();
|
||||
d->animatedItems.erase(it);
|
||||
}
|
||||
|
||||
int frames = d->driver->animationFps(animation);
|
||||
|
||||
if (frames < 1) {
|
||||
// evidently this animator doesn't have an implementation
|
||||
// for this Animation
|
||||
return -1;
|
||||
}
|
||||
|
||||
int duration = d->driver->animationDuration(animation);
|
||||
|
||||
AnimationState *state = new AnimationState;
|
||||
state->id = ++d->animId;
|
||||
state->item = item;
|
||||
state->animation = animation;
|
||||
state->curve = d->driver->animationCurve(animation);
|
||||
state->frames = qMax(1.0, frames * (duration / 1000.0));
|
||||
state->currentFrame = 0;
|
||||
state->interval = d->driver->animationDuration(animation) / qreal(state->frames);
|
||||
state->interval = qMax(MIN_TICK_RATE_INT, state->interval - (state->interval % MIN_TICK_RATE_INT));
|
||||
state->currentInterval = state->interval;
|
||||
state->qobj = dynamic_cast<QObject*>(item);
|
||||
|
||||
if (state->qobj) {
|
||||
//kDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!! got us an object!";
|
||||
disconnect(state->qobj, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(animatedItemDestroyed(QObject*)));
|
||||
connect(state->qobj, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(animatedItemDestroyed(QObject*)));
|
||||
}
|
||||
|
||||
d->animatedItems[item] = state;
|
||||
d->performAnimation(0, state);
|
||||
|
||||
if (!d->timerId) {
|
||||
d->timerId = startTimer(MIN_TICK_RATE);
|
||||
d->time.restart();
|
||||
}
|
||||
|
||||
return state->id;
|
||||
}
|
||||
|
||||
int Animator::moveItem(QGraphicsItem *item, Movement movement, const QPoint &destination)
|
||||
{
|
||||
//kDebug();
|
||||
QMap<QGraphicsItem*, MovementState*>::iterator it = d->movingItems.find(item);
|
||||
if (it != d->movingItems.end()) {
|
||||
delete it.value();
|
||||
d->movingItems.erase(it);
|
||||
}
|
||||
|
||||
int frames = d->driver->movementAnimationFps(movement);
|
||||
if (frames <= 1) {
|
||||
// evidently this animator doesn't have an implementation
|
||||
// for this Animation
|
||||
return -1;
|
||||
}
|
||||
|
||||
MovementState *state = new MovementState;
|
||||
state->id = ++d->animId;
|
||||
state->destination = destination;
|
||||
state->start = item->pos().toPoint();
|
||||
state->item = item;
|
||||
state->movement = movement;
|
||||
state->curve = d->driver->movementAnimationCurve(movement);
|
||||
//TODO: variance in times based on the value of animation
|
||||
int duration = d->driver->movementAnimationDuration(movement);
|
||||
state->frames = qMax(1.0, frames * (duration / 1000.0));
|
||||
state->currentFrame = 0;
|
||||
state->interval = duration / qreal(state->frames);
|
||||
state->interval = qMax(MIN_TICK_RATE_INT, state->interval - (state->interval % MIN_TICK_RATE_INT));
|
||||
// state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
|
||||
// kDebug() << "interval of" << state->interval << state->frames << duration << frames;
|
||||
state->currentInterval = state->interval;
|
||||
state->qobj = dynamic_cast<QObject*>(item);
|
||||
|
||||
if (state->qobj) {
|
||||
disconnect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(movingItemDestroyed(QObject*)));
|
||||
connect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(movingItemDestroyed(QObject*)));
|
||||
}
|
||||
|
||||
d->movingItems[item] = state;
|
||||
d->performMovement(0, state);
|
||||
|
||||
if (!d->timerId) {
|
||||
d->timerId = startTimer(MIN_TICK_RATE);
|
||||
d->time.restart();
|
||||
}
|
||||
|
||||
return state->id;
|
||||
}
|
||||
|
||||
int Animator::customAnimation(int frames, int duration, Animator::CurveShape curve,
|
||||
QObject *receiver, const char *slot)
|
||||
{
|
||||
if (frames < 1 || duration < 1 || !receiver || !slot) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CustomAnimationState *state = new CustomAnimationState;
|
||||
state->id = ++d->animId;
|
||||
state->frames = frames;
|
||||
state->currentFrame = 0;
|
||||
state->curve = curve;
|
||||
state->interval = duration / qreal(state->frames);
|
||||
state->interval = qMax(MIN_TICK_RATE_INT, state->interval - (state->interval % MIN_TICK_RATE_INT));
|
||||
state->currentInterval = state->interval;
|
||||
state->receiver = receiver;
|
||||
state->slot = qstrdup(slot);
|
||||
|
||||
d->customAnims[state->id] = state;
|
||||
|
||||
disconnect(receiver, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(customAnimReceiverDestroyed(QObject*)));
|
||||
connect(receiver, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(customAnimReceiverDestroyed(QObject*)));
|
||||
|
||||
// try with only progress as argument
|
||||
if (!QMetaObject::invokeMethod(receiver, slot, Q_ARG(qreal, 0))) {
|
||||
//try to pass also the animation id
|
||||
QMetaObject::invokeMethod(receiver, slot, Q_ARG(qreal, 0), Q_ARG(int, state->id));
|
||||
}
|
||||
|
||||
if (!d->timerId) {
|
||||
d->timerId = startTimer(MIN_TICK_RATE);
|
||||
d->time.restart();
|
||||
}
|
||||
|
||||
return state->id;
|
||||
}
|
||||
|
||||
void Animator::stopCustomAnimation(int id)
|
||||
{
|
||||
QMap<int, CustomAnimationState*>::iterator it = d->customAnims.find(id);
|
||||
if (it != d->customAnims.end()) {
|
||||
delete [] it.value()->slot;
|
||||
delete it.value();
|
||||
d->customAnims.erase(it);
|
||||
}
|
||||
//kDebug() << "stopCustomAnimation(AnimId " << id << ") done";
|
||||
}
|
||||
|
||||
void Animator::stopItemAnimation(int id)
|
||||
{
|
||||
QMutableMapIterator<QGraphicsItem*, AnimationState*> it(d->animatedItems);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value()->id == id) {
|
||||
delete it.value();
|
||||
it.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::stopItemMovement(int id)
|
||||
{
|
||||
QMutableMapIterator<QGraphicsItem*, MovementState*> it(d->movingItems);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value()->id == id) {
|
||||
delete it.value();
|
||||
it.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Animator::animateElement(QGraphicsItem *item, Animation animation)
|
||||
{
|
||||
//kDebug() << "startElementAnimation(AnimId " << animation << ")";
|
||||
int frames = d->driver->elementAnimationFps(animation);
|
||||
int duration = d->driver->animationDuration(animation);
|
||||
|
||||
ElementAnimationState *state = new ElementAnimationState;
|
||||
state->item = item;
|
||||
state->curve = d->driver->elementAnimationCurve(animation);
|
||||
state->animation = animation;
|
||||
state->frames = qMax(1.0, frames * (duration / 1000.0));
|
||||
state->currentFrame = 0;
|
||||
state->interval = duration / qreal(state->frames);
|
||||
state->interval = qMax(MIN_TICK_RATE_INT, state->interval - (state->interval % MIN_TICK_RATE_INT));
|
||||
state->currentInterval = state->interval;
|
||||
state->id = ++d->animId;
|
||||
state->qobj = dynamic_cast<QObject*>(item);
|
||||
|
||||
if (state->qobj) {
|
||||
disconnect(state->qobj, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(animatedElementDestroyed(QObject*)));
|
||||
connect(state->qobj, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(animatedElementDestroyed(QObject*)));
|
||||
}
|
||||
|
||||
//kDebug() << "animateElement " << animation << ", interval: "
|
||||
// << state->interval << ", frames: " << state->frames;
|
||||
bool needTimer = true;
|
||||
if (state->frames < 1) {
|
||||
state->frames = 1;
|
||||
state->currentFrame = 1;
|
||||
needTimer = false;
|
||||
}
|
||||
|
||||
d->animatedElements[state->id] = state;
|
||||
|
||||
//kDebug() << "startElementAnimation(AnimId " << animation << ") returning " << state->id;
|
||||
if (needTimer && !d->timerId) {
|
||||
// start a 20fps timer;
|
||||
//TODO: should be started at the maximum frame rate needed only?
|
||||
d->timerId = startTimer(MIN_TICK_RATE);
|
||||
d->time.restart();
|
||||
}
|
||||
return state->id;
|
||||
}
|
||||
|
||||
void Animator::stopElementAnimation(int id)
|
||||
{
|
||||
QMap<int, ElementAnimationState*>::iterator it = d->animatedElements.find(id);
|
||||
if (it != d->animatedElements.end()) {
|
||||
delete it.value();
|
||||
d->animatedElements.erase(it);
|
||||
}
|
||||
//kDebug() << "stopElementAnimation(AnimId " << id << ") done";
|
||||
}
|
||||
|
||||
void Animator::setInitialPixmap(int id, const QPixmap &pixmap)
|
||||
{
|
||||
QMap<int, ElementAnimationState*>::iterator it = d->animatedElements.find(id);
|
||||
|
||||
if (it == d->animatedElements.end()) {
|
||||
kDebug() << "No entry found for id " << id;
|
||||
return;
|
||||
}
|
||||
|
||||
it.value()->pixmap = pixmap;
|
||||
}
|
||||
|
||||
QPixmap Animator::currentPixmap(int id)
|
||||
{
|
||||
QMap<int, ElementAnimationState*>::const_iterator it = d->animatedElements.find(id);
|
||||
|
||||
if (it == d->animatedElements.constEnd()) {
|
||||
//kDebug() << "Animator::currentPixmap(" << id << ") found no entry for it!";
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
ElementAnimationState *state = it.value();
|
||||
qreal progress = d->calculateProgress(state->currentFrame * state->interval,
|
||||
state->frames * state->interval,
|
||||
state->curve);
|
||||
//kDebug() << "Animator::currentPixmap(" << id << " at " << progress;
|
||||
|
||||
switch (state->animation) {
|
||||
case AppearAnimation:
|
||||
return d->driver->elementAppear(progress, state->pixmap);
|
||||
break;
|
||||
case DisappearAnimation:
|
||||
return d->driver->elementDisappear(progress, state->pixmap);
|
||||
break;
|
||||
case ActivateAnimation:
|
||||
break;
|
||||
}
|
||||
|
||||
return state->pixmap;
|
||||
}
|
||||
|
||||
bool Animator::isAnimating() const
|
||||
{
|
||||
return (!d->animatedItems.isEmpty() ||
|
||||
!d->movingItems.isEmpty() ||
|
||||
!d->animatedElements.isEmpty() ||
|
||||
!d->customAnims.isEmpty());
|
||||
}
|
||||
|
||||
void Animator::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
bool animationsRemain = false;
|
||||
int elapsed = MIN_TICK_RATE;
|
||||
if (d->time.elapsed() > elapsed) {
|
||||
elapsed = d->time.elapsed();
|
||||
}
|
||||
d->time.restart();
|
||||
//kDebug() << "timeEvent, elapsed time: " << elapsed;
|
||||
|
||||
foreach (AnimationState *state, d->animatedItems) {
|
||||
if (state->currentInterval <= elapsed) {
|
||||
// we need to step forward!
|
||||
state->currentFrame +=
|
||||
(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
|
||||
qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
|
||||
|
||||
if (state->currentFrame < state->frames) {
|
||||
qreal progress = d->calculateProgress(state->currentFrame * state->interval,
|
||||
state->frames * state->interval,
|
||||
state->curve);
|
||||
d->performAnimation(progress, state);
|
||||
state->currentInterval = state->interval;
|
||||
animationsRemain = true;
|
||||
} else {
|
||||
d->performAnimation(1, state);
|
||||
d->animatedItems.erase(d->animatedItems.find(state->item));
|
||||
emit animationFinished(state->item, state->animation);
|
||||
delete state;
|
||||
}
|
||||
} else {
|
||||
state->currentInterval -= elapsed;
|
||||
animationsRemain = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MovementState *state, d->movingItems) {
|
||||
if (state->currentInterval <= elapsed) {
|
||||
// we need to step forward!
|
||||
state->currentFrame +=
|
||||
(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
|
||||
qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
|
||||
|
||||
if (state->currentFrame < state->frames) {
|
||||
//kDebug() << "movement";
|
||||
qreal progress = d->calculateProgress(state->currentFrame * state->interval,
|
||||
state->frames * state->interval,
|
||||
state->curve);
|
||||
d->performMovement(progress, state);
|
||||
animationsRemain = true;
|
||||
} else {
|
||||
//kDebug() << "movement";
|
||||
d->performMovement(1, state);
|
||||
d->movingItems.erase(d->movingItems.find(state->item));
|
||||
emit movementFinished(state->item);
|
||||
delete state;
|
||||
}
|
||||
} else {
|
||||
state->currentInterval -= elapsed;
|
||||
animationsRemain = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ElementAnimationState *state, d->animatedElements) {
|
||||
if (state->currentFrame == state->frames) {
|
||||
//kDebug() << "skipping" << state->id << "as its already at frame"
|
||||
// << state->currentFrame << "of" << state->frames;
|
||||
// since we keep element animations around until they are
|
||||
// removed, we will end up with finished animations in the queue;
|
||||
// just skip them
|
||||
//TODO: should we move them to a separate QMap?
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state->currentInterval <= elapsed) {
|
||||
// we need to step forward!
|
||||
/*kDebug() << "stepping forwards element anim " << state->id
|
||||
<< " from " << state->currentFrame
|
||||
<< " by " << qMax(1, elapsed / state->interval) << " to "
|
||||
<< state->currentFrame + qMax(1, elapsed / state->interval) << endl;*/
|
||||
state->currentFrame +=
|
||||
(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
|
||||
qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
|
||||
|
||||
state->item->update();
|
||||
if (state->currentFrame < state->frames) {
|
||||
state->currentInterval = state->interval;
|
||||
animationsRemain = true;
|
||||
} else {
|
||||
d->animatedElements.remove(state->id);
|
||||
emit elementAnimationFinished(state->id);
|
||||
delete state;
|
||||
}
|
||||
} else {
|
||||
state->currentInterval -= elapsed;
|
||||
animationsRemain = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CustomAnimationState *state, d->customAnims) {
|
||||
if (state->currentInterval <= elapsed) {
|
||||
// advance the frame
|
||||
state->currentFrame +=
|
||||
(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
|
||||
qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
|
||||
/*kDebug() << "custom anim for" << state->receiver
|
||||
<< "to slot" << state->slot
|
||||
<< "with interval of" << state->interval
|
||||
<< "at frame" << state->currentFrame;*/
|
||||
|
||||
if (state->currentFrame < state->frames) {
|
||||
//kDebug () << "not the final frame";
|
||||
//TODO: calculate a proper interval based on the curve
|
||||
state->currentInterval = state->interval;
|
||||
animationsRemain = true;
|
||||
// signal the object
|
||||
// try with only progress as argument
|
||||
qreal progress = d->calculateProgress(state->currentFrame * state->interval,
|
||||
state->frames * state->interval,
|
||||
state->curve);
|
||||
if (!QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, progress))) {
|
||||
//if fails try to add the animation id
|
||||
QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, progress),
|
||||
Q_ARG(int, state->id));
|
||||
}
|
||||
} else {
|
||||
if (!QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, 1))) {
|
||||
QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, 1), Q_ARG(int, state->id));
|
||||
}
|
||||
d->customAnims.erase(d->customAnims.find(state->id));
|
||||
emit customAnimationFinished(state->id);
|
||||
delete [] state->slot;
|
||||
delete state;
|
||||
}
|
||||
} else {
|
||||
state->currentInterval -= elapsed;
|
||||
animationsRemain = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!animationsRemain && d->timerId) {
|
||||
killTimer(d->timerId);
|
||||
d->timerId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimatorPrivate::init(Animator *q)
|
||||
{
|
||||
//FIXME: usage between different applications?
|
||||
KConfig c("plasmarc");
|
||||
KConfigGroup cg(&c, "Animator");
|
||||
QString pluginName = cg.readEntry("driver", "default");
|
||||
|
||||
if (!pluginName.isEmpty()) {
|
||||
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(pluginName);
|
||||
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Animator", constraint);
|
||||
|
||||
if (!offers.isEmpty()) {
|
||||
QString error;
|
||||
|
||||
KPluginLoader plugin(*offers.first());
|
||||
|
||||
if (Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
|
||||
driver = offers.first()->createInstance<Plasma::AnimationDriver>(0, QVariantList(), &error);
|
||||
}
|
||||
|
||||
if (!driver) {
|
||||
kDebug() << "Could not load requested animator "
|
||||
<< offers.first() << ". Error given: " << error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!driver) {
|
||||
driver = new AnimationDriver(q);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#include <animator.moc>
|
180
animator.h
Normal file
180
animator.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
|
||||
* 2007 Alexis Ménard <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_ANIMATOR_H
|
||||
#define PLASMA_ANIMATOR_H
|
||||
|
||||
#include <QtGui/QImage>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
|
||||
class QGraphicsItem;
|
||||
class QTimeLine;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class AnimatorPrivate;
|
||||
|
||||
/**
|
||||
* @class Animator plasma/animator.h <Plasma/Animator>
|
||||
*
|
||||
* @short A system for applying effects to Plasma elements
|
||||
*/
|
||||
class PLASMA_EXPORT Animator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(Animation)
|
||||
Q_ENUMS(CurveShape)
|
||||
Q_ENUMS(Movement)
|
||||
|
||||
public:
|
||||
|
||||
enum Animation {
|
||||
AppearAnimation = 0, /*<< Animate the appearance of an element */
|
||||
DisappearAnimation, /*<< Animate the disappearance of an element */
|
||||
ActivateAnimation /*<< When something is activated or launched,
|
||||
such as an app icon being clicked */
|
||||
};
|
||||
|
||||
enum CurveShape {
|
||||
EaseInCurve = 0,
|
||||
EaseOutCurve,
|
||||
EaseInOutCurve,
|
||||
LinearCurve
|
||||
};
|
||||
|
||||
enum Movement {
|
||||
SlideInMovement = 0,
|
||||
SlideOutMovement,
|
||||
FastSlideInMovement,
|
||||
FastSlideOutMovement
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton accessor
|
||||
**/
|
||||
static Animator *self();
|
||||
|
||||
/**
|
||||
* Starts a standard animation on a QGraphicsItem.
|
||||
*
|
||||
* @arg item the item to animate in some fashion
|
||||
* @arg anim the type of animation to perform
|
||||
* @return the id of the animation
|
||||
**/
|
||||
Q_INVOKABLE int animateItem(QGraphicsItem *item, Animation anim);
|
||||
|
||||
/**
|
||||
* Stops an item animation before the animation is complete.
|
||||
* Note that it is not necessary to call
|
||||
* this on normal completion of the animation.
|
||||
*
|
||||
* @arg id the id of the animation as returned by animateItem
|
||||
*/
|
||||
Q_INVOKABLE void stopItemAnimation(int id);
|
||||
|
||||
/**
|
||||
* Starts a standard animation on a QGraphicsItem.
|
||||
*
|
||||
* @arg item the item to animate in some fashion
|
||||
* @arg anim the type of animation to perform
|
||||
* @return the id of the animation
|
||||
**/
|
||||
Q_INVOKABLE int moveItem(QGraphicsItem *item, Movement movement, const QPoint &destination);
|
||||
|
||||
/**
|
||||
* Stops an item movement before the animation is complete.
|
||||
* Note that it is not necessary to call
|
||||
* this on normal completion of the animation.
|
||||
*
|
||||
* @arg id the id of the animation as returned by moveItem
|
||||
*/
|
||||
Q_INVOKABLE void stopItemMovement(int id);
|
||||
|
||||
/**
|
||||
* Starts a custom animation, preventing the need to create a timeline
|
||||
* with its own timer tick.
|
||||
*
|
||||
* @arg frames the number of frames this animation should persist for
|
||||
* @arg duration the length, in milliseconds, the animation will take
|
||||
* @arg curve the curve applied to the frame rate
|
||||
* @arg receive the object that will handle the actual animation
|
||||
* @arg method the method name of slot to be invoked on each update.
|
||||
* It must take a qreal. So if the slot is animate(qreal),
|
||||
* pass in "animate" as the method parameter.
|
||||
* It has an optional integer paramenter that takes an
|
||||
* integer that reapresents the animation id, useful if
|
||||
* you want to manage multiple animations with a sigle slot
|
||||
*
|
||||
* @return an id that can be used to identify this animation.
|
||||
*/
|
||||
Q_INVOKABLE int customAnimation(int frames, int duration, Animator::CurveShape curve,
|
||||
QObject *receiver, const char *method);
|
||||
|
||||
/**
|
||||
* Stops a custom animation. Note that it is not necessary to call
|
||||
* this on object destruction, as custom animations associated with
|
||||
* a given QObject are cleaned up automatically on QObject destruction.
|
||||
*
|
||||
* @arg id the id of the animation as returned by customAnimation
|
||||
*/
|
||||
Q_INVOKABLE void stopCustomAnimation(int id);
|
||||
|
||||
Q_INVOKABLE int animateElement(QGraphicsItem *obj, Animation);
|
||||
Q_INVOKABLE void stopElementAnimation(int id);
|
||||
Q_INVOKABLE void setInitialPixmap(int id, const QPixmap &pixmap);
|
||||
Q_INVOKABLE QPixmap currentPixmap(int id);
|
||||
|
||||
/**
|
||||
* Can be used to query if there are other animations happening. This way
|
||||
* heavy operations can be delayed until all animations are finished.
|
||||
* @return true if there are animations going on.
|
||||
* @since 4.1
|
||||
*/
|
||||
Q_INVOKABLE bool isAnimating() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void animationFinished(QGraphicsItem *item, Plasma::Animator::Animation anim);
|
||||
void movementFinished(QGraphicsItem *item);
|
||||
void elementAnimationFinished(int id);
|
||||
void customAnimationFinished(int id);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event);
|
||||
|
||||
private:
|
||||
friend class AnimatorSingleton;
|
||||
explicit Animator(QObject * parent = 0);
|
||||
~Animator();
|
||||
|
||||
Q_PRIVATE_SLOT(d, void animatedItemDestroyed(QObject*))
|
||||
Q_PRIVATE_SLOT(d, void movingItemDestroyed(QObject*))
|
||||
Q_PRIVATE_SLOT(d, void animatedElementDestroyed(QObject*))
|
||||
Q_PRIVATE_SLOT(d, void customAnimReceiverDestroyed(QObject*))
|
||||
|
||||
AnimatorPrivate * const d;
|
||||
};
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#endif
|
||||
|
1957
applet.cpp
Normal file
1957
applet.cpp
Normal file
File diff suppressed because it is too large
Load Diff
857
applet.h
Normal file
857
applet.h
Normal file
@ -0,0 +1,857 @@
|
||||
/*
|
||||
* 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 <QtGui/QGraphicsItem>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QGraphicsWidget>
|
||||
|
||||
#include <KDE/KConfigGroup>
|
||||
#include <KDE/KGenericFactory>
|
||||
#include <KDE/KPluginInfo>
|
||||
#include <KDE/KShortcut>
|
||||
|
||||
#include <plasma/configloader.h>
|
||||
#include <plasma/packagestructure.h>
|
||||
#include <plasma/plasma.h>
|
||||
#include <plasma/animator.h>
|
||||
#include <plasma/version.h>
|
||||
|
||||
class KConfigDialog;
|
||||
class QGraphicsView;
|
||||
class KActionCollection;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class AppletPrivate;
|
||||
class Containment;
|
||||
class Context;
|
||||
class DataEngine;
|
||||
class Extender;
|
||||
class ExtenderItem;
|
||||
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 tutorial on writing Applets using this class.
|
||||
*/
|
||||
class PLASMA_EXPORT Applet : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool hasConfigurationInterface READ hasConfigurationInterface)
|
||||
Q_PROPERTY(QString name READ name)
|
||||
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 configurationRequired READ configurationRequired WRITE setConfigurationRequired)
|
||||
Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)
|
||||
Q_PROPERTY(bool shouldConserveResources READ shouldConserveResources)
|
||||
|
||||
public:
|
||||
typedef QList<Applet*> List;
|
||||
typedef QHash<QString, Applet*> Dict;
|
||||
|
||||
/**
|
||||
* Description on how draw a background for the applet
|
||||
*/
|
||||
enum BackgroundHint {
|
||||
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_DECLARE_FLAGS(BackgroundHints, BackgroundHint)
|
||||
|
||||
~Applet();
|
||||
|
||||
/**
|
||||
* @return a package structure representing a Theme
|
||||
*/
|
||||
static PackageStructure::Ptr packageStructure();
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Returns a config group with the name provided. This ensures
|
||||
* that the group name is properly namespaced to avoid collision
|
||||
* with other applets that may be sharing this config file
|
||||
*
|
||||
* @param group the name of the group to access
|
||||
**/
|
||||
KConfigGroup config(const QString &group) 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
|
||||
**/
|
||||
const Package *package() const;
|
||||
|
||||
/**
|
||||
* Returns the view this widget is visible on, or 0 if none can be found.
|
||||
* @warning do NOT assume this will always return a view!
|
||||
* a null view probably means that either plasma isn't finished loading, or your applet is
|
||||
* on an activity that's not being shown anywhere.
|
||||
*/
|
||||
QGraphicsView *view() const;
|
||||
|
||||
/**
|
||||
* Maps a QRect from a view's coordinates to local coordinates.
|
||||
* @param view the view from which rect should be mapped
|
||||
* @param rect the rect to be mapped
|
||||
*/
|
||||
QRectF mapFromView(const QGraphicsView *view, const QRect &rect) const;
|
||||
|
||||
/**
|
||||
* Maps a QRectF from local coordinates to a view's coordinates.
|
||||
* @param view the view to which rect should be mapped
|
||||
* @param rect the rect to be mapped
|
||||
*/
|
||||
QRect mapToView(const QGraphicsView *view, const QRectF &rect) 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Returns the workspace context which the applet is operating in
|
||||
*/
|
||||
Context *context() 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.
|
||||
*
|
||||
* @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 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);
|
||||
|
||||
/**
|
||||
* Attempts to load an applet
|
||||
*
|
||||
* Returns a pointer to the applet if successful.
|
||||
* The caller takes responsibility for the applet, including
|
||||
* deleting it when no longer needed.
|
||||
*
|
||||
* @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
|
||||
**/
|
||||
static Applet *load(const QString &name, uint appletId = 0,
|
||||
const QVariantList &args = QVariantList());
|
||||
|
||||
/**
|
||||
* Attempts to load an applet
|
||||
*
|
||||
* Returns a pointer to the applet if successful.
|
||||
* The caller takes responsibility for the applet, including
|
||||
* deleting it when no longer needed.
|
||||
*
|
||||
* @param info KPluginInfo object for the desired applet
|
||||
* @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
|
||||
**/
|
||||
static Applet *load(const KPluginInfo &info, 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);
|
||||
|
||||
/**
|
||||
* This method is called when the interface should be painted.
|
||||
*
|
||||
* @param painter the QPainter to use to do the paintiner
|
||||
* @param option the style options object
|
||||
* @param contentsRect the rect to paint within; automatically adjusted for
|
||||
* the background, if any
|
||||
**/
|
||||
virtual void paintInterface(QPainter *painter,
|
||||
const QStyleOptionGraphicsItem *option,
|
||||
const QRect &contentsRect);
|
||||
|
||||
/**
|
||||
* Returns the user-visible name for the applet, as specified in the
|
||||
* .desktop file.
|
||||
*
|
||||
* @return the user-visible name for the applet.
|
||||
**/
|
||||
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;
|
||||
|
||||
void paintWindowFrame(QPainter *painter,
|
||||
const QStyleOptionGraphicsItem *option, QWidget *widget);
|
||||
|
||||
/**
|
||||
* 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 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
|
||||
*/
|
||||
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 BackgroundHints hints);
|
||||
|
||||
/**
|
||||
* @return BackgroundHints flags combination telling if the standard background is shown
|
||||
* and if it has a drop shadow
|
||||
*/
|
||||
BackgroundHints backgroundHints() const;
|
||||
|
||||
/**
|
||||
* @return true if this Applet is currently being used as a Containment, false otherwise
|
||||
*/
|
||||
bool isContainment() const;
|
||||
|
||||
/**
|
||||
* This method returns screen coordinates for the widget; this method can be somewhat
|
||||
* expensive and should ONLY be called when screen coordinates are required. For
|
||||
* example when positioning top level widgets on top of the view to create the
|
||||
* appearance of unit. This should NOT be used for popups (@see popupPosition) or
|
||||
* for normal widget use (use Plasma:: widgets or QGraphicsProxyWidget instead).
|
||||
*
|
||||
* @return a rect of the applet in screen coordinates.
|
||||
*/
|
||||
QRect screenRect() const;
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsItem
|
||||
**/
|
||||
int type() const;
|
||||
enum {
|
||||
Type = Plasma::AppletType
|
||||
};
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Gets called when and extender item has to be initialized after a plasma restart. If you
|
||||
* create ExtenderItems in your applet, you should implement this function to again create
|
||||
* the widget that should be shown in this extender item. This function might look something
|
||||
* like this:
|
||||
*
|
||||
* @code
|
||||
* SuperCoolWidget *widget = new SuperCoolWidget();
|
||||
* dataEngine("engine")->connectSource(item->config("dataSourceName"), widget);
|
||||
* item->setWidget(widget);
|
||||
* @endcode
|
||||
*
|
||||
* You can also add one or more custom qactions to this extender item in this function.
|
||||
*
|
||||
* Note that by default, not all ExtenderItems are persistent. Only items that are detached,
|
||||
* will have their configuration stored when plasma exits.
|
||||
*/
|
||||
virtual void initExtenderItem(ExtenderItem *item);
|
||||
|
||||
/**
|
||||
* @param parent the QGraphicsItem 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(QGraphicsItem *parent = 0,
|
||||
const QString &serviceId = QString(),
|
||||
uint appletId = 0);
|
||||
|
||||
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 hides when such an event is
|
||||
* triggered by an item it is displaying.
|
||||
*/
|
||||
void releaseVisualFocus();
|
||||
|
||||
/**
|
||||
* Emitted whenever the applet makes a geometry change, so that views
|
||||
* can coordinate themselves with these changes if they desire.
|
||||
*/
|
||||
void geometryChanged();
|
||||
|
||||
/**
|
||||
* Emitted by Applet subclasses when they change a sizeHint and wants to announce the change
|
||||
*/
|
||||
void sizeHintChanged(Qt::SizeHint which);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Sets the immutability type for this applet (not immutable,
|
||||
* user immutable or system immutable)
|
||||
* @arg 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.
|
||||
*/
|
||||
virtual void showConfigurationInterface();
|
||||
|
||||
/**
|
||||
* Causes this applet to raise above all other applets.
|
||||
*/
|
||||
void raise();
|
||||
|
||||
/**
|
||||
* Causes this applet to lower below all the other applets.
|
||||
*/
|
||||
void lower();
|
||||
|
||||
/**
|
||||
* 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 QGraphicsScene or has an particularly intensive
|
||||
* set of initialization routines to go through, consider implementing it
|
||||
* in this method instead of the constructor.
|
||||
**/
|
||||
virtual void init();
|
||||
|
||||
/**
|
||||
* Called when applet configuration values has changed.
|
||||
*/
|
||||
virtual void configChanged();
|
||||
|
||||
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
|
||||
*
|
||||
* 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 needsConfiguring true if the applet needs to be configured,
|
||||
* or false if it doesn't
|
||||
*/
|
||||
void setConfigurationRequired(bool needsConfiguring, const QString &reason = QString());
|
||||
|
||||
/**
|
||||
* Reimplement this method so provide a configuration interface,
|
||||
* parented to the supplied widget. Ownership of the widgets is passed
|
||||
* to the parent widget.
|
||||
*
|
||||
* @param parent the dialog which is the parent of the configuration
|
||||
* widgets
|
||||
*/
|
||||
virtual void createConfigurationInterface(KConfigDialog *parent);
|
||||
|
||||
/**
|
||||
* Called when any of the geometry constraints have been updated.
|
||||
*
|
||||
* This is always called prior to painting and should 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);
|
||||
|
||||
/**
|
||||
* Register the widgets that manage mouse clicks but you still want
|
||||
* to be able to drag the applet around when holding the mouse pointer
|
||||
* on that widget.
|
||||
*
|
||||
* Calling this results in an eventFilter being places on the widget.
|
||||
*
|
||||
* @param item the item to watch for mouse move
|
||||
*/
|
||||
void registerAsDragHandle(QGraphicsItem *item);
|
||||
|
||||
/**
|
||||
* Unregister a widget registered with registerAsDragHandle.
|
||||
*
|
||||
* @param item the item to unregister
|
||||
*/
|
||||
void unregisterAsDragHandle(QGraphicsItem *item);
|
||||
|
||||
/**
|
||||
* @param item the item to look for if it is registered or not
|
||||
* @return true if it is registered, false otherwise
|
||||
*/
|
||||
bool isRegisteredAsDragHandle(QGraphicsItem *item);
|
||||
|
||||
|
||||
/**
|
||||
* @return the extender of this applet.
|
||||
*/
|
||||
Extender *extender() const;
|
||||
|
||||
/**
|
||||
* @internal event filter; used for focus watching
|
||||
**/
|
||||
bool eventFilter(QObject *o, QEvent *e);
|
||||
|
||||
/**
|
||||
* @internal scene event filter; used to manage applet dragging
|
||||
*/
|
||||
bool sceneEventFilter (QGraphicsItem *watched, QEvent *event);
|
||||
|
||||
/**
|
||||
* @internal manage the mouse movement to drag the applet around
|
||||
*/
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
|
||||
|
||||
/**
|
||||
* @internal manage the mouse movement to drag the applet around
|
||||
*/
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsItem
|
||||
*/
|
||||
void focusInEvent(QFocusEvent *event);
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsItem
|
||||
*/
|
||||
void resizeEvent(QGraphicsSceneResizeEvent *event);
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsItem
|
||||
*/
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsItem
|
||||
*/
|
||||
QPainterPath shape() const;
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsLayoutItem
|
||||
*/
|
||||
QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF()) const;
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsLayoutItem
|
||||
*/
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsLayoutItem
|
||||
*/
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
|
||||
/**
|
||||
* Reimplemented from QObject
|
||||
*/
|
||||
void timerEvent (QTimerEvent *event);
|
||||
|
||||
private:
|
||||
Q_PRIVATE_SLOT(d, void setFocus())
|
||||
Q_PRIVATE_SLOT(d, void checkImmutability())
|
||||
Q_PRIVATE_SLOT(d, void themeChanged())
|
||||
Q_PRIVATE_SLOT(d, void appletAnimationComplete(QGraphicsItem *item,
|
||||
Plasma::Animator::Animation anim))
|
||||
Q_PRIVATE_SLOT(d, void selectItemToDestroy())
|
||||
Q_PRIVATE_SLOT(d, void updateRect(const QRectF& rect))
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsItem
|
||||
**/
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
|
||||
|
||||
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 PopupApplet;
|
||||
friend class PopupAppletPrivate;
|
||||
|
||||
friend class Extender;
|
||||
friend class ExtenderItem;
|
||||
};
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::Applet::BackgroundHints)
|
||||
|
||||
/**
|
||||
* 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
|
567
configloader.cpp
Normal file
567
configloader.cpp
Normal file
@ -0,0 +1,567 @@
|
||||
/*
|
||||
* 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 <QColor>
|
||||
#include <QFont>
|
||||
#include <QHash>
|
||||
#include <QXmlContentHandler>
|
||||
#include <QXmlInputSource>
|
||||
#include <QXmlSimpleReader>
|
||||
|
||||
#include <KDebug>
|
||||
#include <KUrl>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class ConfigLoaderPrivate
|
||||
{
|
||||
public:
|
||||
~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;
|
||||
}
|
||||
|
||||
KUrl::List *newUrlList()
|
||||
{
|
||||
KUrl::List *v = new KUrl::List;
|
||||
urllists.append(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void parse(ConfigLoader *loader, QIODevice *xml);
|
||||
|
||||
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<KUrl::List *> urllists;
|
||||
QString baseGroup;
|
||||
QStringList groups;
|
||||
QHash<QString, QString> keysToNames;
|
||||
};
|
||||
|
||||
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);
|
||||
} else if (name == "type") {
|
||||
m_type = attrs.value(i).toLower();
|
||||
} else if (name == "key") {
|
||||
m_key = attrs.value(i);
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
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()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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(),
|
||||
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<qint32> 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(',');
|
||||
while (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(',');
|
||||
while (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(',');
|
||||
while (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(",");
|
||||
KUrl::List 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]);
|
||||
}
|
||||
|
||||
bool ConfigLoader::hasGroup(const QString &group) const
|
||||
{
|
||||
return d->groups.contains(group);
|
||||
}
|
||||
|
||||
QStringList ConfigLoader::groupList() const
|
||||
{
|
||||
return d->groups;
|
||||
}
|
||||
|
||||
} // Plasma namespace
|
137
configloader.h
Normal file
137
configloader.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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 <KDE/KConfigGroup>
|
||||
#include <KDE/KConfigSkeleton>
|
||||
#include <KDE/KSharedConfig>
|
||||
|
||||
#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.
|
||||
*
|
||||
* @arg group the group in the config file to look in
|
||||
* @arg key the configuration key to find
|
||||
* @return the associated KConfigSkeletonItem, or 0 if none
|
||||
*/
|
||||
KConfigSkeletonItem *findItem(const QString &group, const QString &key);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private:
|
||||
ConfigLoaderPrivate * const d;
|
||||
};
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#endif //multiple inclusion guard
|
1869
containment.cpp
Normal file
1869
containment.cpp
Normal file
File diff suppressed because it is too large
Load Diff
508
containment.h
Normal file
508
containment.h
Normal file
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* 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 PLASMA_CONTAINMENT_H
|
||||
#define PLASMA_CONTAINMENT_H
|
||||
|
||||
#include <QtGui/QGraphicsItem>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QStyleOptionGraphicsItem>
|
||||
|
||||
#include <kplugininfo.h>
|
||||
#include <ksharedconfig.h>
|
||||
#include <kgenericfactory.h>
|
||||
|
||||
#include <plasma/applet.h>
|
||||
#include <plasma/animator.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class AppletHandle;
|
||||
class DataEngine;
|
||||
class Package;
|
||||
class Corona;
|
||||
class View;
|
||||
class Wallpaper;
|
||||
class ContainmentPrivate;
|
||||
|
||||
/**
|
||||
* @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:
|
||||
class StyleOption : public QStyleOptionGraphicsItem
|
||||
{
|
||||
public:
|
||||
explicit StyleOption();
|
||||
explicit StyleOption(const StyleOption &other);
|
||||
explicit StyleOption(const QStyleOptionGraphicsItem &other);
|
||||
|
||||
enum StyleOptionType {
|
||||
Type = SO_CustomBase + 1
|
||||
};
|
||||
enum StyleOptionVersion {
|
||||
Version = QStyleOptionGraphicsItem::Version + 1
|
||||
};
|
||||
|
||||
/**
|
||||
* The View, if any, that this containment is currently
|
||||
* being rendered into. Note: this may be NULL, so be
|
||||
* sure to check it before using it!
|
||||
*/
|
||||
Plasma::View *view;
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @param parent the QGraphicsItem 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(QGraphicsItem *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 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 listContainments(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 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
|
||||
*/
|
||||
void setScreen(int screen);
|
||||
|
||||
/**
|
||||
* @return the screen number this containment is serving as the desktop for
|
||||
* or -1 if none
|
||||
*/
|
||||
int screen() const;
|
||||
|
||||
/**
|
||||
* @reimplemented from Applet
|
||||
*/
|
||||
void save(KConfigGroup &group) const;
|
||||
|
||||
/**
|
||||
* @reimplemented from Applet
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* Sets the open or closed state of the Containment's toolbox
|
||||
*
|
||||
* @arg open true to open the ToolBox, false to close it
|
||||
*/
|
||||
void setToolBoxOpen(bool open);
|
||||
|
||||
/**
|
||||
* Open the Containment's toolbox
|
||||
*/
|
||||
void openToolBox();
|
||||
|
||||
/**
|
||||
* Closes Containment's toolbox
|
||||
*/
|
||||
void closeToolBox();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Plasma::Wallpaper *wallpaper() const;
|
||||
|
||||
/**
|
||||
* Sets the current activity by name
|
||||
*
|
||||
* @param activity the name of the activity; if it doesn't exist in the
|
||||
* semantic store, it will be created.
|
||||
*/
|
||||
void setActivity(const QString &activity);
|
||||
|
||||
/**
|
||||
* @return the current activity associated with this activity
|
||||
*/
|
||||
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
|
||||
* This implementation does nothing, reimplement in containments that needs it
|
||||
*
|
||||
* @param pos point where to show the drop target
|
||||
*/
|
||||
virtual void showDropZone(const QPoint pos);
|
||||
|
||||
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 containment requests zooming in or out one step.
|
||||
*/
|
||||
void zoomRequested(Plasma::Containment *containment, Plasma::ZoomDirection direction);
|
||||
|
||||
/**
|
||||
* Emitted when the user clicks on the toolbox
|
||||
*/
|
||||
void toolBoxToggled();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* The activity associated to this containemnt has changed
|
||||
*/
|
||||
void contextChanged(Plasma::Context *context);
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Informs the Corona as to what position it is in. This is informational
|
||||
* only, as the Corona doesn't change it's 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();
|
||||
|
||||
/**
|
||||
* switch keyboard focus to the next of our applets
|
||||
*/
|
||||
void focusNextApplet();
|
||||
|
||||
/**
|
||||
* switch keyboard focus to the previous one of our applets
|
||||
*/
|
||||
void focusPreviousApplet();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @arg confirm whether or not confirmation from the user should be requested
|
||||
*/
|
||||
void destroy(bool confirm);
|
||||
|
||||
/**
|
||||
* @reimplemented from Plasma::Applet
|
||||
*/
|
||||
void showConfigurationInterface();
|
||||
protected:
|
||||
/**
|
||||
* Sets the type of this containment.
|
||||
*/
|
||||
void setContainmentType(Containment::Type type);
|
||||
|
||||
/**
|
||||
* Sets whether wallpaper is painted or not.
|
||||
*/
|
||||
void setDrawWallpaper(bool drawWallpaper);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
|
||||
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
void wheelEvent(QGraphicsSceneWheelEvent *event);
|
||||
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event);
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
||||
|
||||
/**
|
||||
* @reimplemented from QGraphicsItem
|
||||
*/
|
||||
void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
|
||||
|
||||
/**
|
||||
* @reimplemented from QGraphicsItem
|
||||
*/
|
||||
void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
|
||||
|
||||
/**
|
||||
* @reimplemented from QGraphicsItem
|
||||
*/
|
||||
void dropEvent(QGraphicsSceneDragDropEvent *event);
|
||||
|
||||
/**
|
||||
* @reimplemented from QGraphicsItem
|
||||
*/
|
||||
void resizeEvent(QGraphicsSceneResizeEvent *event);
|
||||
|
||||
private:
|
||||
Q_PRIVATE_SLOT(d, void appletDestroyed(QObject*))
|
||||
Q_PRIVATE_SLOT(d, void containmentAppletAnimationComplete(QGraphicsItem *item,
|
||||
Plasma::Animator::Animation anim))
|
||||
Q_PRIVATE_SLOT(d, void triggerShowAddWidgets())
|
||||
Q_PRIVATE_SLOT(d, void handleDisappeared(AppletHandle *handle))
|
||||
Q_PRIVATE_SLOT(d, void positionToolBox())
|
||||
Q_PRIVATE_SLOT(d, void zoomIn())
|
||||
Q_PRIVATE_SLOT(d, void zoomOut())
|
||||
Q_PRIVATE_SLOT(d, void toggleDesktopImmutability())
|
||||
|
||||
friend class Applet;
|
||||
friend class AppletPrivate;
|
||||
friend class CoronaPrivate;
|
||||
friend class ContainmentPrivate;
|
||||
ContainmentPrivate *const d;
|
||||
};
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#endif // multiple inclusion guard
|
76
context.cpp
Normal file
76
context.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2008 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 "context.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class ContextPrivate
|
||||
{
|
||||
public:
|
||||
QString activity;
|
||||
};
|
||||
|
||||
Context::Context(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new ContextPrivate)
|
||||
{
|
||||
//TODO: look up activity in Nepomuk
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Context::createActivity(const QString &name)
|
||||
{
|
||||
}
|
||||
|
||||
QStringList Context::listActivities() const
|
||||
{
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
void Context::setCurrentActivity(const QString &name)
|
||||
{
|
||||
if (d->activity == name || name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->activity = name;
|
||||
emit activityChanged(this);
|
||||
emit changed(this);
|
||||
|
||||
QStringList activities = listActivities();
|
||||
if (!activities.contains(name)) {
|
||||
createActivity(name);
|
||||
}
|
||||
}
|
||||
|
||||
QString Context::currentActivity() const
|
||||
{
|
||||
return d->activity;
|
||||
}
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#include "context.moc"
|
||||
|
61
context.h
Normal file
61
context.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2008 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_CONTEXT_H
|
||||
#define PLASMA_CONTEXT_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include "plasma_export.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class ContextPrivate;
|
||||
|
||||
class PLASMA_EXPORT Context : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Context(QObject *parent = 0);
|
||||
~Context();
|
||||
|
||||
void createActivity(const QString &name);
|
||||
QStringList listActivities() const;
|
||||
|
||||
void setCurrentActivity(const QString &name);
|
||||
QString currentActivity() const;
|
||||
|
||||
//TODO: location
|
||||
|
||||
Q_SIGNALS:
|
||||
void changed(Plasma::Context *context);
|
||||
void activityChanged(Plasma::Context *context);
|
||||
void locationChanged(Plasma::Context *context);
|
||||
|
||||
private:
|
||||
ContextPrivate * const d;
|
||||
};
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#endif // multiple inclusion guard
|
||||
|
526
corona.cpp
Normal file
526
corona.cpp
Normal file
@ -0,0 +1,526 @@
|
||||
/*
|
||||
* Copyright 2007 Matt Broadstone <mbroadst@gmail.com>
|
||||
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
|
||||
* Copyright 2007 Riccardo Iaconelli <riccardo@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 <QApplication>
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsSceneDragDropEvent>
|
||||
#include <QGraphicsGridLayout>
|
||||
#include <QMimeData>
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
#include <KDebug>
|
||||
#include <KGlobal>
|
||||
#include <KLocale>
|
||||
#include <KMimeType>
|
||||
|
||||
#include "containment.h"
|
||||
#include "view.h"
|
||||
#include "private/applet_p.h"
|
||||
#include "tooltipmanager.h"
|
||||
|
||||
using namespace Plasma;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
// constant controlling how long between requesting a configuration sync
|
||||
// and one happening should occur. currently 10 seconds
|
||||
const int CONFIG_SYNC_TIMEOUT = 10000;
|
||||
|
||||
class CoronaPrivate
|
||||
{
|
||||
public:
|
||||
CoronaPrivate(Corona *corona)
|
||||
: q(corona),
|
||||
immutability(Mutable),
|
||||
mimetype("text/x-plasmoidservicename"),
|
||||
config(0),
|
||||
offscreenLayout(0)
|
||||
{
|
||||
if (KGlobal::hasMainComponent()) {
|
||||
configName = KGlobal::mainComponent().componentName() + "-appletsrc";
|
||||
} else {
|
||||
configName = "plasma-appletsrc";
|
||||
}
|
||||
}
|
||||
|
||||
~CoronaPrivate()
|
||||
{
|
||||
qDeleteAll(containments);
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
configSyncTimer.setSingleShot(true);
|
||||
QObject::connect(&configSyncTimer, SIGNAL(timeout()), q, SLOT(syncConfig()));
|
||||
}
|
||||
|
||||
void 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 updateContainmentImmutability()
|
||||
{
|
||||
foreach (Containment *c, containments) {
|
||||
// we need to tell each containment that immutability has been altered
|
||||
c->updateConstraints(ImmutableConstraint);
|
||||
}
|
||||
}
|
||||
|
||||
void 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 syncConfig()
|
||||
{
|
||||
q->config()->sync();
|
||||
emit q->configSynced();
|
||||
}
|
||||
|
||||
Containment *addContainment(const QString &name, const QVariantList &args,
|
||||
uint id, bool delayedInit)
|
||||
{
|
||||
QString pluginName = name;
|
||||
Containment *containment = 0;
|
||||
Applet *applet = 0;
|
||||
|
||||
//kDebug() << "Loading" << name << args << id;
|
||||
|
||||
if (pluginName.isEmpty()) {
|
||||
// default to the desktop containment
|
||||
pluginName = "desktop";
|
||||
}
|
||||
|
||||
if (pluginName != "null") {
|
||||
applet = Applet::load(pluginName, id, args);
|
||||
containment = dynamic_cast<Containment*>(applet);
|
||||
}
|
||||
|
||||
if (!containment) {
|
||||
kDebug() << "loading of containment" << name << "failed.";
|
||||
|
||||
// in case we got a non-Containment from Applet::loadApplet or
|
||||
// a null containment was requested
|
||||
delete applet;
|
||||
containment = new Containment(0, 0, id);
|
||||
|
||||
if (pluginName == "null") {
|
||||
containment->setDrawWallpaper(false);
|
||||
}
|
||||
|
||||
// we want to provide something and don't care about the failure to launch
|
||||
containment->setFailedToLaunch(false);
|
||||
containment->setFormFactor(Plasma::Planar);
|
||||
}
|
||||
|
||||
static_cast<Applet*>(containment)->d->setIsContainment(true);
|
||||
q->addItem(containment);
|
||||
|
||||
if (!delayedInit) {
|
||||
containment->init();
|
||||
containment->updateConstraints(Plasma::StartupCompletedConstraint);
|
||||
KConfigGroup cg = containment->config();
|
||||
containment->save(cg);
|
||||
q->requestConfigSync();
|
||||
}
|
||||
|
||||
containments.append(containment);
|
||||
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*)));
|
||||
|
||||
if (!delayedInit) {
|
||||
emit q->containmentAdded(containment);
|
||||
}
|
||||
|
||||
return containment;
|
||||
}
|
||||
|
||||
Corona *q;
|
||||
ImmutabilityType immutability;
|
||||
QString mimetype;
|
||||
QString configName;
|
||||
KSharedConfigPtr config;
|
||||
QTimer configSyncTimer;
|
||||
QList<Containment*> containments;
|
||||
QGraphicsGridLayout *offscreenLayout;
|
||||
};
|
||||
|
||||
Corona::Corona(QObject *parent)
|
||||
: QGraphicsScene(parent),
|
||||
d(new CoronaPrivate(this))
|
||||
{
|
||||
d->init();
|
||||
ToolTipManager::self()->m_corona = this;
|
||||
//setViewport(new QGLWidget(QGLFormat(QGL::StencilBuffer | QGL::AlphaChannel)));
|
||||
}
|
||||
|
||||
Corona::~Corona()
|
||||
{
|
||||
// FIXME: Same fix as in Plasma::View - make sure that when the focused widget is
|
||||
// destroyed we don't try to transfer it to something that's already been
|
||||
// deleted.
|
||||
clearFocus();
|
||||
|
||||
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);
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Corona::setAppletMimeType(const QString &type)
|
||||
{
|
||||
d->mimetype = type;
|
||||
}
|
||||
|
||||
QString Corona::appletMimeType()
|
||||
{
|
||||
return d->mimetype;
|
||||
}
|
||||
|
||||
void Corona::saveLayout(const QString &configName) const
|
||||
{
|
||||
KSharedConfigPtr c;
|
||||
|
||||
if (configName.isEmpty() || configName == d->configName) {
|
||||
c = config();
|
||||
} else {
|
||||
c = KSharedConfig::openConfig(configName);
|
||||
}
|
||||
|
||||
d->saveLayout(c);
|
||||
}
|
||||
|
||||
void Corona::requestConfigSync()
|
||||
{
|
||||
// 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::initializeLayout(const QString &configName)
|
||||
{
|
||||
clearContainments();
|
||||
loadLayout(configName);
|
||||
|
||||
if (d->containments.isEmpty()) {
|
||||
loadDefaultLayout();
|
||||
if (!d->containments.isEmpty()) {
|
||||
requestConfigSync();
|
||||
}
|
||||
}
|
||||
|
||||
if (config()->isImmutable()) {
|
||||
d->updateContainmentImmutability();
|
||||
}
|
||||
|
||||
KConfigGroup coronaConfig(config(), "General");
|
||||
setImmutability((ImmutabilityType)coronaConfig.readEntry("immutability", (int)Mutable));
|
||||
}
|
||||
|
||||
void Corona::loadLayout(const QString &configName)
|
||||
{
|
||||
KSharedConfigPtr c;
|
||||
|
||||
if (configName.isEmpty() || configName == d->configName) {
|
||||
c = config();
|
||||
} else {
|
||||
c = KSharedConfig::openConfig(configName);
|
||||
}
|
||||
|
||||
KConfigGroup containments(config(), "Containments");
|
||||
|
||||
foreach (const QString &group, containments.groupList()) {
|
||||
KConfigGroup containmentConfig(&containments, group);
|
||||
|
||||
if (containmentConfig.entryMap().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int cid = group.toUInt();
|
||||
//kDebug() << "got a containment in the config, trying to make a" << containmentConfig.readEntry("plugin", QString()) << "from" << group;
|
||||
Containment *c = d->addContainment(containmentConfig.readEntry("plugin", QString()), QVariantList(),
|
||||
cid, true);
|
||||
if (!c) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//addItem(c);
|
||||
c->init();
|
||||
c->restore(containmentConfig);
|
||||
}
|
||||
|
||||
foreach (Containment *containment, d->containments) {
|
||||
QString cid = QString::number(containment->id());
|
||||
KConfigGroup containmentConfig(&containments, cid);
|
||||
|
||||
foreach (Applet *applet, containment->applets()) {
|
||||
applet->init();
|
||||
// We have to flush the applet constraints manually
|
||||
applet->flushPendingConstraintsEvents();
|
||||
}
|
||||
|
||||
containment->updateConstraints(Plasma::StartupCompletedConstraint);
|
||||
containment->flushPendingConstraintsEvents();
|
||||
emit containmentAdded(containment);
|
||||
}
|
||||
}
|
||||
|
||||
Containment *Corona::containmentForScreen(int screen) const
|
||||
{
|
||||
foreach (Containment *containment, d->containments) {
|
||||
if (containment->screen() == screen &&
|
||||
(containment->containmentType() == Containment::DesktopContainment ||
|
||||
containment->containmentType() >= Containment::CustomContainment)) {
|
||||
return containment;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return d->config;
|
||||
}
|
||||
|
||||
Containment *Corona::addContainment(const QString &name, const QVariantList &args)
|
||||
{
|
||||
return d->addContainment(name, args, 0, false);
|
||||
}
|
||||
|
||||
Containment *Corona::addContainmentDelayed(const QString &name, const QVariantList &args)
|
||||
{
|
||||
return d->addContainment(name, args, 0, true);
|
||||
}
|
||||
|
||||
void Corona::addOffscreenWidget(QGraphicsWidget *widget)
|
||||
{
|
||||
widget->setParentItem(0);
|
||||
if (!d->offscreenLayout) {
|
||||
kDebug() << "adding offscreen widget.";
|
||||
QGraphicsWidget *offscreenWidget = new QGraphicsWidget(0);
|
||||
addItem(offscreenWidget);
|
||||
d->offscreenLayout = new QGraphicsGridLayout(offscreenWidget);
|
||||
//FIXME: do this a nice way.
|
||||
offscreenWidget->setPos(-10000, -10000);
|
||||
offscreenWidget->setLayout(d->offscreenLayout);
|
||||
}
|
||||
|
||||
//check if the layout already contains this widget.
|
||||
//XXX: duplicated from removeOffscreenWidget()
|
||||
for (int i = 0; i < d->offscreenLayout->count(); i++) {
|
||||
QGraphicsWidget *foundWidget = dynamic_cast<QGraphicsWidget*>(d->offscreenLayout->itemAt(i));
|
||||
if (foundWidget == widget) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
d->offscreenLayout->addItem(widget, d->offscreenLayout->rowCount() + 1,
|
||||
d->offscreenLayout->columnCount() + 1);
|
||||
widget->update();
|
||||
}
|
||||
|
||||
void Corona::removeOffscreenWidget(QGraphicsWidget *widget)
|
||||
{
|
||||
if (!d->offscreenLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < d->offscreenLayout->count(); i++) {
|
||||
QGraphicsWidget *foundWidget = dynamic_cast<QGraphicsWidget*>(d->offscreenLayout->itemAt(i));
|
||||
if (foundWidget == widget) {
|
||||
d->offscreenLayout->removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Corona::numScreens() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QRect Corona::screenGeometry(int id) const
|
||||
{
|
||||
Q_UNUSED(id);
|
||||
if (views().isEmpty()) {
|
||||
return sceneRect().toRect();
|
||||
} else {
|
||||
QGraphicsView *v = views()[0];
|
||||
QRect r = sceneRect().toRect();
|
||||
r.moveTo(v->mapToGlobal(v->pos()));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
QRegion Corona::availableScreenRegion(int id) const
|
||||
{
|
||||
return QRegion(screenGeometry(id));
|
||||
}
|
||||
|
||||
QPoint Corona::popupPosition(const QGraphicsItem *item, const QSize &s)
|
||||
{
|
||||
QGraphicsView *v = viewFor(item);
|
||||
|
||||
if (!v) {
|
||||
return QPoint(0, 0);
|
||||
}
|
||||
|
||||
QPoint pos = v->mapFromScene(item->scenePos());
|
||||
pos = v->mapToGlobal(pos);
|
||||
//kDebug() << "==> position is" << item->scenePos() << v->mapFromScene(item->scenePos()) << pos;
|
||||
Plasma::View *pv = dynamic_cast<Plasma::View *>(v);
|
||||
|
||||
Plasma::Location loc = Floating;
|
||||
if (pv && pv->containment()) {
|
||||
loc = pv->containment()->location();
|
||||
}
|
||||
|
||||
switch (loc) {
|
||||
case BottomEdge:
|
||||
pos = QPoint(pos.x(), pos.y() - s.height());
|
||||
break;
|
||||
case TopEdge:
|
||||
pos = QPoint(pos.x(), pos.y() + (int)item->boundingRect().size().height());
|
||||
break;
|
||||
case LeftEdge:
|
||||
pos = QPoint(pos.x() + (int)item->boundingRect().size().width(), pos.y());
|
||||
break;
|
||||
case RightEdge:
|
||||
pos = QPoint(pos.x() - s.width(), pos.y());
|
||||
break;
|
||||
default:
|
||||
if (pos.y() - s.height() > 0) {
|
||||
pos = QPoint(pos.x(), pos.y() - s.height());
|
||||
} else {
|
||||
pos = QPoint(pos.x(), pos.y() + (int)item->boundingRect().size().height());
|
||||
}
|
||||
}
|
||||
|
||||
//are we out of screen?
|
||||
QRect screenRect =
|
||||
screenGeometry((pv && pv->containment()) ? pv->containment()->screen() : -1);
|
||||
//kDebug() << "==> rect for" << (pv ? pv->containment()->screen() : -1) << "is" << screenRect;
|
||||
|
||||
if (pos.rx() + s.width() > screenRect.right()) {
|
||||
pos.rx() -= ((pos.rx() + s.width()) - screenRect.right());
|
||||
}
|
||||
|
||||
if (pos.ry() + s.height() > screenRect.bottom()) {
|
||||
pos.ry() -= ((pos.ry() + s.height()) - screenRect.bottom());
|
||||
}
|
||||
|
||||
pos.rx() = qMax(0, pos.rx());
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Corona::loadDefaultLayout()
|
||||
{
|
||||
}
|
||||
|
||||
void Corona::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
|
||||
{
|
||||
QGraphicsScene::dragEnterEvent(event);
|
||||
}
|
||||
|
||||
void Corona::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
|
||||
{
|
||||
QGraphicsScene::dragLeaveEvent(event);
|
||||
}
|
||||
|
||||
void Corona::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
|
||||
{
|
||||
QGraphicsScene::dragMoveEvent(event);
|
||||
}
|
||||
|
||||
ImmutabilityType Corona::immutability() const
|
||||
{
|
||||
return d->immutability;
|
||||
}
|
||||
|
||||
void Corona::setImmutability(const ImmutabilityType immutable)
|
||||
{
|
||||
if (d->immutability == immutable ||
|
||||
d->immutability == SystemImmutable) {
|
||||
return;
|
||||
}
|
||||
|
||||
kDebug() << "setting immutability to" << immutable;
|
||||
d->immutability = immutable;
|
||||
d->updateContainmentImmutability();
|
||||
}
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#include "corona.moc"
|
||||
|
261
corona.h
Normal file
261
corona.h
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
|
||||
* Copyright 2007 Matt Broadstone <mbroadst@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_CORONA_H
|
||||
#define PLASMA_CORONA_H
|
||||
|
||||
#include <QtGui/QGraphicsScene>
|
||||
|
||||
#include <plasma/applet.h>
|
||||
#include <plasma/plasma.h>
|
||||
#include <plasma/plasma_export.h>
|
||||
|
||||
class QGraphicsGridLayout;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class Containment;
|
||||
class CoronaPrivate;
|
||||
|
||||
/**
|
||||
* @class Corona plasma/corona.h <Plasma/Corona>
|
||||
*
|
||||
* @short A QGraphicsScene for Plasma::Applets
|
||||
*/
|
||||
class PLASMA_EXPORT Corona : public QGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
//typedef QHash<QString, QList<Plasma::Applet*> > layouts;
|
||||
|
||||
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 all containments on this Corona
|
||||
*/
|
||||
QList<Containment*> containments() const;
|
||||
|
||||
/**
|
||||
* Clear the Corona from all applets.
|
||||
*/
|
||||
void clearContainments();
|
||||
|
||||
/**
|
||||
* Returns the config file used to store the configuration for this Corona
|
||||
*/
|
||||
KSharedConfig::Ptr config() const;
|
||||
|
||||
/**
|
||||
* Adds a Containment to the Corona
|
||||
*
|
||||
* @param name the plugin name for the containment, as given by
|
||||
* KPluginInfo::pluginName(). If an empty string is passed in, the defalt
|
||||
* 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
|
||||
*/
|
||||
Containment *addContainment(const QString &name, const QVariantList &args = QVariantList());
|
||||
|
||||
/**
|
||||
* Returns the Containment, if any, for a given physical screen
|
||||
*
|
||||
* @param screen number of the physical screen to locate
|
||||
*/
|
||||
Containment *containmentForScreen(int screen) const;
|
||||
|
||||
/**
|
||||
* Adds a widget in the topleft quadrant in the scene. Widgets in the topleft quadrant are
|
||||
* normally never shown unless you specifically aim a view at it, which makes it ideal for
|
||||
* toplevel views etc.
|
||||
* @param widget the widget to add.
|
||||
*/
|
||||
void addOffscreenWidget(QGraphicsWidget *widget);
|
||||
|
||||
/**
|
||||
* Removes a widget from the topleft quadrant in the scene.
|
||||
* @param widget the widget to remove.
|
||||
*/
|
||||
void removeOffscreenWidget(QGraphicsWidget *widget);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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 QGraphicsItem *item, const QSize &s);
|
||||
|
||||
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
|
||||
* @arg 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 Corona
|
||||
*/
|
||||
ImmutabilityType immutability() const;
|
||||
|
||||
/**
|
||||
* Sets the immutability type for this Corona (not immutable,
|
||||
* user immutable or system immutable)
|
||||
* @arg 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();
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal indicates a new containment has been added to
|
||||
* the Corona
|
||||
*/
|
||||
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();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Loads the default (system wide) layout for this user
|
||||
**/
|
||||
virtual void loadDefaultLayout();
|
||||
|
||||
/**
|
||||
* Loads a containment with delayed initialization, primarily useful
|
||||
* for implementations of loadDefaultLayout. The caller is responsible
|
||||
* for all initializating, saving and notification of a new containment.
|
||||
*
|
||||
* @param name the plugin name for the containment, as given by
|
||||
* KPluginInfo::pluginName(). If an empty string is passed in, the defalt
|
||||
* 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
|
||||
**/
|
||||
Containment *addContainmentDelayed(const QString &name,
|
||||
const QVariantList &args = QVariantList());
|
||||
|
||||
//Reimplemented from QGraphicsScene
|
||||
void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
|
||||
void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
|
||||
void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
|
||||
|
||||
private:
|
||||
CoronaPrivate *const d;
|
||||
|
||||
Q_PRIVATE_SLOT(d, void containmentDestroyed(QObject*))
|
||||
Q_PRIVATE_SLOT(d, void syncConfig())
|
||||
|
||||
friend class CoronaPrivate;
|
||||
};
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#endif
|
||||
|
200
datacontainer.cpp
Normal file
200
datacontainer.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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 <QVariant>
|
||||
|
||||
#include <KDebug>
|
||||
|
||||
#include "plasma.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
DataContainer::DataContainer(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new DataContainerPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
DataContainer::~DataContainer()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
const DataEngine::Data DataContainer::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void DataContainer::setData(const QString &key, const QVariant &value)
|
||||
{
|
||||
if (value.isNull() || !value.isValid()) {
|
||||
d->data.remove(key);
|
||||
} else {
|
||||
d->data[key] = value;
|
||||
}
|
||||
|
||||
d->dirty = true;
|
||||
d->updateTs.start();
|
||||
}
|
||||
|
||||
void DataContainer::removeAllData()
|
||||
{
|
||||
if (d->data.count() < 1) {
|
||||
// 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::disconnectVisualization(QObject *visualization)
|
||||
{
|
||||
QMap<QObject *, SignalRelay *>::iterator objIt = d->relayObjects.find(visualization);
|
||||
|
||||
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);
|
||||
checkUsage();
|
||||
}
|
||||
|
||||
void DataContainer::checkForUpdate()
|
||||
{
|
||||
if (d->dirty) {
|
||||
emit dataUpdated(objectName(), d->data);
|
||||
|
||||
foreach (SignalRelay *relay, d->relays) {
|
||||
relay->checkQueueing();
|
||||
}
|
||||
|
||||
d->dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void DataContainer::checkUsage()
|
||||
{
|
||||
if (d->relays.count() < 1 &&
|
||||
receivers(SIGNAL(dataUpdated(QString, Plasma::DataEngine::Data))) < 1) {
|
||||
// DO NOT CALL ANYTHING AFTER THIS LINE AS IT MAY GET DELETED!
|
||||
emit becameUnused(objectName());
|
||||
}
|
||||
}
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "datacontainer.moc"
|
||||
|
216
datacontainer.h
Normal file
216
datacontainer.h
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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 <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 retreival 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 null or 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
|
||||
**/
|
||||
void connectVisualization(QObject *visualization, uint pollingInterval,
|
||||
Plasma::IntervalAlignment alignment);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
* checkForUpdates() 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:
|
||||
/**
|
||||
* 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();
|
||||
|
||||
private:
|
||||
friend class SignalRelay;
|
||||
DataContainerPrivate *const d;
|
||||
};
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#endif // multiple inclusion guard
|
642
dataengine.cpp
Normal file
642
dataengine.cpp
Normal file
@ -0,0 +1,642 @@
|
||||
/*
|
||||
* 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 <QQueue>
|
||||
#include <QTimer>
|
||||
#include <QTime>
|
||||
#include <QTimerEvent>
|
||||
#include <QVariant>
|
||||
|
||||
#include <KDebug>
|
||||
#include <KPluginInfo>
|
||||
#include <KService>
|
||||
#include <KStandardDirs>
|
||||
|
||||
#include "datacontainer.h"
|
||||
#include "package.h"
|
||||
#include "service.h"
|
||||
#include "scripting/dataenginescript.h"
|
||||
|
||||
#include "private/service_p.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
DataEngine::DataEngine(QObject *parent, KService::Ptr service)
|
||||
: QObject(parent),
|
||||
d(new DataEnginePrivate(this, service))
|
||||
{
|
||||
connect(d->updateTimer, SIGNAL(timeout()), this, SLOT(scheduleSourcesUpdated()));
|
||||
}
|
||||
|
||||
DataEngine::DataEngine(QObject *parent, const QVariantList &args)
|
||||
: QObject(parent),
|
||||
d(new DataEnginePrivate(this, KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString())))
|
||||
{
|
||||
connect(d->updateTimer, SIGNAL(timeout()), this, SLOT(scheduleSourcesUpdated()));
|
||||
}
|
||||
|
||||
DataEngine::~DataEngine()
|
||||
{
|
||||
//kDebug() << objectName() << ": bye bye birdy! ";
|
||||
delete d;
|
||||
}
|
||||
|
||||
QStringList DataEngine::sources() const
|
||||
{
|
||||
return d->sources.keys();
|
||||
}
|
||||
|
||||
Service *DataEngine::serviceForSource(const QString &source)
|
||||
{
|
||||
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)
|
||||
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)) {
|
||||
if (const_cast<DataEngine*>(this)->updateSourceEvent(source)) {
|
||||
d->queueUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
DataEngine::Data data = s->data();
|
||||
s->checkUsage();
|
||||
return data;
|
||||
}
|
||||
|
||||
void DataEngine::init()
|
||||
{
|
||||
if (d->script) {
|
||||
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) {
|
||||
emit sourceAdded(source);
|
||||
}
|
||||
|
||||
d->queueUpdate();
|
||||
}
|
||||
|
||||
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) {
|
||||
emit sourceAdded(source);
|
||||
}
|
||||
|
||||
d->queueUpdate();
|
||||
}
|
||||
|
||||
void DataEngine::removeAllData(const QString &source)
|
||||
{
|
||||
DataContainer *s = d->source(source, false);
|
||||
if (s) {
|
||||
s->removeAllData();
|
||||
d->queueUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void DataEngine::removeData(const QString &source, const QString &key)
|
||||
{
|
||||
DataContainer *s = d->source(source, false);
|
||||
if (s) {
|
||||
s->setData(key, QVariant());
|
||||
d->queueUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void DataEngine::addSource(DataContainer *source)
|
||||
{
|
||||
if (d->sources.contains(source->objectName())) {
|
||||
kDebug() << "source named \"" << source->objectName() << "\" already exists.";
|
||||
return;
|
||||
}
|
||||
|
||||
QObject::connect(source, SIGNAL(updateRequested(DataContainer*)),
|
||||
this, SLOT(internalUpdateSource(DataContainer*)));
|
||||
d->sources.insert(source->objectName(), source);
|
||||
emit sourceAdded(source->objectName());
|
||||
d->queueUpdate();
|
||||
}
|
||||
|
||||
void DataEngine::setMaxSourceCount(uint limit)
|
||||
{
|
||||
if (d->limit == limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->limit = limit;
|
||||
|
||||
if (d->limit > 0) {
|
||||
d->trimQueue();
|
||||
} else {
|
||||
d->sourceQueue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
uint DataEngine::maxSourceCount() const
|
||||
{
|
||||
return d->limit;
|
||||
}
|
||||
|
||||
void DataEngine::setMinimumPollingInterval(int minimumMs)
|
||||
{
|
||||
if (minimumMs < 0) {
|
||||
minimumMs = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE: This is not implemented to prevent having to store the value internally.
|
||||
When there is a good use case for needing access to this value, we can
|
||||
add another member to the Private class and add this method.
|
||||
|
||||
void DataEngine::pollingInterval()
|
||||
{
|
||||
return d->pollingInterval;
|
||||
}
|
||||
*/
|
||||
|
||||
void DataEngine::removeSource(const QString &source)
|
||||
{
|
||||
//kDebug() << "removing source " << source;
|
||||
SourceDict::iterator it = d->sources.find(source);
|
||||
if (it != d->sources.end()) {
|
||||
DataContainer *s = it.value();
|
||||
|
||||
// remove it from the limit queue if we're keeping one
|
||||
if (d->limit > 0) {
|
||||
QQueue<DataContainer*>::iterator it = d->sourceQueue.begin();
|
||||
while (it != d->sourceQueue.end()) {
|
||||
if (*it == s) {
|
||||
d->sourceQueue.erase(it);
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
s->deleteLater();
|
||||
d->sources.erase(it);
|
||||
emit sourceRemoved(source);
|
||||
}
|
||||
}
|
||||
|
||||
void DataEngine::removeAllSources()
|
||||
{
|
||||
QMutableHashIterator<QString, Plasma::DataContainer*> it(d->sources);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
emit sourceRemoved(it.key());
|
||||
delete it.value();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (event->timerId() != d->updateTimerId) {
|
||||
kDebug() << "bzzzt";
|
||||
return;
|
||||
}
|
||||
|
||||
event->accept();
|
||||
|
||||
// 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();
|
||||
QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
//kDebug() << "updating" << it.key();
|
||||
updateSourceEvent(it.key());
|
||||
}
|
||||
|
||||
scheduleSourcesUpdated();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
const Package *DataEngine::package() const
|
||||
{
|
||||
return d->package;
|
||||
}
|
||||
|
||||
void DataEngine::scheduleSourcesUpdated()
|
||||
{
|
||||
QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
it.value()->checkForUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
QString DataEngine::name() const
|
||||
{
|
||||
return d->engineName;
|
||||
}
|
||||
|
||||
void DataEngine::setName(const QString &name)
|
||||
{
|
||||
d->engineName = name;
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
// Private class implementations
|
||||
DataEnginePrivate::DataEnginePrivate(DataEngine *e, KService::Ptr service)
|
||||
: q(e),
|
||||
dataEngineDescription(service),
|
||||
refCount(-1), // first ref
|
||||
updateTimerId(0),
|
||||
minPollingInterval(-1),
|
||||
limit(0),
|
||||
valid(true),
|
||||
script(0),
|
||||
package(0)
|
||||
{
|
||||
updateTimer = new QTimer(q);
|
||||
updateTimer->setSingleShot(true);
|
||||
updateTimestamp.start();
|
||||
|
||||
if (!service) {
|
||||
engineName = i18n("Unnamed");
|
||||
return;
|
||||
}
|
||||
|
||||
engineName = service->name();
|
||||
if (engineName.isEmpty()) {
|
||||
engineName = i18n("Unnamed");
|
||||
}
|
||||
e->setObjectName(engineName);
|
||||
icon = service->icon();
|
||||
|
||||
if (dataEngineDescription.isValid()) {
|
||||
QString api = dataEngineDescription.property("X-Plasma-API").toString();
|
||||
|
||||
if (!api.isEmpty()) {
|
||||
const QString path =
|
||||
KStandardDirs::locate("data",
|
||||
"plasma/engines/" + dataEngineDescription.pluginName() + '/');
|
||||
PackageStructure::Ptr structure =
|
||||
Plasma::packageStructure(api, Plasma::DataEngineComponent);
|
||||
structure->setPath(path);
|
||||
package = new Package(path, structure);
|
||||
|
||||
script = Plasma::loadScriptEngine(api, q);
|
||||
if (!script) {
|
||||
kDebug() << "Could not create a" << api << "ScriptEngine for the"
|
||||
<< dataEngineDescription.name() << "DataEngine.";
|
||||
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";
|
||||
queueUpdate();
|
||||
}/* else {
|
||||
kDebug() << "no update";
|
||||
}*/
|
||||
}
|
||||
|
||||
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.find(sourceName);
|
||||
if (it != sources.constEnd()) {
|
||||
DataContainer *s = it.value();
|
||||
if (limit > 0) {
|
||||
QQueue<DataContainer*>::iterator it = sourceQueue.begin();
|
||||
while (it != sourceQueue.end()) {
|
||||
if (*it == s) {
|
||||
sourceQueue.erase(it);
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
sourceQueue.enqueue(s);
|
||||
}
|
||||
return it.value();
|
||||
}
|
||||
|
||||
if (!createWhenMissing) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*kDebug() << "DataEngine " << q->objectName()
|
||||
<< ": could not find DataContainer " << sourceName
|
||||
<< ", creating" << endl;*/
|
||||
DataContainer *s = new DataContainer(q);
|
||||
s->setObjectName(sourceName);
|
||||
sources.insert(sourceName, s);
|
||||
QObject::connect(s, SIGNAL(updateRequested(DataContainer*)),
|
||||
q, SLOT(internalUpdateSource(DataContainer*)));
|
||||
|
||||
if (limit > 0) {
|
||||
trimQueue();
|
||||
sourceQueue.enqueue(s);
|
||||
}
|
||||
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;
|
||||
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->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()));
|
||||
}
|
||||
}
|
||||
|
||||
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;*/
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void DataEnginePrivate::trimQueue()
|
||||
{
|
||||
uint queueCount = sourceQueue.count();
|
||||
while (queueCount >= limit) {
|
||||
DataContainer *punted = sourceQueue.dequeue();
|
||||
q->removeSource(punted->objectName());
|
||||
}
|
||||
}
|
||||
|
||||
void DataEnginePrivate::queueUpdate()
|
||||
{
|
||||
if (updateTimer->isActive()) {
|
||||
return;
|
||||
}
|
||||
updateTimer->start(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "dataengine.moc"
|
464
dataengine.h
Normal file
464
dataengine.h
Normal file
@ -0,0 +1,464 @@
|
||||
/*
|
||||
* 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 <KDE/KGenericFactory>
|
||||
#include <KDE/KService>
|
||||
|
||||
#include <plasma/version.h>
|
||||
#include <plasma/plasma.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)
|
||||
|
||||
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 have the need to perform a startup routine.
|
||||
**/
|
||||
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 may be deleted by the
|
||||
* caller when finished with it
|
||||
*/
|
||||
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 sigal
|
||||
* 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 to 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;
|
||||
|
||||
/**
|
||||
* Retrevies 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
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* Returns true if the data engine is empty, which is to say that it has no
|
||||
* data sources currently.
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
/**
|
||||
* Returns the maximum number of sources this DataEngine will have
|
||||
* at any given time.
|
||||
*
|
||||
* @return the maximum number of sources; zero means no limit.
|
||||
*/
|
||||
uint maxSourceCount() 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
|
||||
**/
|
||||
const Package *package() const;
|
||||
|
||||
/**
|
||||
* Returns the plugin name for the applet
|
||||
*/
|
||||
QString pluginName() const;
|
||||
|
||||
|
||||
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 an upper limit on the number of data sources to keep in this engine.
|
||||
* If the limit is exceeded, then the oldest data source, as defined by last
|
||||
* update, is dropped.
|
||||
*
|
||||
* @param limit the maximum number of sources to keep active
|
||||
**/
|
||||
void setMaxSourceCount(uint limit);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Returns the current update frequency.
|
||||
* @see setPollingInterval
|
||||
NOTE: This is not implemented to prevent having to store the value internally.
|
||||
When there is a good use case for needing access to this value, we can
|
||||
add another member to the Private class and add this method.
|
||||
uint pollingInterval();
|
||||
**/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
friend class DataEnginePrivate;
|
||||
friend class DataEngineScript;
|
||||
friend class DataEngineManager;
|
||||
friend class NullEngine;
|
||||
|
||||
Q_PRIVATE_SLOT(d, void internalUpdateSource(DataContainer *source))
|
||||
|
||||
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)
|
||||
|
||||
#endif // multiple inclusion guard
|
||||
|
184
dataenginemanager.cpp
Normal file
184
dataenginemanager.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.h"
|
||||
|
||||
#include <KDebug>
|
||||
#include <KServiceTypeTrader>
|
||||
|
||||
#include "private/dataengine_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;
|
||||
};
|
||||
|
||||
K_GLOBAL_STATIC(DataEngineManagerSingleton, privateDataEngineManagerSelf)
|
||||
|
||||
DataEngineManager *DataEngineManager::self()
|
||||
{
|
||||
return &privateDataEngineManagerSelf->self;
|
||||
}
|
||||
|
||||
DataEngineManager::DataEngineManager()
|
||||
: d(new DataEngineManagerPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
DataEngineManager::~DataEngineManager()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Plasma::DataEngine *DataEngineManager::engine(const QString &name) const
|
||||
{
|
||||
Plasma::DataEngine::Dict::const_iterator it = d->engines.find(name);
|
||||
if (it != d->engines.end()) {
|
||||
// ref and return the engine
|
||||
//Plasma::DataEngine *engine = *it;
|
||||
return *it;
|
||||
}
|
||||
|
||||
return d->nullEngine();
|
||||
}
|
||||
|
||||
Plasma::DataEngine *DataEngineManager::loadEngine(const QString &name)
|
||||
{
|
||||
Plasma::DataEngine *engine = 0;
|
||||
Plasma::DataEngine::Dict::const_iterator it = d->engines.find(name);
|
||||
|
||||
if (it != d->engines.end()) {
|
||||
engine = *it;
|
||||
engine->d->ref();
|
||||
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()) {
|
||||
kDebug() << "offers are empty for " << name << " with constraint " << constraint;
|
||||
} 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) {
|
||||
kDebug() << "Couldn't load engine \"" << name << "\". Error given: " << error;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList DataEngineManager::listAllEngines()
|
||||
{
|
||||
QStringList engines;
|
||||
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine");
|
||||
foreach (const KService::Ptr &service, offers) {
|
||||
QString name = service->property("X-KDE-PluginInfo-Name").toString();
|
||||
if (!name.isEmpty()) {
|
||||
engines.append(name);
|
||||
}
|
||||
}
|
||||
|
||||
return engines;
|
||||
}
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#include "dataenginemanager.moc"
|
94
dataenginemanager.h
Normal file
94
dataenginemanager.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 <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);
|
||||
|
||||
/**
|
||||
* Returns a listing of all known engines by name
|
||||
*/
|
||||
static QStringList listAllEngines();
|
||||
|
||||
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
|
385
delegate.cpp
Normal file
385
delegate.cpp
Normal file
@ -0,0 +1,385 @@
|
||||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2007 Kevin Ottens <ervin@kde.org>
|
||||
Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "delegate.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <math.h>
|
||||
|
||||
// Qt
|
||||
#include <QApplication>
|
||||
#include <QFontMetrics>
|
||||
#include <QIcon>
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionViewItem>
|
||||
|
||||
// KDE
|
||||
#include <KColorUtils>
|
||||
#include <KDebug>
|
||||
#include <KGlobal>
|
||||
#include <KGlobalSettings>
|
||||
#include <KColorScheme>
|
||||
|
||||
// plasma
|
||||
#include <plasma/paintutils.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class DelegatePrivate
|
||||
{
|
||||
public:
|
||||
DelegatePrivate() { }
|
||||
|
||||
~DelegatePrivate() { }
|
||||
|
||||
QFont fontForSubTitle(const QFont &titleFont) const;
|
||||
QRect titleRect(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
QRect subTitleRect(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
QMap<int, int> roles;
|
||||
|
||||
static const int ICON_TEXT_MARGIN = 10;
|
||||
static const int TEXT_RIGHT_MARGIN = 5;
|
||||
static const int ACTION_ICON_SIZE = 22;
|
||||
|
||||
static const int ITEM_LEFT_MARGIN = 5;
|
||||
static const int ITEM_RIGHT_MARGIN = 5;
|
||||
static const int ITEM_TOP_MARGIN = 5;
|
||||
static const int ITEM_BOTTOM_MARGIN = 5;
|
||||
};
|
||||
|
||||
QFont DelegatePrivate::fontForSubTitle(const QFont &titleFont) const
|
||||
{
|
||||
QFont subTitleFont = titleFont;
|
||||
subTitleFont.setPointSize(qMax(subTitleFont.pointSize() - 2,
|
||||
KGlobalSettings::smallestReadableFont().pointSize()));
|
||||
return subTitleFont;
|
||||
}
|
||||
|
||||
QRect DelegatePrivate::titleRect(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
QFont font(option.font);
|
||||
font.setBold(true);
|
||||
QFontMetrics fm(font);
|
||||
|
||||
Qt::Alignment textAlignment =
|
||||
option.decorationAlignment & Qt::AlignRight ? Qt::AlignRight : Qt::AlignLeft;
|
||||
|
||||
QRect emptyRect;
|
||||
if (option.direction == Qt::LeftToRight) {
|
||||
emptyRect = option.rect.adjusted(
|
||||
option.decorationSize.width() + ICON_TEXT_MARGIN + ITEM_LEFT_MARGIN,
|
||||
ITEM_TOP_MARGIN, -ITEM_RIGHT_MARGIN, -ITEM_BOTTOM_MARGIN);
|
||||
} else {
|
||||
emptyRect = option.rect.adjusted(
|
||||
ITEM_LEFT_MARGIN, ITEM_TOP_MARGIN,
|
||||
-ITEM_RIGHT_MARGIN - option.decorationSize.width() - ICON_TEXT_MARGIN, -ITEM_BOTTOM_MARGIN);
|
||||
}
|
||||
|
||||
if (emptyRect.width() < 0) {
|
||||
emptyRect.setWidth(0);
|
||||
return emptyRect;
|
||||
}
|
||||
|
||||
QRect textRect = QStyle::alignedRect(
|
||||
option.direction,
|
||||
textAlignment,
|
||||
fm.boundingRect(index.data(Qt::DisplayRole).toString()).size(),
|
||||
emptyRect);
|
||||
|
||||
textRect.setWidth(textRect.width() + TEXT_RIGHT_MARGIN);
|
||||
textRect.setHeight(emptyRect.height() / 2);
|
||||
return textRect;
|
||||
}
|
||||
|
||||
QRect DelegatePrivate::subTitleRect(const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QString subTitle = index.data(roles[Delegate::SubTitleRole]).toString();
|
||||
|
||||
QFontMetrics fm(fontForSubTitle(option.font));
|
||||
|
||||
QRect textRect = titleRect(option, index);
|
||||
int right = textRect.right();
|
||||
|
||||
//if title=subtitle subtitle won't be displayed
|
||||
if (subTitle != index.data(Qt::DisplayRole).toString()) {
|
||||
textRect.setWidth(fm.width(" " + subTitle) + TEXT_RIGHT_MARGIN);
|
||||
} else {
|
||||
textRect.setWidth(0);
|
||||
}
|
||||
textRect.translate(0, textRect.height());
|
||||
|
||||
if (option.direction == Qt::RightToLeft) {
|
||||
textRect.moveRight(right);
|
||||
}
|
||||
|
||||
return textRect;
|
||||
}
|
||||
|
||||
Delegate::Delegate(QObject *parent)
|
||||
: QAbstractItemDelegate(parent),
|
||||
d(new DelegatePrivate)
|
||||
{
|
||||
}
|
||||
|
||||
Delegate::~Delegate()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Delegate::setRoleMapping(SpecificRoles role, int actual)
|
||||
{
|
||||
d->roles[role] = actual;
|
||||
}
|
||||
|
||||
int Delegate::roleMapping(SpecificRoles role) const
|
||||
{
|
||||
return d->roles[role];
|
||||
}
|
||||
|
||||
QRect Delegate::rectAfterTitle(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
QRect textRect = d->titleRect(option, index);
|
||||
|
||||
QRect emptyRect(0, textRect.top(), option.rect.width() - textRect.width() - DelegatePrivate::ITEM_LEFT_MARGIN - DelegatePrivate::ITEM_RIGHT_MARGIN - option.decorationSize.width() - DelegatePrivate::ICON_TEXT_MARGIN, textRect.height());
|
||||
|
||||
if (option.direction == Qt::LeftToRight) {
|
||||
emptyRect.moveLeft(textRect.right());
|
||||
} else {
|
||||
emptyRect.moveRight(textRect.left());
|
||||
}
|
||||
|
||||
if (emptyRect.width() < 0) {
|
||||
emptyRect.setWidth(0);
|
||||
}
|
||||
|
||||
return emptyRect;
|
||||
}
|
||||
|
||||
QRect Delegate::rectAfterSubTitle(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
QRect textRect = d->subTitleRect(option, index);
|
||||
|
||||
QRect emptyRect(0, textRect.top(), option.rect.width() - textRect.width() - DelegatePrivate::ITEM_LEFT_MARGIN - DelegatePrivate::ITEM_RIGHT_MARGIN - option.decorationSize.width() - DelegatePrivate::ICON_TEXT_MARGIN, textRect.height());
|
||||
|
||||
if (option.direction == Qt::LeftToRight) {
|
||||
emptyRect.moveLeft(textRect.right());
|
||||
} else {
|
||||
emptyRect.moveRight(textRect.left());
|
||||
}
|
||||
|
||||
if (emptyRect.width() < 0) {
|
||||
emptyRect.setWidth(0);
|
||||
}
|
||||
|
||||
return emptyRect;
|
||||
}
|
||||
|
||||
QRect Delegate::emptyRect(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
QRect afterTitleRect = rectAfterTitle(option, index);
|
||||
QRect afterSubTitleRect = rectAfterSubTitle(option, index);
|
||||
|
||||
afterTitleRect.setHeight(afterTitleRect.height() * 2);
|
||||
afterSubTitleRect.setTop(afterTitleRect.top());
|
||||
|
||||
return afterTitleRect.intersected(afterSubTitleRect);
|
||||
}
|
||||
|
||||
void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
const bool hover = option.state & (QStyle::State_MouseOver | QStyle::State_Selected);
|
||||
|
||||
QRect contentRect = option.rect;
|
||||
contentRect.setBottom(contentRect.bottom() - 1);
|
||||
|
||||
QRect decorationRect =
|
||||
QStyle::alignedRect(option.direction,
|
||||
option.decorationPosition == QStyleOptionViewItem::Left ?
|
||||
Qt::AlignLeft : Qt::AlignRight,
|
||||
option.decorationSize,
|
||||
contentRect.adjusted(DelegatePrivate::ITEM_LEFT_MARGIN, DelegatePrivate::ITEM_TOP_MARGIN, -DelegatePrivate::ITEM_RIGHT_MARGIN, -DelegatePrivate::ITEM_BOTTOM_MARGIN));
|
||||
decorationRect.moveTop(contentRect.top() + qMax(0, (contentRect.height() - decorationRect.height())) / 2);
|
||||
|
||||
QString titleText = index.data(Qt::DisplayRole).value<QString>();
|
||||
QString subTitleText = index.data(d->roles[SubTitleRole]).value<QString>();
|
||||
|
||||
QRect titleRect = d->titleRect(option, index);
|
||||
QRect subTitleRect = d->subTitleRect(option, index);
|
||||
|
||||
bool uniqueTitle = !index.data(d->roles[SubTitleMandatoryRole]).value<bool>();// true;
|
||||
if (uniqueTitle) {
|
||||
QModelIndex sib = index.sibling(index.row() + 1, index.column());
|
||||
if (sib.isValid()) {
|
||||
uniqueTitle = sib.data(Qt::DisplayRole).value<QString>() != titleText;
|
||||
}
|
||||
|
||||
if (uniqueTitle) {
|
||||
sib = index.sibling(index.row() + -1, index.column());
|
||||
if (sib.isValid()) {
|
||||
uniqueTitle = sib.data(Qt::DisplayRole).value<QString>() != titleText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subTitleText == titleText) {
|
||||
subTitleText.clear();
|
||||
}
|
||||
|
||||
QFont subTitleFont = d->fontForSubTitle(option.font);
|
||||
|
||||
QFont titleFont(option.font);
|
||||
|
||||
if (hover) {
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
const int column = index.column();
|
||||
const int columns = index.model()->columnCount();
|
||||
const int roundedRadius = 5;
|
||||
|
||||
// use a slightly translucent version of the palette's highlight color
|
||||
// for the background
|
||||
QColor backgroundColor = option.palette.color(QPalette::Highlight);
|
||||
backgroundColor.setAlphaF(0.2);
|
||||
|
||||
QColor backgroundColor2 = option.palette.color(QPalette::Highlight);
|
||||
backgroundColor.setAlphaF(0.5);
|
||||
|
||||
QRect highlightRect = option.rect.adjusted(2, 2, -2, -2);
|
||||
|
||||
QPen outlinePen(backgroundColor, 2);
|
||||
|
||||
if (column == 0) {
|
||||
//clip right (or left for rtl languages) to make the connection with the next column
|
||||
if (columns > 1) {
|
||||
if (option.direction == Qt::LeftToRight) {
|
||||
painter->setClipRect(option.rect);
|
||||
highlightRect.adjust(0, 0, roundedRadius, 0);
|
||||
} else {
|
||||
painter->setClipRect(option.rect);
|
||||
highlightRect.adjust(-roundedRadius, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
QLinearGradient gradient(highlightRect.topLeft(), highlightRect.topRight());
|
||||
|
||||
//reverse the gradient
|
||||
if (option.direction == Qt::RightToLeft) {
|
||||
gradient.setStart(highlightRect.topRight());
|
||||
gradient.setFinalStop(highlightRect.topLeft());
|
||||
}
|
||||
|
||||
gradient.setColorAt(0, backgroundColor);
|
||||
|
||||
gradient.setColorAt(((qreal)titleRect.width()/3.0) / (qreal)highlightRect.width(), backgroundColor2);
|
||||
|
||||
gradient.setColorAt(0.7, backgroundColor);
|
||||
|
||||
outlinePen.setBrush(gradient);
|
||||
|
||||
//last column, clip left (right for rtl)
|
||||
} else if (column == columns-1) {
|
||||
if (option.direction == Qt::LeftToRight) {
|
||||
painter->setClipRect(option.rect);
|
||||
highlightRect.adjust(-roundedRadius, 0, 0, 0);
|
||||
} else {
|
||||
painter->setClipRect(option.rect);
|
||||
highlightRect.adjust(0, 0, +roundedRadius, 0);
|
||||
}
|
||||
|
||||
//column < columns-1; clip both ways
|
||||
} else {
|
||||
painter->setClipRect(option.rect);
|
||||
highlightRect.adjust(-roundedRadius, 0, +roundedRadius, 0);
|
||||
}
|
||||
|
||||
painter->setPen(outlinePen);
|
||||
painter->drawPath(PaintUtils::roundedRectangle(highlightRect, roundedRadius));
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
// draw icon
|
||||
QIcon decorationIcon = index.data(Qt::DecorationRole).value<QIcon>();
|
||||
|
||||
if (index.data(d->roles[ColumnTypeRole]).toInt() == SecondaryActionColumn) {
|
||||
if (hover) {
|
||||
// Only draw on hover
|
||||
const int delta = floor((qreal)(option.decorationSize.width() - DelegatePrivate::ACTION_ICON_SIZE) / 2.0);
|
||||
decorationRect.adjust(delta, delta-1, -delta-1, -delta);
|
||||
decorationIcon.paint(painter, decorationRect, option.decorationAlignment);
|
||||
}
|
||||
} else {
|
||||
// as default always draw as main column
|
||||
decorationIcon.paint(painter, decorationRect, option.decorationAlignment);
|
||||
}
|
||||
|
||||
painter->save();
|
||||
|
||||
// draw title
|
||||
painter->setFont(titleFont);
|
||||
painter->drawText(titleRect, Qt::AlignLeft|Qt::AlignVCenter, titleText);
|
||||
|
||||
if (hover || !uniqueTitle) {
|
||||
// draw sub-title, BUT only if:
|
||||
// * it isn't a unique title, this allows two items to have the same title and be
|
||||
// disambiguated by their subtitle
|
||||
// * we are directed by the model that this item should never be treated as unique
|
||||
// e.g. the documents list in the recently used tab
|
||||
// * the mouse is hovered over the item, causing the additional information to be
|
||||
// displayed
|
||||
//
|
||||
// the rational for this is that subtitle text should in most cases not be
|
||||
// required to understand the item itself and that showing all the subtexts in a
|
||||
// listing makes the information density very high, impacting both the speed at
|
||||
// which one can scan the list visually and the aesthetic qualities of the listing.
|
||||
painter->setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText), 1));
|
||||
painter->setFont(subTitleFont);
|
||||
painter->drawText(subTitleRect, Qt::AlignLeft|Qt::AlignVCenter, " " + subTitleText);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
|
||||
}
|
||||
|
||||
QSize Delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
QSize size = option.rect.size();
|
||||
|
||||
QFontMetrics metrics(option.font);
|
||||
|
||||
QFontMetrics subMetrics(d->fontForSubTitle(option.font));
|
||||
size.setHeight(qMax(option.decorationSize.height(), qMax(size.height(), metrics.height() + subMetrics.ascent()) + 3) + 4);
|
||||
// kDebug() << "size hint is" << size << (metrics.height() + subMetrics.ascent());
|
||||
|
||||
size *= 1.1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
122
delegate.h
Normal file
122
delegate.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
Copyright 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef PLASMA_DELEGATE_H
|
||||
#define PLASMA_DELEGATE_H
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QAbstractItemDelegate>
|
||||
|
||||
// Plasma
|
||||
#include <plasma/plasma_export.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class DelegatePrivate;
|
||||
|
||||
/**
|
||||
* @class Delegate plasma/delegate.h <Plasma/Delegate>
|
||||
*
|
||||
* Item delegate for rendering items in Plasma menus implemented with item views.
|
||||
*
|
||||
* The delegate makes use of its own data roles that are:
|
||||
* SubTitleRole: the text of the subtitle
|
||||
* SubTitleMandatoryRole: if the subtitle is to always be displayed
|
||||
* (as default the subtitle is displayed only on mouse over)
|
||||
* ColumnTypeRole: if the column is a main column (with title and subtitle)
|
||||
* or a secondary action column (only a little icon that appears on mouse
|
||||
* over is displayed)
|
||||
*/
|
||||
class PLASMA_EXPORT Delegate : public QAbstractItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum SpecificRoles {
|
||||
SubTitleRole = Qt::UserRole + 1,
|
||||
SubTitleMandatoryRole = Qt::UserRole + 2,
|
||||
ColumnTypeRole = Qt::UserRole + 3
|
||||
};
|
||||
|
||||
enum ColumnType {
|
||||
MainColumn = 1,
|
||||
SecondaryActionColumn = 2
|
||||
};
|
||||
|
||||
Delegate(QObject *parent = 0);
|
||||
~Delegate();
|
||||
|
||||
/**
|
||||
* Maps an arbitrary role to a role belonging to SpecificRoles.
|
||||
* Using this function you can use any model with this delegate.
|
||||
*
|
||||
* @param role a role belonging to SpecificRoles
|
||||
* @param actual an arbitrary role of the model we are using
|
||||
*/
|
||||
void setRoleMapping(SpecificRoles role, int actual);
|
||||
|
||||
int roleMapping(SpecificRoles role) const;
|
||||
|
||||
//Reimplemented
|
||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns the empty area after the title.
|
||||
* The height is the height of the subtitle.
|
||||
* It can be used by subclasses that wants to paint additional data after
|
||||
* calling the paint function of the superclass.
|
||||
*
|
||||
* @param option options for the title text
|
||||
* @param index model index that we want to compute the free area
|
||||
*/
|
||||
QRect rectAfterTitle(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
/**
|
||||
* Returns the empty area after the subtitle.
|
||||
* The height is the height of the subtitle.
|
||||
* It can be used by subclasses, that wants to paint additional data.
|
||||
*
|
||||
* @param option options for the subtitle text
|
||||
* @param index model index that we want to compute the free area
|
||||
*/
|
||||
QRect rectAfterSubTitle(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
/**
|
||||
* Returns the empty area after both the title and the subtitle.
|
||||
* The height is the height of the item.
|
||||
* It can be used by subclasses that wants to paint additional data
|
||||
*
|
||||
* @param option options for the title and subtitle text
|
||||
* @param index model index that we want to compute the free area
|
||||
*/
|
||||
QRect emptyRect(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
private:
|
||||
DelegatePrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // PLASMA_DELEGATE_H
|
423
dialog.cpp
Normal file
423
dialog.cpp
Normal file
@ -0,0 +1,423 @@
|
||||
/*
|
||||
* Copyright 2008 by Alessandro Diaferia <alediaferia@gmail.com>
|
||||
* Copyright 2007 by Alexis Ménard <darktears31@gmail.com>
|
||||
* Copyright 2007 Sebastian Kuegler <sebas@kde.org>
|
||||
* Copyright 2006 Aaron Seigo <aseigo@kde.org>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QSvgRenderer>
|
||||
#include <QResizeEvent>
|
||||
#include <QMouseEvent>
|
||||
#ifdef Q_WS_X11
|
||||
#include <QX11Info>
|
||||
#endif
|
||||
#include <QBitmap>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QGraphicsSceneEvent>
|
||||
#include <QtGui/QGraphicsView>
|
||||
#include <QtGui/QGraphicsWidget>
|
||||
|
||||
#include <KDebug>
|
||||
#include <NETRootInfo>
|
||||
|
||||
#include "plasma/applet.h"
|
||||
#include "plasma/extender.h"
|
||||
#include "plasma/private/extender_p.h"
|
||||
#include "plasma/framesvg.h"
|
||||
#include "plasma/theme.h"
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
const int resizeAreaMargin = 20;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class DialogPrivate
|
||||
{
|
||||
public:
|
||||
DialogPrivate(Dialog *dialog)
|
||||
: q(dialog),
|
||||
background(0),
|
||||
view(0),
|
||||
widget(0),
|
||||
resizeCorners(Dialog::NoCorner),
|
||||
resizeStartCorner(Dialog::NoCorner)
|
||||
{
|
||||
}
|
||||
|
||||
~DialogPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
void themeUpdated();
|
||||
void adjustView();
|
||||
|
||||
Plasma::Dialog *q;
|
||||
/**
|
||||
* Holds the background SVG, to be re-rendered when the cache is invalidated,
|
||||
* for example by resizing the dialogue.
|
||||
*/
|
||||
Plasma::FrameSvg *background;
|
||||
QGraphicsView *view;
|
||||
QGraphicsWidget *widget;
|
||||
Dialog::ResizeCorners resizeCorners;
|
||||
QMap<Dialog::ResizeCorner, QRect> resizeAreas;
|
||||
Dialog::ResizeCorner resizeStartCorner;
|
||||
};
|
||||
|
||||
void DialogPrivate::themeUpdated()
|
||||
{
|
||||
const int topHeight = background->marginSize(Plasma::TopMargin);
|
||||
const int leftWidth = background->marginSize(Plasma::LeftMargin);
|
||||
const int rightWidth = background->marginSize(Plasma::RightMargin);
|
||||
const int bottomHeight = background->marginSize(Plasma::BottomMargin);
|
||||
|
||||
//TODO: correct handling of the situation when having vertical panels.
|
||||
Extender *extender = qobject_cast<Extender*>(widget);
|
||||
if (extender) {
|
||||
switch (extender->d->applet->location()) {
|
||||
case BottomEdge:
|
||||
background->setEnabledBorders(FrameSvg::LeftBorder | FrameSvg::TopBorder
|
||||
| FrameSvg::RightBorder);
|
||||
q->setContentsMargins(0, topHeight, 0, 0);
|
||||
break;
|
||||
case TopEdge:
|
||||
background->setEnabledBorders(FrameSvg::LeftBorder | FrameSvg::BottomBorder
|
||||
| FrameSvg::RightBorder);
|
||||
q->setContentsMargins(0, 0, 0, bottomHeight);
|
||||
break;
|
||||
case LeftEdge:
|
||||
background->setEnabledBorders(FrameSvg::TopBorder | FrameSvg::BottomBorder
|
||||
| FrameSvg::RightBorder);
|
||||
q->setContentsMargins(0, topHeight, 0, bottomHeight);
|
||||
break;
|
||||
case RightEdge:
|
||||
background->setEnabledBorders(FrameSvg::TopBorder | FrameSvg::BottomBorder
|
||||
| FrameSvg::LeftBorder);
|
||||
q->setContentsMargins(0, topHeight, 0, bottomHeight);
|
||||
break;
|
||||
default:
|
||||
background->setEnabledBorders(FrameSvg::AllBorders);
|
||||
q->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
|
||||
}
|
||||
} else {
|
||||
q->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
|
||||
}
|
||||
q->update();
|
||||
}
|
||||
|
||||
void DialogPrivate::adjustView()
|
||||
{
|
||||
if (view && widget) {
|
||||
QSize prevSize = q->size();
|
||||
/*
|
||||
kDebug() << "Widget size:" << widget->size()
|
||||
<< "| Widget size hint:" << widget->effectiveSizeHint(Qt::PreferredSize)
|
||||
<< "| Widget minsize hint:" << widget->minimumSize()
|
||||
<< "| Widget maxsize hint:" << widget->maximumSize()
|
||||
<< "| Widget bounding rect:" << widget->boundingRect();
|
||||
*/
|
||||
//set the sizehints correctly:
|
||||
int left, top, right, bottom;
|
||||
q->getContentsMargins(&left, &top, &right, &bottom);
|
||||
|
||||
q->setMinimumSize(qMin(int(widget->minimumSize().width()) + left + right, QWIDGETSIZE_MAX),
|
||||
qMin(int(widget->minimumSize().height()) + top + bottom, QWIDGETSIZE_MAX));
|
||||
q->setMaximumSize(qMin(int(widget->maximumSize().width()) + left + right, QWIDGETSIZE_MAX),
|
||||
qMin(int(widget->maximumSize().height()) + top + bottom, QWIDGETSIZE_MAX));
|
||||
q->resize(qMin(int(view->size().width()) + left + right, QWIDGETSIZE_MAX),
|
||||
qMin(int(view->size().height()) + top + bottom, QWIDGETSIZE_MAX));
|
||||
q->updateGeometry();
|
||||
|
||||
//reposition and resize the view.
|
||||
view->setSceneRect(widget->sceneBoundingRect());
|
||||
view->resize(view->mapFromScene(view->sceneRect()).boundingRect().size());
|
||||
view->centerOn(widget);
|
||||
|
||||
if (q->size() != prevSize) {
|
||||
//the size of the dialog has changed, emit the signal:
|
||||
emit q->dialogResized();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dialog::Dialog(QWidget *parent, Qt::WindowFlags f)
|
||||
: QWidget(parent, f),
|
||||
d(new DialogPrivate(this))
|
||||
{
|
||||
setWindowFlags(Qt::FramelessWindowHint);
|
||||
d->background = new FrameSvg(this);
|
||||
d->background->setImagePath("dialogs/background");
|
||||
d->background->setEnabledBorders(FrameSvg::AllBorders);
|
||||
d->background->resizeFrame(size());
|
||||
|
||||
connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(update()));
|
||||
|
||||
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeUpdated()));
|
||||
d->themeUpdated();
|
||||
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
Dialog::~Dialog()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Dialog::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.setClipRect(e->rect());
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.fillRect(rect(), Qt::transparent);
|
||||
d->background->paintFrame(&p);
|
||||
|
||||
//we set the resize handlers
|
||||
d->resizeAreas.clear();
|
||||
if (d->resizeCorners & Dialog::NorthEast) {
|
||||
d->resizeAreas[Dialog::NorthEast] = QRect(rect().right() - resizeAreaMargin, 0,
|
||||
resizeAreaMargin, resizeAreaMargin);
|
||||
}
|
||||
|
||||
if (d->resizeCorners & Dialog::NorthWest) {
|
||||
d->resizeAreas[Dialog::NorthWest] = QRect(0, 0, resizeAreaMargin, resizeAreaMargin);
|
||||
}
|
||||
|
||||
if (d->resizeCorners & Dialog::SouthEast) {
|
||||
d->resizeAreas[Dialog::SouthEast] = QRect(rect().right() - resizeAreaMargin,
|
||||
rect().bottom() - resizeAreaMargin,
|
||||
resizeAreaMargin, resizeAreaMargin);
|
||||
}
|
||||
|
||||
if (d->resizeCorners & Dialog::SouthWest) {
|
||||
d->resizeAreas[Dialog::SouthWest] = QRect(0, rect().bottom() - resizeAreaMargin,
|
||||
resizeAreaMargin, resizeAreaMargin);
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (d->resizeAreas[Dialog::NorthEast].contains(event->pos()) && d->resizeCorners & Dialog::NorthEast) {
|
||||
setCursor(Qt::SizeBDiagCursor);
|
||||
} else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos()) && d->resizeCorners & Dialog::NorthWest) {
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
} else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos()) && d->resizeCorners & Dialog::SouthEast) {
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
} else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos()) && d->resizeCorners & Dialog::SouthWest) {
|
||||
setCursor(Qt::SizeBDiagCursor);
|
||||
} else {
|
||||
unsetCursor();
|
||||
}
|
||||
|
||||
// here we take care of resize..
|
||||
if (d->resizeStartCorner != Dialog::NoCorner) {
|
||||
int newWidth;
|
||||
int newHeight;
|
||||
QPoint position;
|
||||
|
||||
switch(d->resizeStartCorner) {
|
||||
case Dialog::NorthEast:
|
||||
newWidth = event->x();
|
||||
newHeight = height() - event->y();
|
||||
position = QPoint(x(), y() + height() - newHeight);
|
||||
break;
|
||||
case Dialog::NorthWest:
|
||||
newWidth = width() - event->x();
|
||||
newHeight = height() - event->y();
|
||||
position = QPoint(x() + width() - newWidth, y() + height() - newHeight);
|
||||
break;
|
||||
case Dialog::SouthWest:
|
||||
newWidth = width() - event->x();
|
||||
newHeight = event->y();
|
||||
position = QPoint(x() + width() - newWidth, y());
|
||||
break;
|
||||
case Dialog::SouthEast:
|
||||
newWidth = event->x();
|
||||
newHeight = event->y();
|
||||
position = QPoint(x(), y());
|
||||
break;
|
||||
default:
|
||||
newWidth = width();
|
||||
newHeight = height();
|
||||
position = QPoint(x(), y());
|
||||
break;
|
||||
}
|
||||
|
||||
// let's check for limitations
|
||||
if (newWidth < minimumWidth() || newWidth > maximumWidth()) {
|
||||
newWidth = width();
|
||||
position.setX(x());
|
||||
}
|
||||
|
||||
if (newHeight < minimumHeight() || newHeight > maximumHeight()) {
|
||||
newHeight = height();
|
||||
position.setY(y());
|
||||
}
|
||||
|
||||
setGeometry(QRect(position, QSize(newWidth, newHeight)));
|
||||
}
|
||||
|
||||
QWidget::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void Dialog::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (d->resizeAreas[Dialog::NorthEast].contains(event->pos()) && d->resizeCorners & Dialog::NorthEast) {
|
||||
d->resizeStartCorner = Dialog::NorthEast;
|
||||
|
||||
} else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos()) && d->resizeCorners & Dialog::NorthWest) {
|
||||
d->resizeStartCorner = Dialog::NorthWest;
|
||||
|
||||
} else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos()) && d->resizeCorners & Dialog::SouthEast) {
|
||||
d->resizeStartCorner = Dialog::SouthEast;
|
||||
|
||||
} else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos()) && d->resizeCorners & Dialog::SouthWest) {
|
||||
d->resizeStartCorner = Dialog::SouthWest;
|
||||
|
||||
} else {
|
||||
d->resizeStartCorner = Dialog::NoCorner;
|
||||
}
|
||||
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void Dialog::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (d->resizeStartCorner != Dialog::NoCorner) {
|
||||
d->resizeStartCorner = Dialog::NoCorner;
|
||||
emit dialogResized();
|
||||
}
|
||||
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void Dialog::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
d->background->resizeFrame(e->size());
|
||||
|
||||
setMask(d->background->mask());
|
||||
|
||||
if (d->resizeStartCorner != Dialog::NoCorner && d->view && d->widget) {
|
||||
d->widget->setPreferredSize(d->view->size());
|
||||
|
||||
QGraphicsLayoutItem *layout = d->widget->parentLayoutItem();
|
||||
QGraphicsWidget *parentWidget = d->widget->parentWidget();
|
||||
|
||||
if (layout && parentWidget) {
|
||||
layout->updateGeometry();
|
||||
parentWidget->resize(layout->preferredSize());
|
||||
}
|
||||
|
||||
d->view->setSceneRect(d->widget->mapToScene(d->widget->boundingRect()).boundingRect());
|
||||
d->view->centerOn(d->widget);
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::setGraphicsWidget(QGraphicsWidget *widget)
|
||||
{
|
||||
if (d->widget) {
|
||||
d->widget->removeEventFilter(this);
|
||||
}
|
||||
|
||||
d->widget = widget;
|
||||
|
||||
if (widget) {
|
||||
if (!layout()) {
|
||||
QVBoxLayout *lay = new QVBoxLayout(this);
|
||||
lay->setMargin(0);
|
||||
lay->setSpacing(0);
|
||||
}
|
||||
|
||||
d->themeUpdated();
|
||||
|
||||
if (!d->view) {
|
||||
d->view = new QGraphicsView(this);
|
||||
d->view->setFrameShape(QFrame::NoFrame);
|
||||
d->view->viewport()->setAutoFillBackground(false);
|
||||
layout()->addWidget(d->view);
|
||||
}
|
||||
|
||||
d->view->setScene(widget->scene());
|
||||
d->adjustView();
|
||||
|
||||
adjustSize();
|
||||
|
||||
widget->installEventFilter(this);
|
||||
} else {
|
||||
delete d->view;
|
||||
d->view = 0;
|
||||
}
|
||||
}
|
||||
|
||||
QGraphicsWidget *Dialog::graphicsWidget()
|
||||
{
|
||||
return d->widget;
|
||||
}
|
||||
|
||||
bool Dialog::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (d->resizeStartCorner == Dialog::NoCorner && watched == d->widget &&
|
||||
(event->type() == QEvent::GraphicsSceneResize || event->type() == QEvent::GraphicsSceneMove)) {
|
||||
d->adjustView();
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void Dialog::hideEvent(QHideEvent * event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
emit dialogVisible(false);
|
||||
}
|
||||
|
||||
void Dialog::showEvent(QShowEvent * event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
emit dialogVisible(true);
|
||||
}
|
||||
|
||||
void Dialog::setResizeHandleCorners(ResizeCorners corners)
|
||||
{
|
||||
d->resizeCorners = corners;
|
||||
update();
|
||||
}
|
||||
|
||||
Dialog::ResizeCorners Dialog::resizeCorners() const
|
||||
{
|
||||
return d->resizeCorners;
|
||||
}
|
||||
|
||||
bool Dialog::inControlArea(const QPoint &point)
|
||||
{
|
||||
foreach (const QRect &r, d->resizeAreas) {
|
||||
if (r.contains(point)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
#include "dialog.moc"
|
134
dialog.h
Normal file
134
dialog.h
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2008 by Alessandro Diaferia <alediaferia@gmail.com>
|
||||
* Copyright 2007 by Alexis Ménard <darktears31@gmail.com>
|
||||
* Copyright 2007 Sebastian Kuegler <sebas@kde.org>
|
||||
* Copyright 2006 Aaron Seigo <aseigo@kde.org>
|
||||
*
|
||||
* 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 PLASMA_DIALOG_H
|
||||
#define PLASMA_DIALOG_H
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QGraphicsSceneEvent>
|
||||
#include <QtGui/QGraphicsView>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class DialogPrivate;
|
||||
|
||||
/**
|
||||
* @class Dialog plasma/dialog.h <Plasma/Dialog>
|
||||
*
|
||||
* @short A dialog that uses the Plasma style
|
||||
*
|
||||
* Dialog provides a dialog-like widget that can be used to display additional
|
||||
* information.
|
||||
*
|
||||
* Dialog uses the plasma theme, and usually has no window decoration. It's meant
|
||||
* as an interim solution to display widgets as extension to plasma applets, for
|
||||
* example when you click on an applet like the devicenotifier or the clock, the
|
||||
* widget that is then displayed, is a Dialog.
|
||||
*/
|
||||
class PLASMA_EXPORT Dialog : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Use these flags to choose the active resize corners.
|
||||
*/
|
||||
enum ResizeCorner {
|
||||
NoCorner = 0,
|
||||
NorthEast = 1,
|
||||
SouthEast = 2,
|
||||
NorthWest = 4,
|
||||
SouthWest = 8,
|
||||
All = NorthEast | SouthEast | NorthWest | SouthWest
|
||||
};
|
||||
Q_DECLARE_FLAGS(ResizeCorners, ResizeCorner)
|
||||
|
||||
/**
|
||||
* @arg parent the parent widget, for plasmoids, this is usually 0.
|
||||
* @arg f the Qt::WindowFlags, default is to not show a windowborder.
|
||||
*/
|
||||
explicit Dialog(QWidget * parent = 0, Qt::WindowFlags f = Qt::Window);
|
||||
virtual ~Dialog();
|
||||
|
||||
void setGraphicsWidget(QGraphicsWidget *widget);
|
||||
QGraphicsWidget *graphicsWidget();
|
||||
|
||||
/**
|
||||
* @arg corners the corners the resize handlers should be placed in.
|
||||
*/
|
||||
void setResizeHandleCorners(ResizeCorners corners);
|
||||
|
||||
/**
|
||||
* Convenience method to get the enabled resize corners.
|
||||
* @return which resize corners are active.
|
||||
*/
|
||||
ResizeCorners resizeCorners() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Fires when the dialog automatically resizes.
|
||||
*/
|
||||
void dialogResized();
|
||||
|
||||
/**
|
||||
* Emit a signal when the dialog become visible/invisible
|
||||
*/
|
||||
void dialogVisible(bool status);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Reimplemented from QWidget
|
||||
*/
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
void hideEvent (QHideEvent *event);
|
||||
void showEvent (QShowEvent *event);
|
||||
void mouseMoveEvent (QMouseEvent *event);
|
||||
void mousePressEvent (QMouseEvent *event);
|
||||
void mouseReleaseEvent (QMouseEvent *event);
|
||||
|
||||
/**
|
||||
* Convenience method to know whether the point is in a control area (e.g. resize area)
|
||||
* or not.
|
||||
* @return true if the point is in the control area.
|
||||
*/
|
||||
bool inControlArea(const QPoint &point);
|
||||
|
||||
private:
|
||||
DialogPrivate *const d;
|
||||
|
||||
friend class DialogPrivate;
|
||||
/**
|
||||
* React to theme changes
|
||||
*/
|
||||
Q_PRIVATE_SLOT(d, void themeUpdated())
|
||||
};
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::Dialog::ResizeCorners)
|
||||
|
||||
#endif
|
147
effects/blur.cpp
Normal file
147
effects/blur.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
/* 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))));
|
||||
|
||||
for (int row=0; row<img.height(); row++) {
|
||||
blurrow<aprec,zprec>(img, row, alpha);
|
||||
}
|
||||
|
||||
for (int col=0; col<img.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);
|
||||
|
||||
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<im.width(); index++) {
|
||||
blurinner<aprec,zprec>((unsigned char *)&ptr[index],zR,zG,zB,zA,alpha);
|
||||
}
|
||||
for (int index=im.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;
|
||||
|
||||
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=im.width(); index<(im.height()-1)*im.width(); index+=im.width()) {
|
||||
blurinner<aprec,zprec>((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
|
||||
}
|
||||
|
||||
for (int index=(im.height()-2)*im.width(); index>=0; index-=im.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
|
446
extender.cpp
Normal file
446
extender.cpp
Normal file
@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Copyright 2008 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
|
||||
*/
|
||||
|
||||
#include "extender.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QGraphicsGridLayout>
|
||||
#include <QGraphicsLinearLayout>
|
||||
|
||||
#include "applet.h"
|
||||
#include "containment.h"
|
||||
#include "corona.h"
|
||||
#include "extenderitem.h"
|
||||
#include "framesvg.h"
|
||||
#include "popupapplet.h"
|
||||
#include "svg.h"
|
||||
#include "widgets/label.h"
|
||||
|
||||
#include "private/applet_p.h"
|
||||
#include "private/extender_p.h"
|
||||
#include "private/extenderitem_p.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
Extender::Extender(Applet *applet)
|
||||
: QGraphicsWidget(applet),
|
||||
d(new ExtenderPrivate(applet, this))
|
||||
{
|
||||
//At multiple places in the extender code, we make the assumption that an applet doesn't have
|
||||
//more then one extender. If a second extender is created, destroy the first one to avoid leaks.
|
||||
if (applet->d->extender) {
|
||||
kWarning() << "Applet already has an extender, and can have only one extender."
|
||||
<< "The previous extender will be destroyed.";
|
||||
delete applet->d->extender;
|
||||
}
|
||||
applet->d->extender = this;
|
||||
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
d->layout = new QGraphicsLinearLayout(this);
|
||||
d->layout->setOrientation(Qt::Vertical);
|
||||
d->layout->setContentsMargins(0, 0, 0, 0);
|
||||
d->layout->setSpacing(0);
|
||||
setLayout(d->layout);
|
||||
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
|
||||
d->emptyExtenderLabel = new Label(this);
|
||||
d->emptyExtenderLabel->setText(d->emptyExtenderMessage);
|
||||
d->emptyExtenderLabel->setMinimumSize(QSizeF(150, 64));
|
||||
d->emptyExtenderLabel->setPreferredSize(QSizeF(200, 64));
|
||||
d->emptyExtenderLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
d->layout->addItem(d->emptyExtenderLabel);
|
||||
|
||||
d->loadExtenderItems();
|
||||
}
|
||||
|
||||
Extender::~Extender()
|
||||
{
|
||||
d->applet->d->extender = 0;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Extender::setEmptyExtenderMessage(const QString &message)
|
||||
{
|
||||
d->emptyExtenderMessage = message;
|
||||
|
||||
if (d->emptyExtenderLabel) {
|
||||
d->emptyExtenderLabel->setText(message);
|
||||
}
|
||||
}
|
||||
|
||||
QString Extender::emptyExtenderMessage() const
|
||||
{
|
||||
return d->emptyExtenderMessage;
|
||||
}
|
||||
|
||||
QList<ExtenderItem*> Extender::items() const
|
||||
{
|
||||
QList<ExtenderItem*> result;
|
||||
|
||||
//FIXME: a triple nested loop ... ew. there should be a more efficient way to do this
|
||||
//iterate through all extenders we can find and check each extenders source applet.
|
||||
foreach (Containment *c, d->applet->containment()->corona()->containments()) {
|
||||
foreach (Applet *applet, c->applets()) {
|
||||
if (applet->d->extender) {
|
||||
foreach (ExtenderItem *item, applet->d->extender->attachedItems()) {
|
||||
if (item->d->sourceApplet == d->applet) {
|
||||
result.append(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<ExtenderItem*> Extender::attachedItems() const
|
||||
{
|
||||
return d->attachedExtenderItems;
|
||||
}
|
||||
|
||||
QList<ExtenderItem*> Extender::detachedItems() const
|
||||
{
|
||||
QList<ExtenderItem*> result;
|
||||
|
||||
foreach (ExtenderItem *item, items()) {
|
||||
if (item->isDetached()) {
|
||||
result.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ExtenderItem *Extender::item(const QString &name) const
|
||||
{
|
||||
foreach (ExtenderItem *item, items()) {
|
||||
if (item->name() == name) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Extender::setAppearance(Appearance appearance)
|
||||
{
|
||||
if (d->appearance == appearance) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->appearance = appearance;
|
||||
d->updateBorders();
|
||||
}
|
||||
|
||||
Extender::Appearance Extender::appearance() const
|
||||
{
|
||||
return d->appearance;
|
||||
}
|
||||
|
||||
void Extender::saveState()
|
||||
{
|
||||
foreach (ExtenderItem *item, attachedItems()) {
|
||||
item->config().writeEntry("extenderItemPosition", item->geometry().y());
|
||||
}
|
||||
}
|
||||
|
||||
QVariant Extender::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == QGraphicsItem::ItemPositionHasChanged) {
|
||||
d->adjustSize();
|
||||
}
|
||||
|
||||
return QGraphicsWidget::itemChange(change, value);
|
||||
}
|
||||
|
||||
void Extender::resizeEvent(QGraphicsSceneResizeEvent *event)
|
||||
{
|
||||
QGraphicsWidget::resizeEvent(event);
|
||||
emit geometryChanged();
|
||||
}
|
||||
|
||||
void Extender::itemAddedEvent(ExtenderItem *item, const QPointF &pos)
|
||||
{
|
||||
//this is a sane size policy imo.
|
||||
item->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
|
||||
if (pos == QPointF(-1, -1)) {
|
||||
d->layout->addItem(item);
|
||||
} else {
|
||||
d->layout->insertItem(d->insertIndexFromPos(pos), item);
|
||||
}
|
||||
|
||||
//remove the empty extender message if needed.
|
||||
if (d->emptyExtenderLabel) {
|
||||
d->layout->removeItem(d->emptyExtenderLabel);
|
||||
d->emptyExtenderLabel->hide();
|
||||
}
|
||||
|
||||
d->adjustSize();
|
||||
}
|
||||
|
||||
void Extender::itemRemovedEvent(ExtenderItem *item)
|
||||
{
|
||||
d->layout->removeItem(item);
|
||||
|
||||
//add the empty extender message if needed.
|
||||
if (!attachedItems().count() && !d->spacerWidget) {
|
||||
d->emptyExtenderLabel->show();
|
||||
d->emptyExtenderLabel->setMinimumSize(item->size());
|
||||
//just in case:
|
||||
d->layout->removeItem(d->emptyExtenderLabel);
|
||||
d->layout->addItem(d->emptyExtenderLabel);
|
||||
}
|
||||
|
||||
d->adjustSize();
|
||||
}
|
||||
|
||||
void Extender::itemHoverEnterEvent(ExtenderItem *item)
|
||||
{
|
||||
itemHoverMoveEvent(item, QPointF(0, 0));
|
||||
}
|
||||
|
||||
void Extender::itemHoverMoveEvent(ExtenderItem *item, const QPointF &pos)
|
||||
{
|
||||
int insertIndex = d->insertIndexFromPos(pos);
|
||||
|
||||
if ((insertIndex == d->currentSpacerIndex) || (insertIndex == -1)) {
|
||||
//relayouting is resource intensive, so don't do that when not necesarry.
|
||||
return;
|
||||
}
|
||||
|
||||
//Make sure we remove any spacer that might already be in the layout.
|
||||
itemHoverLeaveEvent(item);
|
||||
|
||||
d->currentSpacerIndex = insertIndex;
|
||||
|
||||
//Create a widget that functions as spacer, and add that to the layout.
|
||||
QGraphicsWidget *widget = new QGraphicsWidget(this);
|
||||
widget->setMinimumSize(QSizeF(item->minimumSize().width(), item->size().height()));
|
||||
widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
d->spacerWidget = widget;
|
||||
d->layout->insertItem(insertIndex, widget);
|
||||
|
||||
//Make sure we remove any 'no detachables' label that might be there, and update the layout.
|
||||
//XXX: duplicated from itemAttachedEvent.
|
||||
if (d->emptyExtenderLabel) {
|
||||
d->layout->removeItem(d->emptyExtenderLabel);
|
||||
d->emptyExtenderLabel->hide();
|
||||
}
|
||||
|
||||
d->adjustSize();
|
||||
}
|
||||
|
||||
void Extender::itemHoverLeaveEvent(ExtenderItem *item)
|
||||
{
|
||||
Q_UNUSED(item);
|
||||
|
||||
if (d->spacerWidget) {
|
||||
//Remove any trace of the spacer widget.
|
||||
d->layout->removeItem(d->spacerWidget);
|
||||
delete d->spacerWidget;
|
||||
d->spacerWidget = 0;
|
||||
|
||||
d->currentSpacerIndex = -1;
|
||||
|
||||
//Make sure we add a 'no detachables' label when the layout is empty.
|
||||
if (!attachedItems().count()) {
|
||||
d->emptyExtenderLabel->show();
|
||||
d->emptyExtenderLabel->setMinimumSize(item->size());
|
||||
d->layout->removeItem(d->emptyExtenderLabel);
|
||||
d->layout->addItem(d->emptyExtenderLabel);
|
||||
}
|
||||
|
||||
d->adjustSize();
|
||||
}
|
||||
}
|
||||
|
||||
FrameSvg::EnabledBorders Extender::enabledBordersForItem(ExtenderItem *item) const
|
||||
{
|
||||
ExtenderItem *topItem = dynamic_cast<ExtenderItem*>(d->layout->itemAt(0));
|
||||
ExtenderItem *bottomItem = dynamic_cast<ExtenderItem*>(d->layout->itemAt(d->layout->count() - 1));
|
||||
if (d->appearance == TopDownStacked && bottomItem != item) {
|
||||
return FrameSvg::LeftBorder | FrameSvg::BottomBorder | FrameSvg::RightBorder;
|
||||
} else if (d->appearance == BottomUpStacked && topItem != item) {
|
||||
return FrameSvg::LeftBorder | FrameSvg::TopBorder | FrameSvg::RightBorder;
|
||||
} else if (d->appearance != NoBorders) {
|
||||
return FrameSvg::LeftBorder | FrameSvg::RightBorder;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ExtenderPrivate::ExtenderPrivate(Applet *applet, Extender *extender) :
|
||||
q(extender),
|
||||
applet(applet),
|
||||
currentSpacerIndex(-1),
|
||||
spacerWidget(0),
|
||||
emptyExtenderMessage(i18n("no items")),
|
||||
emptyExtenderLabel(0),
|
||||
popup(false),
|
||||
appearance(Extender::NoBorders)
|
||||
{
|
||||
}
|
||||
|
||||
ExtenderPrivate::~ExtenderPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
void ExtenderPrivate::addExtenderItem(ExtenderItem *item, const QPointF &pos)
|
||||
{
|
||||
attachedExtenderItems.append(item);
|
||||
q->itemHoverLeaveEvent(item);
|
||||
q->itemAddedEvent(item, pos);
|
||||
updateBorders();
|
||||
emit q->itemAttached(item);
|
||||
}
|
||||
|
||||
void ExtenderPrivate::removeExtenderItem(ExtenderItem *item)
|
||||
{
|
||||
attachedExtenderItems.removeOne(item);
|
||||
|
||||
//collapse the popupapplet if the last item is removed.
|
||||
if (!q->attachedItems().count()) {
|
||||
PopupApplet *popupApplet = qobject_cast<PopupApplet*>(applet);
|
||||
if (popupApplet) {
|
||||
popupApplet->hidePopup();
|
||||
}
|
||||
}
|
||||
|
||||
q->itemRemovedEvent(item);
|
||||
updateBorders();
|
||||
}
|
||||
|
||||
int ExtenderPrivate::insertIndexFromPos(const QPointF &pos) const
|
||||
{
|
||||
int insertIndex = -1;
|
||||
|
||||
//XXX: duplicated from panel
|
||||
if (pos != QPointF(-1, -1)) {
|
||||
for (int i = 0; i < layout->count(); ++i) {
|
||||
QRectF siblingGeometry = layout->itemAt(i)->geometry();
|
||||
qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
|
||||
if (pos.y() < middle) {
|
||||
insertIndex = i;
|
||||
break;
|
||||
} else if (pos.y() <= siblingGeometry.bottom()) {
|
||||
insertIndex = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return insertIndex;
|
||||
}
|
||||
|
||||
void ExtenderPrivate::loadExtenderItems()
|
||||
{
|
||||
KConfigGroup cg = applet->config("ExtenderItems");
|
||||
|
||||
//first create a list of extenderItems, and then sort them on their position, so the items get
|
||||
//recreated in the correct order.
|
||||
//TODO: this restoring of the correct order should now be done in itemAddedEvent instead of
|
||||
//here, to allow easy subclassing of Extender.
|
||||
QList<QPair<int, QString> > groupList;
|
||||
foreach (const QString &extenderItemId, cg.groupList()) {
|
||||
KConfigGroup dg = cg.group(extenderItemId);
|
||||
groupList.append(qMakePair(dg.readEntry("extenderItemPosition", 0), extenderItemId));
|
||||
}
|
||||
qSort(groupList);
|
||||
|
||||
//iterate over the extender items
|
||||
for (int i = 0; i < groupList.count(); i++) {
|
||||
QPair<int, QString> pair = groupList[i];
|
||||
KConfigGroup dg = cg.group(pair.second);
|
||||
|
||||
//load the relevant settings.
|
||||
QString extenderItemId = dg.name();
|
||||
QString extenderItemName = dg.readEntry("extenderItemName", "");
|
||||
QString appletName = dg.readEntry("sourceAppletPluginName", "");
|
||||
uint sourceAppletId = dg.readEntry("sourceAppletId", 0);
|
||||
|
||||
bool temporarySourceApplet = false;
|
||||
|
||||
//find the source applet.
|
||||
Corona *corona = applet->containment()->corona();
|
||||
Applet *sourceApplet = 0;
|
||||
foreach (Containment *containment, corona->containments()) {
|
||||
foreach (Applet *applet, containment->applets()) {
|
||||
if (applet->id() == sourceAppletId) {
|
||||
sourceApplet = applet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//There is no source applet. We just instantiate one just for the sake of creating
|
||||
//detachables.
|
||||
if (!sourceApplet) {
|
||||
kDebug() << "creating a temporary applet as factory";
|
||||
sourceApplet = Applet::load(appletName);
|
||||
temporarySourceApplet = true;
|
||||
//TODO: maybe add an option to applet to indicate that it shouldn't be deleted after
|
||||
//having used it as factory.
|
||||
}
|
||||
|
||||
if (!sourceApplet) {
|
||||
kDebug() << "sourceApplet is null? appletName = " << appletName;
|
||||
kDebug() << " extenderItemId = " << extenderItemId;
|
||||
} else {
|
||||
ExtenderItem *item = new ExtenderItem(q, extenderItemId.toInt());
|
||||
item->setName(extenderItemName);
|
||||
sourceApplet->initExtenderItem(item);
|
||||
|
||||
if (temporarySourceApplet) {
|
||||
delete sourceApplet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void ExtenderPrivate::updateBorders()
|
||||
{
|
||||
foreach (ExtenderItem *item, q->attachedItems()) {
|
||||
if (item && (item->d->background->enabledBorders() != q->enabledBordersForItem(item))) {
|
||||
//call themeChanged to change the backgrounds enabled borders, and move all contained
|
||||
//widgets according to it's changed margins.
|
||||
item->d->themeChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtenderPrivate::adjustSize()
|
||||
{
|
||||
if (q->layout()) {
|
||||
q->layout()->updateGeometry();
|
||||
//FIXME: for some reason the preferred size hint get's set correctly,
|
||||
//but the minimumSizeHint doesn't. Investigate why.
|
||||
q->setMinimumSize(q->layout()->preferredSize());
|
||||
}
|
||||
|
||||
emit q->geometryChanged();
|
||||
}
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "extender.moc"
|
250
extender.h
Normal file
250
extender.h
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright 2008 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 PLASMA_EXTENDER_H
|
||||
#define PLASMA_EXTENDER_H
|
||||
|
||||
#include <QtGui/QGraphicsWidget>
|
||||
|
||||
#include "plasma/framesvg.h"
|
||||
#include "plasma/plasma_export.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
class ExtenderPrivate;
|
||||
class ExtenderItem;
|
||||
class Applet;
|
||||
|
||||
/**
|
||||
* @class Extender plasma/extender.h <Plasma/Extender>
|
||||
*
|
||||
* @short Extends applets to allow detachable parts
|
||||
*
|
||||
* An Extender is a widget that visually extends the normal contents of an applet with
|
||||
* additional dynamic widgets called ExtenderItems. These ExtenderItems can be
|
||||
* detached by the user and dropped either on another Extender or on the canvas directly.
|
||||
*
|
||||
* This widget allows using ExtenderItems in your applet. Extender takes care of the presentation
|
||||
* of a collection of ExtenderItems and keeps track of ExtenderItems that originate in it.
|
||||
*
|
||||
* The default Extender implementation displays extender items in a vertical layout with
|
||||
* spacers that appear when dropping an ExtenderItem over it.
|
||||
*
|
||||
* If you wish to have a different presentation of extender items, you can choose to subclass
|
||||
* Extender and reimplement the extenderItem* events and, optionally, the saveState function.
|
||||
*
|
||||
* To use an Extender in you applet, you'll have to instantiate one. A call to extender() in your
|
||||
* applet will create an extender on your applet if you haven't got one already. Every applet can
|
||||
* contain only one extender. Think of it as a decorator that adds some functionality to applets
|
||||
* that require it. Never instantiate an Extender before init() in your applet. This won't work
|
||||
* correctly since a scene is required when an Extender is instantiated.
|
||||
*
|
||||
* As soon as an Extender is instantiated, ExtenderItems contained previously in this Extender are
|
||||
* restored using the initExtenderItem function from the applet the items originally came from. For
|
||||
* more information on how this works and how to use ExtenderItems in general, see the ExtenderItem
|
||||
* API documentation.
|
||||
*/
|
||||
class PLASMA_EXPORT Extender : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString emptyExtenderMessage READ emptyExtenderMessage WRITE setEmptyExtenderMessage)
|
||||
|
||||
public:
|
||||
/**
|
||||
* Description on how to render the extender's items.
|
||||
*/
|
||||
enum Appearance {
|
||||
NoBorders = 0, /**< Draws no borders on the extender's items. When placed in an applet
|
||||
on the desktop, use this setting and use the standard margins of
|
||||
the applet containing this extender. */
|
||||
BottomUpStacked = 1, /**< Draws no borders on the topmost extenderitem, but draws the
|
||||
left, top and right border on subsequent items. When margins
|
||||
of the containing dialog are set to 0, except for the top
|
||||
margin, this leads to the 'stacked' look, recommended for
|
||||
extenders of applet's contained in a panel at the bottom of
|
||||
the screen. */
|
||||
TopDownStacked = 2 /**< Draws no borders on the bottom extenderitem, but draws the
|
||||
left, bottom and right border on subsequent items. When margins
|
||||
of the containing dialog are set to 0, except for the bottom
|
||||
margin, this leads to the 'stacked' look, recommended for
|
||||
extenders of applet's contained in a panel at the top of
|
||||
the screen. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an extender. Note that extender expects applet to have a config(), and needs a
|
||||
* scene because of that. So you should only instantiate an extender in init() or later, not
|
||||
* in an applet's constructor.
|
||||
* The constructor also takes care of restoring ExtenderItems that were contained in this
|
||||
* extender before, so ExtenderItems are persistent between sessions.
|
||||
* @param applet The applet this extender is part of. Null is not allowed here.
|
||||
*/
|
||||
explicit Extender(Applet *applet);
|
||||
|
||||
~Extender();
|
||||
|
||||
/**
|
||||
* @param message The text to be shown whenever the applet's extender is empty.
|
||||
* Defaults to i18n'ed "no items".
|
||||
*/
|
||||
void setEmptyExtenderMessage(const QString &message);
|
||||
|
||||
/**
|
||||
* @return The text to be shown whenever the applet's layout is empty.
|
||||
*/
|
||||
QString emptyExtenderMessage() const;
|
||||
|
||||
/**
|
||||
* @returns a list of all extender items (attached AND detached) where the source applet is
|
||||
* this applet.
|
||||
*/
|
||||
QList<ExtenderItem*> items() const;
|
||||
|
||||
/**
|
||||
* @returns a list of all attached extender items.
|
||||
*/
|
||||
QList<ExtenderItem*> attachedItems() const;
|
||||
|
||||
/**
|
||||
* @returns a list of all detached extender items.
|
||||
*/
|
||||
QList<ExtenderItem*> detachedItems() const;
|
||||
|
||||
/**
|
||||
* This function can be used for easily determining if a certain item is already displayed
|
||||
* in a extender item somewhere, so your applet doesn't duplicate this item. Say the applet
|
||||
* displays 'jobs', from an engine which add's a source for every job. In sourceAdded you
|
||||
* could do something like:
|
||||
* if (!item(source)) {
|
||||
* //add an extender item monitoring this source.
|
||||
* }
|
||||
*/
|
||||
ExtenderItem *item(const QString &name) const;
|
||||
|
||||
/**
|
||||
* Use this function to instruct the extender on how to render it's items. Usually you will
|
||||
* want to call this function in your applet's constraintsEvent, allthough this is already
|
||||
* done for you when using PopupApplet at base class for your applet. Defaults to NoBorders.
|
||||
*/
|
||||
void setAppearance(Appearance appearance);
|
||||
|
||||
/**
|
||||
* @return the current way of rendering extender items that is used.
|
||||
*/
|
||||
Appearance appearance() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Get's called after an item has been added to this extender. The bookkeeping has already
|
||||
* been done when this function get's called. The only thing left to do is put it somewhere
|
||||
* appropriate. The default implementation adds the extenderItem to the appropriate place in
|
||||
* a QGraphicsLinearLayout.
|
||||
* @param item The item that has just been added.
|
||||
* @param pos The location the item has been dropped in local coordinates.
|
||||
*/
|
||||
virtual void itemAddedEvent(ExtenderItem *item, const QPointF &pos);
|
||||
|
||||
/**
|
||||
* Get's called after an item has been removed from this extender. All bookkeeping has
|
||||
* already been done when this function get's called.
|
||||
* @param item The item that has just been removed.
|
||||
*/
|
||||
virtual void itemRemovedEvent(ExtenderItem *item);
|
||||
|
||||
/**
|
||||
* Get's called when an ExtenderItem that get's dragged enters this extender. Default
|
||||
* implementation does nothing.
|
||||
*/
|
||||
virtual void itemHoverEnterEvent(ExtenderItem *item);
|
||||
|
||||
/**
|
||||
* Gets called when an ExtenderItem is hovering over this extender. Implement this function
|
||||
* to give some visual feedback about what will happen when the mouse button is released at
|
||||
* that position. The default implementation shows a spacer at the appropriate location in
|
||||
* the layout.
|
||||
* @param item The item that's hovering over this extender. Most useful for obtaining the
|
||||
* size of the spacer.
|
||||
* @param pos The location the item is hovering.
|
||||
*/
|
||||
virtual void itemHoverMoveEvent(ExtenderItem *item, const QPointF &pos);
|
||||
|
||||
/**
|
||||
* Get's called when an ExtenderItem that was previously hovering over this extender moves
|
||||
* away from this extender. The default implementation removes any spacer from the layout.
|
||||
*/
|
||||
virtual void itemHoverLeaveEvent(ExtenderItem *item);
|
||||
|
||||
/**
|
||||
* This function get's called for every extender when plasma exits. Implement this function
|
||||
* to store the current state of this extender (position in a layout for example), so this
|
||||
* can be restored when applet starts again. The default implementation stores the y
|
||||
* coordinate of every extender item in the config field extenderItemPos.
|
||||
*/
|
||||
virtual void saveState();
|
||||
|
||||
/**
|
||||
* This function get's called on every item to determine which background border's to
|
||||
* render.
|
||||
* @param item the item for which it's position or extender has changed.
|
||||
* @return the borders that have to be enabled on it's background.
|
||||
*/
|
||||
virtual FrameSvg::EnabledBorders enabledBordersForItem(ExtenderItem *item) const;
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsWidget
|
||||
*/
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
||||
|
||||
/**
|
||||
* Reimplemented from QGraphicsWidget
|
||||
*/
|
||||
void resizeEvent(QGraphicsSceneResizeEvent *event);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Fires when an extender item is added to this extender.
|
||||
*/
|
||||
void itemAttached(Plasma::ExtenderItem *);
|
||||
|
||||
/**
|
||||
* Fires when an extender item is removed from this extender.
|
||||
*/
|
||||
void itemDetached(Plasma::ExtenderItem *);
|
||||
|
||||
/**
|
||||
* Fires when an extender's preferred size changes.
|
||||
*/
|
||||
void geometryChanged();
|
||||
|
||||
private:
|
||||
ExtenderPrivate *const d;
|
||||
|
||||
friend class ExtenderPrivate;
|
||||
friend class ExtenderItem;
|
||||
friend class ExtenderItemPrivate;
|
||||
//dialog needs access to the extender's applet location.
|
||||
friend class DialogPrivate;
|
||||
//applet should be able to call saveState();
|
||||
friend class Applet;
|
||||
|
||||
};
|
||||
} // Plasma namespace
|
||||
|
||||
#endif //PLASMA_EXTENDER_H
|
||||
|
1001
extenderitem.cpp
Normal file
1001
extenderitem.cpp
Normal file
File diff suppressed because it is too large
Load Diff
257
extenderitem.h
Normal file
257
extenderitem.h
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright 2008 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 PLASMA_EXTENDERITEM_H
|
||||
#define PLASMA_EXTENDERITEM_H
|
||||
|
||||
#include <QtGui/QGraphicsWidget>
|
||||
|
||||
#include <KDE/KConfigGroup>
|
||||
#include <KDE/KIcon>
|
||||
|
||||
#include "plasma/plasma_export.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class Applet;
|
||||
class Extender;
|
||||
class ExtenderItemPrivate;
|
||||
|
||||
/**
|
||||
* @class ExtenderItem plasma/extenderitem.h <Plasma/ExtenderItem>
|
||||
*
|
||||
* @short Provides detachable items for an Extender
|
||||
*
|
||||
* This class wraps around a QGraphicsWidget and provides drag&drop handling, a draghandle,
|
||||
* title and ability to display qactions as a row of icon, ability to expand, collapse, return
|
||||
* to source and tracks configuration associated with this item for you.
|
||||
*
|
||||
* Typical usage of ExtenderItems in your applet could look like this:
|
||||
*
|
||||
* @code
|
||||
* ExtenderItem *item = new ExtenderItem(extender());
|
||||
* //name can be used to later access this item through extender()->item(name):
|
||||
* item->setName("networkmonitoreth0");
|
||||
* item->config().writeEntry("device", "eth0");
|
||||
* initExtenderItem(item);
|
||||
* @endcode
|
||||
*
|
||||
* You'll then need to implement the initExtenderItem function. Having this function in your applet
|
||||
* makes sure that detached extender items get restored after plasma is restarted, just like applets
|
||||
* are. That is also the reason that we write an entry in item->config().
|
||||
* In this function you should instantiate a QGraphicsWidget or QGraphicsItem and call the
|
||||
* setWidget function on the ExtenderItem. This is the only correct way of adding actual content to
|
||||
* a extenderItem. An example:
|
||||
*
|
||||
* @code
|
||||
* void MyApplet::initExtenderItem(Plasma::ExtenderItem *item)
|
||||
* {
|
||||
* QGraphicsWidget *myNetworkMonitorWidget = new NetworkMonitorWidget(item);
|
||||
* dataEngine("networktraffic")->connectSource(item->config().readEntry("device", ""),
|
||||
* myNetworkMonitorWidget);
|
||||
* item->setWidget(myNetworkMonitorWidget);
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
class PLASMA_EXPORT ExtenderItem : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QGraphicsItem * widget READ widget WRITE setWidget)
|
||||
Q_PROPERTY(QString title READ title WRITE setTitle)
|
||||
Q_PROPERTY(QString name READ name WRITE setName)
|
||||
Q_PROPERTY(QIcon icon READ icon WRITE setIcon)
|
||||
Q_PROPERTY(Extender * extender READ extender WRITE setExtender)
|
||||
Q_PROPERTY(bool collapsed READ isCollapsed WRITE setCollapsed)
|
||||
Q_PROPERTY(bool detached READ isDetached)
|
||||
Q_PROPERTY(uint autoExpireDelay WRITE setAutoExpireDelay)
|
||||
|
||||
public:
|
||||
/**
|
||||
* The constructor takes care of adding this item to an extender.
|
||||
* @param hostExtender The extender the extender item belongs to.
|
||||
* @param extenderItemId the id of the extender item. Use the default 0 to assign a new,
|
||||
* unique id to this extender item.
|
||||
*/
|
||||
explicit ExtenderItem(Extender *hostExtender, uint extenderItemId = 0);
|
||||
|
||||
~ExtenderItem();
|
||||
|
||||
/**
|
||||
* fetch the configuration of this widget.
|
||||
* @return the configuration of this widget.
|
||||
*/
|
||||
KConfigGroup config() const;
|
||||
|
||||
/**
|
||||
* @param widget The widget that should be wrapped into the extender item.
|
||||
*/
|
||||
void setWidget(QGraphicsItem *widget);
|
||||
|
||||
/**
|
||||
* @return The widget that is wrapped into the extender item.
|
||||
*/
|
||||
QGraphicsItem *widget() const;
|
||||
|
||||
/**
|
||||
* @param title the title that will be shown in the extender item's dragger. Default is
|
||||
* no title. This title will also be stored in the item's configuration, so you don't have
|
||||
* to manually store/restore this information for your extender items.
|
||||
*/
|
||||
void setTitle(const QString &title);
|
||||
|
||||
/**
|
||||
* @return the title shown in the extender item's dragger.
|
||||
*/
|
||||
QString title() const;
|
||||
|
||||
/**
|
||||
* You can assign names to extender items to look them up through the item() function.
|
||||
* Make sure you only use unique names. This name will be stored in the item's
|
||||
* configuration.
|
||||
* @param name the name of the item. Defaults to an empty string.
|
||||
*/
|
||||
void setName(const QString &name);
|
||||
|
||||
/**
|
||||
* @return the name of the item.
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* @param icon the icon name to display in the extender item's
|
||||
* drag handle. Defaults to the source applet's icon. This icon name will also be stored
|
||||
* in the item's configuration, so you don't have to manually store/restore this
|
||||
* information.
|
||||
*/
|
||||
void setIcon(const QString &icon);
|
||||
|
||||
/**
|
||||
* @param icon the icon to display in the extender item's drag handle. Defaults to the
|
||||
* source applet's icon.
|
||||
*/
|
||||
void setIcon(const QIcon &icon);
|
||||
|
||||
/**
|
||||
* @return the icon being displayed in the extender item's drag handle.
|
||||
*/
|
||||
QIcon icon() const;
|
||||
|
||||
/**
|
||||
* @param extender the extender this item belongs to.
|
||||
* @param pos the position in the extender this item should be added. Defaults to 'just
|
||||
* append'.
|
||||
*/
|
||||
void setExtender(Extender *extender, const QPointF &pos = QPointF(-1, -1));
|
||||
|
||||
/**
|
||||
* @return the extender this items belongs to.
|
||||
*/
|
||||
Extender *extender() const;
|
||||
|
||||
/**
|
||||
* @param time (in ms) before this extender item destroys itself unless it is detached,
|
||||
* in which case this extender stays around. 0 means forever and is the default.
|
||||
*/
|
||||
void setAutoExpireDelay(uint time);
|
||||
|
||||
/**
|
||||
* @return whether or not this extender item has an auto expire delay.
|
||||
*/
|
||||
uint autoExpireDelay() const;
|
||||
|
||||
/**
|
||||
* @return whether or not this item is detached from it's original source.
|
||||
*/
|
||||
bool isDetached() const;
|
||||
|
||||
/**
|
||||
* @return whether or not the extender item is collapsed.
|
||||
*/
|
||||
bool isCollapsed() const;
|
||||
|
||||
/**
|
||||
* @param name the name to store the action under in our collection.
|
||||
* @param action the action to add. Actions will be displayed as an icon in the drag
|
||||
* handle.
|
||||
*/
|
||||
void addAction(const QString &name, QAction *action);
|
||||
|
||||
/**
|
||||
* @return the QAction with the given name from our collection. By default the action
|
||||
* collection contains a "movebacktosource" action which will be only shown when the
|
||||
* item is detached.
|
||||
*/
|
||||
QAction *action(const QString &name) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Destroys the extender item. As opposed to calling delete on this class, destroy also
|
||||
* removes the config group associated with this item.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Collapse or expand the extender item. Defaults to false.
|
||||
*/
|
||||
void setCollapsed(bool collapsed);
|
||||
|
||||
/**
|
||||
* Returns the extender item to its source applet.
|
||||
*/
|
||||
void returnToSource();
|
||||
|
||||
/**
|
||||
* Shows a close button in this item's drag handle. By default a close button will not be
|
||||
* shown.
|
||||
*/
|
||||
void showCloseButton();
|
||||
|
||||
/**
|
||||
* Hides the close button in this item's drag handle.
|
||||
*/
|
||||
void hideCloseButton();
|
||||
|
||||
protected:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
||||
|
||||
void resizeEvent(QGraphicsSceneResizeEvent *event);
|
||||
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
|
||||
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
|
||||
private:
|
||||
Q_PRIVATE_SLOT(d, void toggleCollapse())
|
||||
Q_PRIVATE_SLOT(d, void updateToolBox())
|
||||
Q_PRIVATE_SLOT(d, void themeChanged())
|
||||
Q_PRIVATE_SLOT(d, void sourceAppletRemoved())
|
||||
|
||||
ExtenderItemPrivate * const d;
|
||||
|
||||
friend class Extender;
|
||||
friend class ExtenderPrivate;
|
||||
};
|
||||
} // namespace Plasma
|
||||
#endif // PLASMA_EXTENDERITEM_H
|
676
framesvg.cpp
Normal file
676
framesvg.cpp
Normal file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "framesvg.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QSize>
|
||||
#include <QBitmap>
|
||||
|
||||
#include <KDebug>
|
||||
|
||||
#include <plasma/theme.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class FrameData
|
||||
{
|
||||
public:
|
||||
FrameData()
|
||||
: enabledBorders(FrameSvg::AllBorders),
|
||||
frameSize(-1,-1)
|
||||
{
|
||||
}
|
||||
|
||||
FrameData(const FrameData &other)
|
||||
: enabledBorders(other.enabledBorders),
|
||||
frameSize(other.frameSize)
|
||||
{
|
||||
}
|
||||
|
||||
~FrameData()
|
||||
{
|
||||
}
|
||||
|
||||
FrameSvg::EnabledBorders enabledBorders;
|
||||
QPixmap cachedBackground;
|
||||
QBitmap cachedMask;
|
||||
QSizeF 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;
|
||||
};
|
||||
|
||||
class FrameSvgPrivate
|
||||
{
|
||||
public:
|
||||
FrameSvgPrivate(FrameSvg *psvg)
|
||||
: q(psvg),
|
||||
cacheAll(false)
|
||||
{
|
||||
}
|
||||
|
||||
~FrameSvgPrivate()
|
||||
{
|
||||
qDeleteAll(frames);
|
||||
frames.clear();
|
||||
}
|
||||
|
||||
void generateBackground(FrameData *frame);
|
||||
void updateSizes();
|
||||
void updateNeeded();
|
||||
void updateAndSignalSizes();
|
||||
|
||||
Location location;
|
||||
QString prefix;
|
||||
|
||||
FrameSvg *q;
|
||||
|
||||
bool cacheAll : 1;
|
||||
|
||||
QHash<QString, FrameData*> frames;
|
||||
};
|
||||
|
||||
FrameSvg::FrameSvg(QObject *parent)
|
||||
: Svg(parent),
|
||||
d(new FrameSvgPrivate(this))
|
||||
{
|
||||
connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateNeeded()));
|
||||
d->frames.insert(QString(), new FrameData());
|
||||
}
|
||||
|
||||
FrameSvg::~FrameSvg()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void FrameSvg::setImagePath(const QString &path)
|
||||
{
|
||||
if (path == imagePath()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Svg::setImagePath(path);
|
||||
setContainsMultipleImages(true);
|
||||
|
||||
clearCache();
|
||||
d->updateAndSignalSizes();
|
||||
}
|
||||
|
||||
void FrameSvg::setEnabledBorders(const EnabledBorders borders)
|
||||
{
|
||||
if (borders == d->frames[d->prefix]->enabledBorders) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->frames[d->prefix]->enabledBorders = borders;
|
||||
d->updateAndSignalSizes();
|
||||
}
|
||||
|
||||
FrameSvg::EnabledBorders FrameSvg::enabledBorders() const
|
||||
{
|
||||
QHash<QString, FrameData*>::const_iterator it = d->frames.constFind(d->prefix);
|
||||
|
||||
if (it != d->frames.constEnd()) {
|
||||
return it.value()->enabledBorders;
|
||||
} else {
|
||||
return NoBorder;
|
||||
}
|
||||
}
|
||||
|
||||
void FrameSvg::setElementPrefix(Plasma::Location location)
|
||||
{
|
||||
switch (location) {
|
||||
case TopEdge:
|
||||
setElementPrefix("north");
|
||||
break;
|
||||
case BottomEdge:
|
||||
setElementPrefix("south");
|
||||
break;
|
||||
case LeftEdge:
|
||||
setElementPrefix("west");
|
||||
break;
|
||||
case RightEdge:
|
||||
setElementPrefix("east");
|
||||
break;
|
||||
default:
|
||||
setElementPrefix(QString());
|
||||
break;
|
||||
}
|
||||
d->location = location;
|
||||
}
|
||||
|
||||
void FrameSvg::setElementPrefix(const QString & prefix)
|
||||
{
|
||||
const QString oldPrefix(d->prefix);
|
||||
|
||||
if (!hasElement(prefix + "-center")) {
|
||||
d->prefix.clear();
|
||||
} else {
|
||||
d->prefix = prefix;
|
||||
if (!d->prefix.isEmpty()) {
|
||||
d->prefix += '-';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (oldPrefix == d->prefix && d->frames[oldPrefix]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->frames.contains(d->prefix)) {
|
||||
d->frames.insert(d->prefix, new FrameData(*(d->frames[oldPrefix])));
|
||||
d->updateSizes();
|
||||
}
|
||||
|
||||
if (!d->cacheAll) {
|
||||
delete d->frames[oldPrefix];
|
||||
d->frames.remove(oldPrefix);
|
||||
}
|
||||
|
||||
d->location = Floating;
|
||||
}
|
||||
|
||||
bool FrameSvg::hasElementPrefix(const QString & prefix) const
|
||||
{
|
||||
//for now it simply checks if a center element exists,
|
||||
//because it could make sense for certain themes to not have all the elements
|
||||
if (prefix.isEmpty()) {
|
||||
return hasElement("center");
|
||||
} else {
|
||||
return hasElement(prefix + "-center");
|
||||
}
|
||||
}
|
||||
|
||||
bool FrameSvg::hasElementPrefix(Plasma::Location location) const
|
||||
{
|
||||
switch (location) {
|
||||
case TopEdge:
|
||||
return hasElementPrefix("north");
|
||||
break;
|
||||
case BottomEdge:
|
||||
return hasElementPrefix("south");
|
||||
break;
|
||||
case LeftEdge:
|
||||
return hasElementPrefix("west");
|
||||
break;
|
||||
case RightEdge:
|
||||
return hasElementPrefix("east");
|
||||
break;
|
||||
default:
|
||||
return hasElementPrefix(QString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString FrameSvg::prefix()
|
||||
{
|
||||
if (d->prefix.isEmpty()) {
|
||||
return d->prefix;
|
||||
}
|
||||
|
||||
return d->prefix.left(d->prefix.size() - 1);
|
||||
}
|
||||
|
||||
void FrameSvg::resizeFrame(const QSizeF &size)
|
||||
{
|
||||
if (size.isEmpty()) {
|
||||
kWarning() << "Invalid size" << size;
|
||||
return;
|
||||
}
|
||||
|
||||
if (size == d->frames[d->prefix]->frameSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->updateSizes();
|
||||
d->frames[d->prefix]->frameSize = size;
|
||||
}
|
||||
|
||||
QSizeF FrameSvg::frameSize() const
|
||||
{
|
||||
QHash<QString, FrameData*>::const_iterator it = d->frames.constFind(d->prefix);
|
||||
|
||||
if (it != d->frames.constEnd()) {
|
||||
return it.value()->frameSize;
|
||||
} else {
|
||||
return QSize(-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
qreal FrameSvg::marginSize(const Plasma::MarginEdge edge) const
|
||||
{
|
||||
if (d->frames[d->prefix]->noBorderPadding) {
|
||||
return .0;
|
||||
}
|
||||
|
||||
switch (edge) {
|
||||
case Plasma::TopMargin:
|
||||
return d->frames[d->prefix]->topMargin;
|
||||
break;
|
||||
|
||||
case Plasma::LeftMargin:
|
||||
return d->frames[d->prefix]->leftMargin;
|
||||
break;
|
||||
|
||||
case Plasma::RightMargin:
|
||||
return d->frames[d->prefix]->rightMargin;
|
||||
break;
|
||||
|
||||
//Plasma::BottomMargin
|
||||
default:
|
||||
return d->frames[d->prefix]->bottomMargin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FrameSvg::getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const
|
||||
{
|
||||
FrameData *frame = d->frames[d->prefix];
|
||||
|
||||
if (!frame || frame->noBorderPadding) {
|
||||
left = top = right = bottom = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
top = frame->topMargin;
|
||||
left = frame->leftMargin;
|
||||
right = frame->rightMargin;
|
||||
bottom = frame->bottomMargin;
|
||||
}
|
||||
|
||||
QRectF FrameSvg::contentsRect() const
|
||||
{
|
||||
QSizeF size(frameSize());
|
||||
|
||||
if (size.isValid()) {
|
||||
QRectF rect(QPointF(0, 0), size);
|
||||
FrameData *frame = d->frames[d->prefix];
|
||||
|
||||
return rect.adjusted(frame->leftMargin, frame->topMargin,
|
||||
-frame->rightMargin, -frame->bottomMargin);
|
||||
} else {
|
||||
return QRectF();
|
||||
}
|
||||
}
|
||||
|
||||
QBitmap FrameSvg::mask() const
|
||||
{
|
||||
FrameData *frame = d->frames[d->prefix];
|
||||
|
||||
if (!frame->cachedMask) {
|
||||
if (frame->cachedBackground.isNull()) {
|
||||
d->generateBackground(frame);
|
||||
if (frame->cachedBackground.isNull()) {
|
||||
return QBitmap();
|
||||
}
|
||||
}
|
||||
frame->cachedMask = QBitmap(frame->cachedBackground.alphaChannel().createMaskFromColor(Qt::black));
|
||||
}
|
||||
return frame->cachedMask;
|
||||
}
|
||||
|
||||
void FrameSvg::setCacheAllRenderedFrames(bool cache)
|
||||
{
|
||||
if (d->cacheAll && !cache) {
|
||||
clearCache();
|
||||
}
|
||||
|
||||
d->cacheAll = cache;
|
||||
}
|
||||
|
||||
bool FrameSvg::cacheAllRenderedFrames() const
|
||||
{
|
||||
return d->cacheAll;
|
||||
}
|
||||
|
||||
void FrameSvg::clearCache()
|
||||
{
|
||||
FrameData *frame = d->frames[d->prefix];
|
||||
|
||||
// delete all the frames that aren't this one
|
||||
QMutableHashIterator<QString, FrameData*> it(d->frames);
|
||||
while (it.hasNext()) {
|
||||
FrameData *p = it.next().value();
|
||||
if (frame != p) {
|
||||
delete p;
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap FrameSvg::framePixmap()
|
||||
{
|
||||
FrameData *frame = d->frames[d->prefix];
|
||||
if (frame->cachedBackground.isNull()) {
|
||||
d->generateBackground(frame);
|
||||
if (frame->cachedBackground.isNull()) {
|
||||
return QPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
return frame->cachedBackground;
|
||||
}
|
||||
|
||||
void FrameSvg::paintFrame(QPainter *painter, const QRectF &target, const QRectF &source)
|
||||
{
|
||||
FrameData *frame = d->frames[d->prefix];
|
||||
if (frame->cachedBackground.isNull()) {
|
||||
d->generateBackground(frame);
|
||||
if (frame->cachedBackground.isNull()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
painter->drawPixmap(target, frame->cachedBackground, source.isValid() ? source : target);
|
||||
}
|
||||
|
||||
void FrameSvg::paintFrame(QPainter *painter, const QPointF &pos)
|
||||
{
|
||||
FrameData *frame = d->frames[d->prefix];
|
||||
if (frame->cachedBackground.isNull()) {
|
||||
d->generateBackground(frame);
|
||||
if (frame->cachedBackground.isNull()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
painter->drawPixmap(pos, frame->cachedBackground);
|
||||
}
|
||||
|
||||
void FrameSvgPrivate::generateBackground(FrameData *frame)
|
||||
{
|
||||
if (!frame->cachedBackground.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString id = QString::fromLatin1("%5_%4_%3_%2_%1_").
|
||||
arg(frame->enabledBorders).arg(frame->frameSize.width()).arg(frame->frameSize.height()).arg(prefix).arg(q->imagePath());
|
||||
Theme *theme = Theme::defaultTheme();
|
||||
if (theme->findInCache(id, frame->cachedBackground) && !frame->cachedBackground.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//kDebug() << "generating background";
|
||||
const int topWidth = q->elementSize(prefix + "top").width();
|
||||
const int leftHeight = q->elementSize(prefix + "left").height();
|
||||
const int topOffset = 0;
|
||||
const int leftOffset = 0;
|
||||
|
||||
|
||||
if (!frame->frameSize.isValid()) {
|
||||
kWarning() << "Invalid frame size" << frame->frameSize;
|
||||
return;
|
||||
}
|
||||
|
||||
const int contentWidth = frame->frameSize.width() - frame->leftWidth - frame->rightWidth;
|
||||
const int contentHeight = frame->frameSize.height() - frame->topHeight - frame->bottomHeight;
|
||||
int contentTop = 0;
|
||||
int contentLeft = 0;
|
||||
int rightOffset = contentWidth;
|
||||
int bottomOffset = contentHeight;
|
||||
|
||||
frame->cachedBackground = QPixmap(frame->leftWidth + contentWidth + frame->rightWidth,
|
||||
frame->topHeight + contentHeight + frame->bottomHeight);
|
||||
frame->cachedBackground.fill(Qt::transparent);
|
||||
QPainter p(&frame->cachedBackground);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
|
||||
//if we must stretch the center or the borders we compute how much we will have to stretch
|
||||
//the svg to get the desired element sizes
|
||||
QSizeF scaledContentSize(0, 0);
|
||||
if (q->elementSize(prefix + "center").width() > 0 &&
|
||||
q->elementSize(prefix + "center").height() > 0 &&
|
||||
(!frame->tileCenter || frame->stretchBorders)) {
|
||||
scaledContentSize = QSizeF(contentWidth * ((qreal)q->size().width() / (qreal)q->elementSize(prefix + "center").width()),
|
||||
contentHeight * ((qreal)q->size().height() / (qreal)q->elementSize(prefix + "center").height()));
|
||||
}
|
||||
|
||||
//CENTER
|
||||
if (frame->tileCenter) {
|
||||
if (contentHeight > 0 && contentWidth > 0) {
|
||||
int centerTileHeight;
|
||||
int centerTileWidth;
|
||||
centerTileHeight = q->elementSize(prefix + "center").height();
|
||||
centerTileWidth = q->elementSize(prefix + "center").width();
|
||||
QPixmap center(centerTileWidth, centerTileHeight);
|
||||
center.fill(Qt::transparent);
|
||||
|
||||
{
|
||||
QPainter centerPainter(¢er);
|
||||
centerPainter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
q->paint(¢erPainter, QRect(QPoint(0, 0), q->elementSize(prefix + "center")), prefix + "center");
|
||||
}
|
||||
|
||||
p.drawTiledPixmap(QRect(frame->leftWidth, frame->topHeight,
|
||||
contentWidth, contentHeight), center);
|
||||
}
|
||||
} else {
|
||||
if (contentHeight > 0 && contentWidth > 0) {
|
||||
q->paint(&p, QRect(frame->leftWidth, frame->topHeight,
|
||||
contentWidth, contentHeight),
|
||||
prefix + "center");
|
||||
}
|
||||
}
|
||||
|
||||
// Corners
|
||||
if (q->hasElement(prefix + "top") && frame->enabledBorders & FrameSvg::TopBorder) {
|
||||
contentTop = frame->topHeight;
|
||||
bottomOffset += frame->topHeight;
|
||||
|
||||
if (q->hasElement(prefix + "topleft") && frame->enabledBorders & FrameSvg::LeftBorder) {
|
||||
q->paint(&p, QRect(leftOffset, topOffset, frame->leftWidth, frame->topHeight), prefix + "topleft");
|
||||
|
||||
contentLeft = frame->leftWidth;
|
||||
rightOffset = contentWidth + frame->leftWidth;
|
||||
}
|
||||
|
||||
if (q->hasElement(prefix + "topright") && frame->enabledBorders & FrameSvg::RightBorder) {
|
||||
q->paint(&p, QRect(rightOffset, topOffset, frame->rightWidth, frame->topHeight), prefix + "topright");
|
||||
}
|
||||
}
|
||||
|
||||
if (q->hasElement(prefix + "bottom") && frame->enabledBorders & FrameSvg::BottomBorder) {
|
||||
if (q->hasElement(prefix + "bottomleft") && frame->enabledBorders & FrameSvg::LeftBorder) {
|
||||
q->paint(&p, QRect(leftOffset, bottomOffset, frame->leftWidth, frame->bottomHeight), prefix + "bottomleft");
|
||||
|
||||
contentLeft = frame->leftWidth;
|
||||
rightOffset = contentWidth + frame->leftWidth;
|
||||
}
|
||||
|
||||
if (q->hasElement(prefix + "bottomright") && frame->enabledBorders & FrameSvg::RightBorder) {
|
||||
q->paint(&p, QRect(rightOffset, bottomOffset, frame->rightWidth, frame->bottomHeight), prefix + "bottomright");
|
||||
}
|
||||
}
|
||||
|
||||
// Sides
|
||||
if (frame->stretchBorders) {
|
||||
if (frame->enabledBorders & FrameSvg::LeftBorder || frame->enabledBorders & FrameSvg::RightBorder) {
|
||||
|
||||
if (q->hasElement(prefix + "left") &&
|
||||
frame->enabledBorders & FrameSvg::LeftBorder) {
|
||||
q->paint(&p, QRect(leftOffset, contentTop, frame->leftWidth, contentHeight), prefix + "left");
|
||||
}
|
||||
|
||||
if (q->hasElement(prefix + "right") &&
|
||||
frame->enabledBorders & FrameSvg::RightBorder) {
|
||||
q->paint(&p, QRect(rightOffset, contentTop, frame->rightWidth, contentHeight), prefix + "right");
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->enabledBorders & FrameSvg::TopBorder ||
|
||||
frame->enabledBorders & FrameSvg::BottomBorder) {
|
||||
|
||||
if (q->hasElement(prefix + "top") &&
|
||||
frame->enabledBorders & FrameSvg::TopBorder) {
|
||||
q->paint(&p, QRect(contentLeft, topOffset, contentWidth, frame->topHeight), prefix + "top");
|
||||
}
|
||||
|
||||
if (q->hasElement(prefix + "bottom") &&
|
||||
frame->enabledBorders & FrameSvg::BottomBorder) {
|
||||
q->paint(&p, QRect(contentLeft, bottomOffset, contentWidth, frame->bottomHeight), prefix + "bottom");
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (q->hasElement(prefix + "left") &&
|
||||
frame->enabledBorders & FrameSvg::LeftBorder) {
|
||||
QPixmap left(frame->leftWidth, leftHeight);
|
||||
left.fill(Qt::transparent);
|
||||
|
||||
QPainter sidePainter(&left);
|
||||
sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
q->paint(&sidePainter, QRect(QPoint(0, 0), left.size()), prefix + "left");
|
||||
|
||||
p.drawTiledPixmap(QRect(leftOffset, contentTop, frame->leftWidth, contentHeight), left);
|
||||
}
|
||||
|
||||
if (q->hasElement(prefix + "right") && frame->enabledBorders & FrameSvg::RightBorder) {
|
||||
QPixmap right(frame->rightWidth, leftHeight);
|
||||
right.fill(Qt::transparent);
|
||||
|
||||
QPainter sidePainter(&right);
|
||||
sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
q->paint(&sidePainter, QRect(QPoint(0, 0), right.size()), prefix + "right");
|
||||
|
||||
p.drawTiledPixmap(QRect(rightOffset, contentTop, frame->rightWidth, contentHeight), right);
|
||||
}
|
||||
|
||||
if (q->hasElement(prefix + "top") && frame->enabledBorders & FrameSvg::TopBorder) {
|
||||
QPixmap top(topWidth, frame->topHeight);
|
||||
top.fill(Qt::transparent);
|
||||
|
||||
QPainter sidePainter(&top);
|
||||
sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
q->paint(&sidePainter, QRect(QPoint(0, 0), top.size()), prefix + "top");
|
||||
|
||||
p.drawTiledPixmap(QRect(contentLeft, topOffset, contentWidth, frame->topHeight), top);
|
||||
}
|
||||
|
||||
if (q->hasElement(prefix + "bottom") && frame->enabledBorders & FrameSvg::BottomBorder) {
|
||||
QPixmap bottom(topWidth, frame->bottomHeight);
|
||||
bottom.fill(Qt::transparent);
|
||||
|
||||
QPainter sidePainter(&bottom);
|
||||
sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
q->paint(&sidePainter, QRect(QPoint(0, 0), bottom.size()), prefix + "bottom");
|
||||
|
||||
p.drawTiledPixmap(QRect(contentLeft, bottomOffset, contentWidth, frame->bottomHeight), bottom);
|
||||
}
|
||||
}
|
||||
|
||||
theme->insertIntoCache(id, frame->cachedBackground);
|
||||
}
|
||||
|
||||
void FrameSvgPrivate::updateSizes()
|
||||
{
|
||||
//kDebug() << "!!!!!!!!!!!!!!!!!!!!!! updating sizes" << prefix;
|
||||
FrameData *frame = frames[prefix];
|
||||
Q_ASSERT(frame);
|
||||
|
||||
frame->cachedBackground = QPixmap();
|
||||
frame->cachedMask = QPixmap();
|
||||
|
||||
if (frame->enabledBorders & FrameSvg::TopBorder) {
|
||||
frame->topHeight = q->elementSize(prefix + "top").height();
|
||||
|
||||
if (q->hasElement(prefix + "hint-top-margin")) {
|
||||
frame->topMargin = q->elementSize(prefix + "hint-top-margin").height();
|
||||
} else {
|
||||
frame->topMargin = frame->topHeight;
|
||||
}
|
||||
} else {
|
||||
frame->topMargin = frame->topHeight = 0;
|
||||
}
|
||||
|
||||
if (frame->enabledBorders & FrameSvg::LeftBorder) {
|
||||
frame->leftWidth = q->elementSize(prefix + "left").width();
|
||||
|
||||
if (q->hasElement(prefix + "hint-left-margin")) {
|
||||
frame->leftMargin = q->elementSize(prefix + "hint-left-margin").height();
|
||||
} else {
|
||||
frame->leftMargin = frame->leftWidth;
|
||||
}
|
||||
} else {
|
||||
frame->leftMargin = frame->leftWidth = 0;
|
||||
}
|
||||
|
||||
if (frame->enabledBorders & FrameSvg::RightBorder) {
|
||||
frame->rightWidth = q->elementSize(prefix + "right").width();
|
||||
|
||||
if (q->hasElement(prefix + "hint-right-margin")) {
|
||||
frame->rightMargin = q->elementSize(prefix + "hint-right-margin").height();
|
||||
} else {
|
||||
frame->rightMargin = frame->rightWidth;
|
||||
}
|
||||
} else {
|
||||
frame->rightMargin = frame->rightWidth = 0;
|
||||
}
|
||||
|
||||
if (frame->enabledBorders & FrameSvg::BottomBorder) {
|
||||
frame->bottomHeight = q->elementSize(prefix + "bottom").height();
|
||||
|
||||
if (q->hasElement(prefix + "hint-bottom-margin")) {
|
||||
frame->bottomMargin = q->elementSize(prefix + "hint-bottom-margin").height();
|
||||
} else {
|
||||
frame->bottomMargin = frame->bottomHeight;
|
||||
}
|
||||
} else {
|
||||
frame->bottomMargin = frame->bottomHeight = 0;
|
||||
}
|
||||
|
||||
//since it's rectangular, topWidth and bottomWidth must be the same
|
||||
frame->tileCenter = q->hasElement("hint-tile-center");
|
||||
frame->noBorderPadding = q->hasElement("hint-no-border-padding");
|
||||
frame->stretchBorders = q->hasElement("hint-stretch-borders");
|
||||
}
|
||||
|
||||
void FrameSvgPrivate::updateNeeded()
|
||||
{
|
||||
q->clearCache();
|
||||
updateSizes();
|
||||
}
|
||||
|
||||
void FrameSvgPrivate::updateAndSignalSizes()
|
||||
{
|
||||
updateSizes();
|
||||
emit q->repaintNeeded();
|
||||
}
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "framesvg.moc"
|
263
framesvg.h
Normal file
263
framesvg.h
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* 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 <QtGui/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 Plamsa::Svg
|
||||
**/
|
||||
class PLASMA_EXPORT FrameSvg : public Svg
|
||||
{
|
||||
Q_OBJECT
|
||||
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.
|
||||
*
|
||||
* @arg parent options QObject to parent this to
|
||||
*
|
||||
* @related Plasma::Theme
|
||||
*/
|
||||
explicit FrameSvg(QObject *parent = 0);
|
||||
~FrameSvg();
|
||||
|
||||
/**
|
||||
* Loads a new Svg
|
||||
* @arg imagePath the new file
|
||||
*/
|
||||
void setImagePath(const QString &path);
|
||||
|
||||
/**
|
||||
* Sets what borders should be painted
|
||||
* @arg 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
|
||||
* @arg size the new size of the frame
|
||||
*/
|
||||
void resizeFrame(const QSizeF &size);
|
||||
|
||||
/**
|
||||
* @returns the size of the frame
|
||||
*/
|
||||
QSizeF frameSize() const;
|
||||
|
||||
/**
|
||||
* Returns the margin size given the margin edge we want
|
||||
* @arg edge the margin edge we want, top, bottom, left or right
|
||||
* @return the margin size
|
||||
*/
|
||||
qreal marginSize(const Plasma::MarginEdge edge) const;
|
||||
|
||||
/**
|
||||
* Convenience method that extracts the size of the four margins
|
||||
* in the four output parameters
|
||||
* @arg left left margin size
|
||||
* @arg top top margin size
|
||||
* @arg right right margin size
|
||||
* @arg bottom bottom margin size
|
||||
*/
|
||||
void getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const;
|
||||
|
||||
/**
|
||||
* @return the rectangle of the center element, taking the margins into account.
|
||||
*/
|
||||
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.
|
||||
* @arg location location
|
||||
*/
|
||||
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.
|
||||
* If the
|
||||
* @arg prefix prefix for the SVG element names
|
||||
*/
|
||||
void setElementPrefix(const QString & prefix);
|
||||
|
||||
/**
|
||||
* @return true if the svg has the necessary elements with the given prefix
|
||||
* to draw a frame
|
||||
* @arg prefix the given prefix we want to check if drawable
|
||||
*/
|
||||
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.
|
||||
* @arg location the given prefix we want to check if drawable
|
||||
*/
|
||||
bool hasElementPrefix(Plasma::Location location) const;
|
||||
|
||||
/**
|
||||
* Returns the prefix for SVG elements of the FrameSvg
|
||||
* @return the prefix
|
||||
*/
|
||||
QString prefix();
|
||||
|
||||
/**
|
||||
* Returns a monochrome mask that tightly contains the fully opaque areas of the svg
|
||||
* @return a monochrome bitmap of opaque areas
|
||||
*/
|
||||
QBitmap mask() const;
|
||||
|
||||
/**
|
||||
* Sets whether saving all the rendered prefixes in a cache or not
|
||||
* @arg cache if use the cache or not
|
||||
*/
|
||||
void setCacheAllRenderedFrames(bool cache);
|
||||
|
||||
/**
|
||||
* @return if all the different prefixes should be kept in a cache when rendered
|
||||
*/
|
||||
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 setUseCache(true)
|
||||
*/
|
||||
void clearCache();
|
||||
|
||||
/**
|
||||
* Returns a pixmap of the SVG represented by this object.
|
||||
*
|
||||
* @arg 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
|
||||
* @arg painter the QPainter to use
|
||||
* @arg target the target rectangle on the paint device
|
||||
* @arg 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
|
||||
* @arg painter the QPainter to use
|
||||
* @arg pos where to paint the svg
|
||||
*/
|
||||
Q_INVOKABLE void paintFrame(QPainter *painter, const QPointF &pos = QPointF(0, 0));
|
||||
|
||||
private:
|
||||
FrameSvgPrivate *const d;
|
||||
|
||||
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
|
217
glapplet.cpp
Normal file
217
glapplet.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright 2007 Zack Rusin <zack@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 "glapplet.h"
|
||||
|
||||
#include <QtOpenGL/QGLPixelBuffer>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
namespace Plasma {
|
||||
|
||||
class GLAppletPrivate
|
||||
{
|
||||
public:
|
||||
GLAppletPrivate()
|
||||
{
|
||||
init();
|
||||
}
|
||||
~GLAppletPrivate()
|
||||
{
|
||||
delete pbuf;
|
||||
delete dummy;
|
||||
}
|
||||
void init()
|
||||
{
|
||||
dummy = new QGLWidget((QWidget *) 0);
|
||||
QGLFormat format = QGLFormat::defaultFormat();
|
||||
format.setSampleBuffers(true);
|
||||
format.setAlphaBufferSize(8);
|
||||
//dummy size construction
|
||||
pbuf = new QGLPixelBuffer(300, 300, format, dummy);
|
||||
if (pbuf->isValid()) {
|
||||
pbuf->makeCurrent();
|
||||
}
|
||||
}
|
||||
void updateGlSize(const QSize &size)
|
||||
{
|
||||
if (size.width() > pbuf->width() ||
|
||||
size.height() > pbuf->height()) {
|
||||
QGLFormat format = pbuf->format();
|
||||
delete pbuf;
|
||||
pbuf = new QGLPixelBuffer(size, format, dummy);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
QGLPixelBuffer *pbuf;
|
||||
QGLWidget *dummy;
|
||||
};
|
||||
|
||||
GLApplet::GLApplet(QGraphicsItem *parent,
|
||||
const QString &serviceId,
|
||||
int appletId)
|
||||
: Applet(parent, serviceId, appletId),
|
||||
d(new GLAppletPrivate)
|
||||
{
|
||||
if (!d->dummy->isValid() ||
|
||||
!QGLPixelBuffer::hasOpenGLPbuffers() ||
|
||||
!d->pbuf->isValid()) {
|
||||
setFailedToLaunch(true, i18n("This system does not support OpenGL widgets."));
|
||||
}
|
||||
}
|
||||
|
||||
GLApplet::GLApplet(QObject *parent, const QVariantList &args)
|
||||
: Applet(parent, args),
|
||||
d(new GLAppletPrivate)
|
||||
{
|
||||
if (!d->dummy->isValid() ||
|
||||
!QGLPixelBuffer::hasOpenGLPbuffers() ||
|
||||
!d->pbuf->isValid()) {
|
||||
setFailedToLaunch(true, i18n("This system does not support OpenGL widgets."));
|
||||
}
|
||||
}
|
||||
|
||||
GLApplet::~GLApplet()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
GLuint GLApplet::bindTexture(const QImage &image, GLenum target)
|
||||
{
|
||||
Q_ASSERT(d->pbuf);
|
||||
if (!d->dummy->isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return d->dummy->bindTexture(image, target);
|
||||
}
|
||||
|
||||
void GLApplet::deleteTexture(GLuint textureId)
|
||||
{
|
||||
Q_ASSERT(d->pbuf);
|
||||
d->dummy->deleteTexture(textureId);
|
||||
}
|
||||
|
||||
void GLApplet::paintGLInterface(QPainter *painter,
|
||||
const QStyleOptionGraphicsItem *option)
|
||||
{
|
||||
Q_UNUSED(painter)
|
||||
Q_UNUSED(option)
|
||||
}
|
||||
|
||||
static inline QPainterPath headerPath(const QRectF &r, int roundness,
|
||||
int headerHeight=10)
|
||||
{
|
||||
QPainterPath path;
|
||||
int xRnd = roundness;
|
||||
int yRnd = roundness;
|
||||
if (r.width() > r.height()) {
|
||||
xRnd = int(roundness * r.height() / r.width());
|
||||
} else {
|
||||
yRnd = int(roundness * r.width() / r.height());
|
||||
}
|
||||
|
||||
if(xRnd >= 100) { // fix ranges
|
||||
xRnd = 99;
|
||||
}
|
||||
if(yRnd >= 100) {
|
||||
yRnd = 99;
|
||||
}
|
||||
if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
|
||||
path.addRect(r);
|
||||
return path;
|
||||
}
|
||||
|
||||
QRectF rect = r.normalized();
|
||||
|
||||
if (rect.isNull()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
qreal x = rect.x();
|
||||
qreal y = rect.y();
|
||||
qreal w = rect.width();
|
||||
qreal h = rect.height();
|
||||
qreal rxx = w * xRnd / 200;
|
||||
qreal ryy = h * yRnd / 200;
|
||||
// were there overflows?
|
||||
if (rxx < 0) {
|
||||
rxx = w / 200 * xRnd;
|
||||
}
|
||||
if (ryy < 0) {
|
||||
ryy = h / 200 * yRnd;
|
||||
}
|
||||
qreal rxx2 = 2 * rxx;
|
||||
qreal ryy2 = 2 * ryy;
|
||||
|
||||
path.arcMoveTo(x, y, rxx2, ryy2, 90);
|
||||
path.arcTo(x, y, rxx2, ryy2, 90, 90);
|
||||
QPointF pt = path.currentPosition();
|
||||
path.lineTo(x, pt.y() + headerHeight);
|
||||
path.lineTo(x + w, pt.y() + headerHeight);
|
||||
path.lineTo(x + w, pt.y());
|
||||
path.arcTo(x + w - rxx2, y, rxx2, ryy2, 0, 90);
|
||||
path.closeSubpath();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void GLApplet::paintInterface(QPainter *painter,
|
||||
const QStyleOptionGraphicsItem *option,
|
||||
const QRect &contentsRect)
|
||||
{
|
||||
Q_UNUSED(contentsRect)
|
||||
Q_ASSERT(d->pbuf);
|
||||
if ((!d->dummy->isValid() ||
|
||||
!d->pbuf->isValid())) {
|
||||
if (!hasFailedToLaunch()) {
|
||||
setFailedToLaunch(true, i18n("Your machine does not support OpenGL widgets."));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
d->pbuf->makeCurrent();
|
||||
|
||||
// handle background filling
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
QMatrix m = painter->worldMatrix();
|
||||
QRect deviceRect = m.mapRect(QRect(QPoint(23, 25), boundingRect().size().toSize()));
|
||||
d->updateGlSize(deviceRect.size());
|
||||
|
||||
// redirect this widget's painting into the pbuffer
|
||||
QPainter p(d->pbuf);
|
||||
paintGLInterface(&p, option);
|
||||
|
||||
// draw the pbuffer contents to the backingstore
|
||||
QImage image = d->pbuf->toImage();
|
||||
painter->drawImage(0, 0, image);
|
||||
}
|
||||
|
||||
void GLApplet::makeCurrent()
|
||||
{
|
||||
if (!d->dummy->isValid() || !d->pbuf->isValid()) {
|
||||
d->dummy->makeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "glapplet.moc"
|
88
glapplet.h
Normal file
88
glapplet.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2007 Zack Rusin <zack@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_GLAPPLET_H
|
||||
#define PLASMA_GLAPPLET_H
|
||||
|
||||
#include <plasma/applet.h>
|
||||
|
||||
#include <QtOpenGL/QGLWidget>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class GLAppletPrivate;
|
||||
|
||||
/**
|
||||
* @class GLApplet plasma/glapplet.h <Plasma/GLApplet>
|
||||
*
|
||||
* @short Plasma Applet that is fully rendered using OpengGL
|
||||
*/
|
||||
class PLASMA_EXPORT GLApplet : public Applet
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @arg parent the QGraphicsItem this applet is parented to
|
||||
* @arg serviceId the name of the .desktop file containing the
|
||||
* information about the widget
|
||||
* @arg appletId a unique id used to differentiate between multiple
|
||||
* instances of the same Applet type
|
||||
*/
|
||||
GLApplet(QGraphicsItem *parent,
|
||||
const QString &serviceId,
|
||||
int appletId);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @arg parent a QObject parent; you probably want to pass in 0
|
||||
* @arg args a list of strings containing two entries: the service id
|
||||
* and the applet id
|
||||
*/
|
||||
GLApplet(QObject *parent, const QVariantList &args);
|
||||
|
||||
~GLApplet();
|
||||
|
||||
GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D);
|
||||
void deleteTexture(GLuint texture_id);
|
||||
|
||||
/**
|
||||
* Reimplement this method to render using OpenGL. QPainter passed
|
||||
* to this method will always use OpenGL engine and rendering
|
||||
* using OpenGL api directly is supported.
|
||||
*/
|
||||
virtual void paintGLInterface(QPainter *painter,
|
||||
const QStyleOptionGraphicsItem *option);
|
||||
void makeCurrent();
|
||||
private:
|
||||
virtual void paintInterface(QPainter *painter,
|
||||
const QStyleOptionGraphicsItem *option,
|
||||
const QRect &contentsRect);
|
||||
private:
|
||||
GLAppletPrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
1
includes/AbstractRunner
Normal file
1
includes/AbstractRunner
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/abstractrunner.h"
|
1
includes/AnimationDriver
Normal file
1
includes/AnimationDriver
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/animationdriver.h"
|
1
includes/Animator
Normal file
1
includes/Animator
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/animator.h"
|
2
includes/Applet
Normal file
2
includes/Applet
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/applet.h"
|
||||
|
1
includes/AppletScript
Normal file
1
includes/AppletScript
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/scripting/appletscript.h"
|
1
includes/BusyWidget
Normal file
1
includes/BusyWidget
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/busywidget.h"
|
1
includes/CheckBox
Normal file
1
includes/CheckBox
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/checkbox.h"
|
1
includes/ComboBox
Normal file
1
includes/ComboBox
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/combobox.h"
|
1
includes/ConfigLoader
Normal file
1
includes/ConfigLoader
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/configloader.h"
|
2
includes/Containment
Normal file
2
includes/Containment
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/containment.h"
|
||||
|
2
includes/Context
Normal file
2
includes/Context
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/context.h"
|
||||
|
1
includes/Corona
Normal file
1
includes/Corona
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/corona.h"
|
1
includes/DataContainer
Normal file
1
includes/DataContainer
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/datacontainer.h"
|
1
includes/DataEngine
Normal file
1
includes/DataEngine
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/dataengine.h"
|
1
includes/DataEngineManager
Normal file
1
includes/DataEngineManager
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/dataenginemanager.h"
|
1
includes/DataEngineScript
Normal file
1
includes/DataEngineScript
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/scripting/dataenginescript.h"
|
1
includes/Delegate
Normal file
1
includes/Delegate
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/delegate.h"
|
1
includes/Dialog
Normal file
1
includes/Dialog
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/dialog.h"
|
2
includes/Extender
Normal file
2
includes/Extender
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/extender.h"
|
||||
|
2
includes/ExtenderItem
Normal file
2
includes/ExtenderItem
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/extenderitem.h"
|
||||
|
1
includes/FlashingLabel
Normal file
1
includes/FlashingLabel
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/flashinglabel.h"
|
1
includes/Frame
Normal file
1
includes/Frame
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/frame.h"
|
1
includes/FrameSvg
Normal file
1
includes/FrameSvg
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/framesvg.h"
|
1
includes/GLApplet
Normal file
1
includes/GLApplet
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/glapplet.h"
|
1
includes/GroupBox
Normal file
1
includes/GroupBox
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/groupbox.h"
|
1
includes/IconWidget
Normal file
1
includes/IconWidget
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/iconwidget.h"
|
1
includes/Label
Normal file
1
includes/Label
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/label.h"
|
1
includes/LineEdit
Normal file
1
includes/LineEdit
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/lineedit.h"
|
1
includes/Meter
Normal file
1
includes/Meter
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/meter.h"
|
1
includes/Package
Normal file
1
includes/Package
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/package.h"
|
2
includes/PackageMetadata
Normal file
2
includes/PackageMetadata
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/packagemetadata.h"
|
||||
|
1
includes/PackageStructure
Normal file
1
includes/PackageStructure
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/packagestructure.h"
|
1
includes/PaintUtils
Normal file
1
includes/PaintUtils
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/paintutils.h"
|
1
includes/Plasma
Normal file
1
includes/Plasma
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/plasma.h"
|
1
includes/PopupApplet
Normal file
1
includes/PopupApplet
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/popupapplet.h"
|
1
includes/PushButton
Normal file
1
includes/PushButton
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/pushbutton.h"
|
1
includes/QueryMatch
Normal file
1
includes/QueryMatch
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/querymatch.h"
|
1
includes/RadioButton
Normal file
1
includes/RadioButton
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/radiobutton.h"
|
1
includes/RunnerContext
Normal file
1
includes/RunnerContext
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/runnercontext.h"
|
1
includes/RunnerManager
Normal file
1
includes/RunnerManager
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/runnermanager.h"
|
1
includes/RunnerScript
Normal file
1
includes/RunnerScript
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/scripting/runnerscript.h"
|
1
includes/ScriptEngine
Normal file
1
includes/ScriptEngine
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/scripting/scriptengine.h"
|
1
includes/ScrollBar
Normal file
1
includes/ScrollBar
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/scrollbar.h"
|
1
includes/Service
Normal file
1
includes/Service
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/service.h"
|
1
includes/ServiceJob
Normal file
1
includes/ServiceJob
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/servicejob.h"
|
1
includes/SignalPlotter
Normal file
1
includes/SignalPlotter
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/signalplotter.h"
|
1
includes/Slider
Normal file
1
includes/Slider
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/slider.h"
|
1
includes/Svg
Normal file
1
includes/Svg
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/svg.h"
|
1
includes/SvgWidget
Normal file
1
includes/SvgWidget
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/svgwidget.h"
|
1
includes/TabBar
Normal file
1
includes/TabBar
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/tabbar.h"
|
1
includes/TextEdit
Normal file
1
includes/TextEdit
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/textedit.h"
|
1
includes/Theme
Normal file
1
includes/Theme
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/theme.h"
|
1
includes/ToolTipManager
Normal file
1
includes/ToolTipManager
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/tooltipmanager.h"
|
1
includes/TreeView
Normal file
1
includes/TreeView
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/treeview.h"
|
2
includes/UiLoader
Normal file
2
includes/UiLoader
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/scripting/uiloader.h"
|
||||
|
1
includes/Version
Normal file
1
includes/Version
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/version.h"
|
1
includes/View
Normal file
1
includes/View
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/view.h"
|
1
includes/Wallpaper
Normal file
1
includes/Wallpaper
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/wallpaper.h"
|
1
includes/WebView
Normal file
1
includes/WebView
Normal file
@ -0,0 +1 @@
|
||||
#include "../../plasma/widgets/webview.h"
|
447
package.cpp
Normal file
447
package.cpp
Normal file
@ -0,0 +1,447 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2007 by Aaron Seigo <aseigo@kde.org> *
|
||||
* Copyright 2007 by Riccardo Iaconelli <riccardo@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 "package.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QRegExp>
|
||||
|
||||
#include <KArchiveDirectory>
|
||||
#include <KArchiveEntry>
|
||||
#include <KComponentData>
|
||||
#include <KDesktopFile>
|
||||
#include <KIO/CopyJob>
|
||||
#include <KIO/DeleteJob>
|
||||
#include <KIO/FileCopyJob>
|
||||
#include <KIO/Job>
|
||||
#include <KPluginInfo>
|
||||
#include <KStandardDirs>
|
||||
#include <KTempDir>
|
||||
#include <KTemporaryFile>
|
||||
#include <KZip>
|
||||
#include <KDebug>
|
||||
|
||||
#include "packagemetadata.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class PackagePrivate
|
||||
{
|
||||
public:
|
||||
PackagePrivate(const PackageStructure::Ptr st, const QString &p)
|
||||
: structure(st),
|
||||
basePath(p),
|
||||
valid(QFile::exists(basePath))
|
||||
{
|
||||
QFileInfo info(basePath);
|
||||
if (valid && info.isDir() && basePath[basePath.length() - 1] != '/') {
|
||||
basePath.append('/');
|
||||
}
|
||||
}
|
||||
|
||||
~PackagePrivate()
|
||||
{
|
||||
}
|
||||
|
||||
PackageStructure::Ptr structure;
|
||||
QString basePath;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
Package::Package(const QString &packageRoot, const QString &package,
|
||||
PackageStructure::Ptr structure)
|
||||
: d(new PackagePrivate(structure, packageRoot + '/' + package))
|
||||
{
|
||||
structure->setPath(d->basePath);
|
||||
}
|
||||
|
||||
Package::Package(const QString &packagePath, PackageStructure::Ptr structure)
|
||||
: d(new PackagePrivate(structure, packagePath))
|
||||
{
|
||||
structure->setPath(d->basePath);
|
||||
}
|
||||
|
||||
Package::~Package()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool Package::isValid() const
|
||||
{
|
||||
if (!d->valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (const char *dir, d->structure->requiredDirectories()) {
|
||||
if (!QFile::exists(d->basePath + d->structure->contentsPrefix() + d->structure->path(dir))) {
|
||||
kWarning() << "Could not find required directory" << dir;
|
||||
d->valid = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const char *file, d->structure->requiredFiles()) {
|
||||
if (!QFile::exists(d->basePath + d->structure->contentsPrefix() + d->structure->path(file))) {
|
||||
kWarning() << "Could not find required file" << file << ", look in"
|
||||
<< d->basePath + d->structure->contentsPrefix() + d->structure->path(file) << endl;
|
||||
d->valid = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString Package::filePath(const char *fileType, const QString &filename) const
|
||||
{
|
||||
if (!d->valid) {
|
||||
kDebug() << "package is not valid";
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString path = d->structure->path(fileType);
|
||||
|
||||
if (path.isEmpty()) {
|
||||
kDebug() << "no matching path came of it";
|
||||
return QString();
|
||||
}
|
||||
|
||||
path.prepend(d->basePath + d->structure->contentsPrefix());
|
||||
|
||||
if (!filename.isEmpty()) {
|
||||
path.append("/").append(filename);
|
||||
}
|
||||
|
||||
if (QFile::exists(path)) {
|
||||
// ensure that we don't return files outside of our base path
|
||||
// due to symlink or ../ games
|
||||
QDir dir(path);
|
||||
QString canonicalized = dir.canonicalPath() + QDir::separator();
|
||||
if (canonicalized.startsWith(d->basePath)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
kDebug() << path << "does not exist";
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString Package::filePath(const char *fileType) const
|
||||
{
|
||||
return filePath(fileType, QString());
|
||||
}
|
||||
|
||||
QStringList Package::entryList(const char *fileType) const
|
||||
{
|
||||
if (!d->valid) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QString path = d->structure->path(fileType);
|
||||
if (path.isEmpty()) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QDir dir(d->basePath + d->structure->contentsPrefix() + path);
|
||||
|
||||
if (dir.exists()) {
|
||||
// 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->basePath)) {
|
||||
return dir.entryList(QDir::Files | QDir::Readable);
|
||||
}
|
||||
}
|
||||
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
PackageMetadata Package::metadata() const
|
||||
{
|
||||
return d->structure->metadata();
|
||||
}
|
||||
|
||||
const QString Package::path() const
|
||||
{
|
||||
return d->basePath;
|
||||
}
|
||||
|
||||
const PackageStructure::Ptr Package::structure() const
|
||||
{
|
||||
return d->structure;
|
||||
}
|
||||
|
||||
//TODO: provide a version of this that allows one to ask for certain types of packages, etc?
|
||||
// should we be using KService here instead/as well?
|
||||
QStringList Package::listInstalled(const QString &packageRoot) // static
|
||||
{
|
||||
QDir dir(packageRoot);
|
||||
|
||||
if (!dir.exists()) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QStringList packages;
|
||||
|
||||
foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
|
||||
QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
|
||||
if (QFile::exists(metadata)) {
|
||||
PackageMetadata m(metadata);
|
||||
packages << m.pluginName();
|
||||
}
|
||||
}
|
||||
|
||||
return packages;
|
||||
}
|
||||
|
||||
bool Package::installPackage(const QString &package,
|
||||
const QString &packageRoot,
|
||||
const QString &servicePrefix) // static
|
||||
{
|
||||
//TODO: report *what* failed if something does fail
|
||||
QDir root(packageRoot);
|
||||
|
||||
if (!root.exists()) {
|
||||
KStandardDirs::makeDir(packageRoot);
|
||||
if (!root.exists()) {
|
||||
kWarning() << "Could not create package root directory:" << packageRoot;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QFileInfo fileInfo(package);
|
||||
if (!fileInfo.exists()) {
|
||||
kWarning() << "No such file:" << package;
|
||||
return false;
|
||||
}
|
||||
|
||||
QString path;
|
||||
KTempDir tempdir;
|
||||
bool archivedPackage = false;
|
||||
|
||||
if (fileInfo.isDir()) {
|
||||
// we have a directory, so let's just install what is in there
|
||||
path = package;
|
||||
|
||||
// make sure we end in a slash!
|
||||
if (path[path.size() - 1] != '/') {
|
||||
path.append('/');
|
||||
}
|
||||
} else {
|
||||
KZip archive(package);
|
||||
if (!archive.open(QIODevice::ReadOnly)) {
|
||||
kWarning() << "Could not open package file:" << package;
|
||||
return false;
|
||||
}
|
||||
|
||||
archivedPackage = true;
|
||||
const KArchiveDirectory *source = archive.directory();
|
||||
const KArchiveEntry *metadata = source->entry("metadata.desktop");
|
||||
|
||||
if (!metadata) {
|
||||
kWarning() << "No metadata file in package" << package;
|
||||
return false;
|
||||
}
|
||||
|
||||
path = tempdir.name();
|
||||
source->copyTo(path);
|
||||
}
|
||||
|
||||
QString metadataPath = path + "metadata.desktop";
|
||||
if (!QFile::exists(metadataPath)) {
|
||||
kWarning() << "No metadata file in package" << package;
|
||||
return false;
|
||||
}
|
||||
|
||||
PackageMetadata meta(metadataPath);
|
||||
QString targetName = meta.pluginName();
|
||||
|
||||
if (targetName.isEmpty()) {
|
||||
kWarning() << "Package plugin name not specified";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure that package names are safe so package uninstall can't inject
|
||||
// bad characters into the paths used for removal.
|
||||
QRegExp validatePluginName("^[\\w-\\.]+$"); // Only allow letters, numbers, underscore and period.
|
||||
if (!validatePluginName.exactMatch(targetName)) {
|
||||
kWarning() << "Package plugin name " << targetName << "contains invalid characters";
|
||||
return false;
|
||||
}
|
||||
|
||||
targetName = packageRoot + '/' + targetName;
|
||||
if (QFile::exists(targetName)) {
|
||||
kWarning() << targetName << "already exists";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (archivedPackage) {
|
||||
// it's in a temp dir, so just move it over.
|
||||
KIO::CopyJob *job = KIO::move(KUrl(path), KUrl(targetName), KIO::HideProgressInfo);
|
||||
if (!job->exec()) {
|
||||
kWarning() << "Could not move package to destination:" << targetName << " : " << job->errorString();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// it's a directory containing the stuff, so copy the contents rather
|
||||
// than move them
|
||||
KIO::CopyJob *job = KIO::copy(KUrl(path), KUrl(targetName), KIO::HideProgressInfo);
|
||||
if (!job->exec()) {
|
||||
kWarning() << "Could not copy package to destination:" << targetName << " : " << job->errorString();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (archivedPackage) {
|
||||
// no need to remove the temp dir (which has been successfully moved if it's an archive)
|
||||
tempdir.setAutoRemove(false);
|
||||
}
|
||||
|
||||
// and now we register it as a service =)
|
||||
QString metaPath = targetName + "/metadata.desktop";
|
||||
KDesktopFile df(metaPath);
|
||||
KConfigGroup cg = df.desktopGroup();
|
||||
|
||||
// Q: should not installing it as a service disqualify it?
|
||||
// Q: i don't think so since KServiceTypeTrader may not be
|
||||
// used by the installing app in any case, and the
|
||||
// package is properly installed - aseigo
|
||||
|
||||
//TODO: reduce code duplication with registerPackage below
|
||||
|
||||
QString serviceName = servicePrefix + meta.pluginName();
|
||||
|
||||
QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
|
||||
KIO::FileCopyJob *job = KIO::file_copy(metaPath, service, -1, KIO::HideProgressInfo);
|
||||
if (job->exec()) {
|
||||
// the icon in the installed file needs to point to the icon in the
|
||||
// installation dir!
|
||||
QString iconPath = targetName + '/' + cg.readEntry("Icon");
|
||||
QFile icon(iconPath);
|
||||
if (icon.exists()) {
|
||||
KDesktopFile df(service);
|
||||
KConfigGroup cg = df.desktopGroup();
|
||||
cg.writeEntry("Icon", iconPath);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Package::uninstallPackage(const QString &pluginName,
|
||||
const QString &packageRoot,
|
||||
const QString &servicePrefix) // static
|
||||
{
|
||||
// We need to remove the package directory and its metadata file.
|
||||
QString targetName = pluginName;
|
||||
targetName = packageRoot + '/' + targetName;
|
||||
|
||||
if (!QFile::exists(targetName)) {
|
||||
kWarning() << targetName << "does not exist";
|
||||
return false;
|
||||
}
|
||||
|
||||
QString serviceName = servicePrefix + pluginName;
|
||||
|
||||
QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
|
||||
kDebug() << "Removing service file " << service;
|
||||
bool ok = QFile::remove(service);
|
||||
|
||||
if (!ok) {
|
||||
kWarning() << "Unable to remove " << service;
|
||||
return ok;
|
||||
}
|
||||
|
||||
KIO::DeleteJob *job = KIO::del(KUrl(targetName));
|
||||
if (!job->exec()) {
|
||||
kWarning() << "Could not delete package from:" << targetName << " : " << job->errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Package::registerPackage(const PackageMetadata &data, const QString &iconPath)
|
||||
{
|
||||
QString serviceName("plasma-applet-" + data.pluginName());
|
||||
QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
|
||||
|
||||
if (data.pluginName().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data.write(service);
|
||||
|
||||
KDesktopFile config(service);
|
||||
KConfigGroup cg = config.desktopGroup();
|
||||
const QString type = data.type().isEmpty() ? "Service" : data.type();
|
||||
cg.writeEntry("Type", type);
|
||||
const QString serviceTypes = data.serviceType().isNull() ? "Plasma/Applet,Plasma/Containment" : data.serviceType();
|
||||
cg.writeEntry("X-KDE-ServiceTypes", serviceTypes);
|
||||
cg.writeEntry("X-KDE-PluginInfo-EnabledByDefault", true);
|
||||
|
||||
QFile icon(iconPath);
|
||||
if (icon.exists()) {
|
||||
//FIXME: the '/' search will break on non-UNIX. do we care?
|
||||
QString installedIcon("plasma_applet_" + data.pluginName() +
|
||||
iconPath.right(iconPath.length() - iconPath.lastIndexOf("/")));
|
||||
cg.writeEntry("Icon", installedIcon);
|
||||
installedIcon = KStandardDirs::locateLocal("icon", installedIcon);
|
||||
KIO::FileCopyJob *job = KIO::file_copy(iconPath, installedIcon, -1, KIO::HideProgressInfo);
|
||||
job->exec();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Package::createPackage(const PackageMetadata &metadata,
|
||||
const QString &source,
|
||||
const QString &destination,
|
||||
const QString &icon) // static
|
||||
{
|
||||
Q_UNUSED(icon)
|
||||
if (!metadata.isValid()) {
|
||||
kWarning() << "Metadata file is not complete";
|
||||
return false;
|
||||
}
|
||||
|
||||
// write metadata in a temporary file
|
||||
KTemporaryFile metadataFile;
|
||||
if (!metadataFile.open()) {
|
||||
return false;
|
||||
}
|
||||
metadata.write(metadataFile.fileName());
|
||||
|
||||
// put everything into a zip archive
|
||||
KZip creation(destination);
|
||||
creation.setCompression(KZip::NoCompression);
|
||||
if (!creation.open(QIODevice::WriteOnly)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
creation.addLocalFile(metadataFile.fileName(), "metadata.desktop");
|
||||
creation.addLocalDirectory(source, "contents");
|
||||
creation.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // Namespace
|
180
package.h
Normal file
180
package.h
Normal file
@ -0,0 +1,180 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2007 by Aaron Seigo <aseigo@kde.org> *
|
||||
* Copyright 2007 by Riccardo Iaconelli <riccardo@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 <plasma/plasma_export.h>
|
||||
#include <plasma/packagestructure.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
/**
|
||||
* @class Package plasma/package.h <Plasma/Package>
|
||||
*
|
||||
* @short object representing an installed Plasmagik package
|
||||
**/
|
||||
|
||||
class PackageMetadata;
|
||||
class PackagePrivate;
|
||||
|
||||
class PLASMA_EXPORT Package
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @arg packageRoot path to the package installation root
|
||||
* @arg package the name of the package
|
||||
* @arg structure the package structure describing this package
|
||||
**/
|
||||
Package(const QString &packageRoot, const QString &package,
|
||||
PackageStructure::Ptr structure);
|
||||
|
||||
/**
|
||||
* Construct a Package object.
|
||||
*
|
||||
* @arg packagePath full path to the package directory
|
||||
* @arg structure the package structure describing this package
|
||||
*/
|
||||
Package(const QString &packagePath, PackageStructure::Ptr structure);
|
||||
|
||||
//TODO for 4.1: be able to load an uninstalled/uncompressed file.
|
||||
|
||||
~Package();
|
||||
|
||||
/**
|
||||
* @return true if all the required components as defined in
|
||||
* the PackageStructure exist
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* Get the path to a given file.
|
||||
*
|
||||
* @arg fileType the type of file to look for, as defined in the
|
||||
* package structure
|
||||
* @arg filename the name of the file
|
||||
* @return path to the file on disk. QString() if not found.
|
||||
**/
|
||||
QString filePath(const char *fileType, const QString &filename) const;
|
||||
|
||||
/**
|
||||
* Get the path to a given file.
|
||||
*
|
||||
* @arg fileType the type of file to look for, as defined in the
|
||||
* package structure. The type must refer to a file
|
||||
* in the package structure and not a directory.
|
||||
* @return path to the file on disk. QString() if not found
|
||||
**/
|
||||
QString filePath(const char *fileType) const;
|
||||
|
||||
/**
|
||||
* Get the list of files of a given type.
|
||||
*
|
||||
* @arg 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 *fileType) const;
|
||||
|
||||
/**
|
||||
* @return the package metadata object.
|
||||
*/
|
||||
PackageMetadata metadata() const;
|
||||
|
||||
/**
|
||||
* @return the path to the root of this particular package
|
||||
*/
|
||||
const QString path() const;
|
||||
|
||||
/**
|
||||
* @return the PackageStructure use in this Package
|
||||
*/
|
||||
const PackageStructure::Ptr structure() const;
|
||||
|
||||
/**
|
||||
* Returns a list of all installed packages
|
||||
*
|
||||
* @param packageRoot path to the directory where Plasmagik packages
|
||||
* have been installed to
|
||||
* @return a list of installed Plasmagik packages
|
||||
**/
|
||||
static QStringList listInstalled(const QString &packageRoot);
|
||||
|
||||
/**
|
||||
* Installs a package.
|
||||
*
|
||||
* @param package path to the Plasmagik package
|
||||
* @param packageRoot path to the directory where the package should be
|
||||
* installed to
|
||||
* @return true on successful installation, false otherwise
|
||||
**/
|
||||
static bool installPackage(const QString &package,
|
||||
const QString &packageRoot,
|
||||
const QString &servicePrefix);
|
||||
|
||||
/**
|
||||
* Uninstalls a package.
|
||||
*
|
||||
* @param package path to the Plasmagik package
|
||||
* @param packageRoot path to the directory where the package should be
|
||||
* installed to
|
||||
* @return true on successful uninstallation, false otherwise
|
||||
**/
|
||||
static bool uninstallPackage(const QString &package,
|
||||
const QString &packageRoot,
|
||||
const QString &servicePrefix);
|
||||
|
||||
/**
|
||||
* Registers a package described by the given desktop file
|
||||
*
|
||||
* @arg the full path to the desktop file (must be KPluginInfo compatible)
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
static bool registerPackage(const PackageMetadata &data, const QString &iconPath);
|
||||
|
||||
/**
|
||||
* Creates a package based on the metadata from the files contained
|
||||
* in the source directory
|
||||
*
|
||||
* @arg metadata description of the package to create
|
||||
* @arg source path to local directory containing the individual
|
||||
* files to be added to the package
|
||||
* @arg destination path to the package that should be created
|
||||
* @arg icon path to the package icon
|
||||
**/
|
||||
static bool createPackage(const PackageMetadata &metadata,
|
||||
const QString &source,
|
||||
const QString &destination,
|
||||
const QString &icon = QString());
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(Package)
|
||||
PackagePrivate * const d;
|
||||
};
|
||||
|
||||
} // Namespace
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user