Page MenuHomePhorge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
This document is not UTF8. It was detected as JIS and converted to UTF8 for display.
diff --git a/plasma/abstractdialogmanager.cpp b/plasma/abstractdialogmanager.cpp
index 50d78f1b8b..e40e2bf809 100644
--- a/plasma/abstractdialogmanager.cpp
+++ b/plasma/abstractdialogmanager.cpp
@@ -1,54 +1,56 @@
/*
* Copyright (C) 2010 Marco Martin <notmart@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "abstractdialogmanager.h"
#include "corona.h"
namespace Plasma
{
class AbstractDialogManagerPrivate
{
public:
AbstractDialogManagerPrivate()
{
}
};
AbstractDialogManager::AbstractDialogManager(Corona *parent)
: QObject(parent),
d(new AbstractDialogManagerPrivate)
{
}
AbstractDialogManager::~AbstractDialogManager()
{
delete d;
}
void AbstractDialogManager::showDialog(QWidget *widget, Plasma::Applet *applet)
{
Q_UNUSED(applet)
widget->show();
}
}
+
+#include "moc_abstractdialogmanager.cpp"
diff --git a/plasma/abstractrunner.cpp b/plasma/abstractrunner.cpp
index 95847ba070..4475842218 100644
--- a/plasma/abstractrunner.cpp
+++ b/plasma/abstractrunner.cpp
@@ -1,455 +1,457 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "abstractrunner.h"
#include <QAction>
#include <QHash>
#include <QMenu>
#include <QMimeData>
#include <QMutex>
#include <QMutexLocker>
#include <QTimer>
#include <kdebug.h>
#include <kicon.h>
#include <kplugininfo.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#include "package.h"
#include "pluginloader.h"
#include "private/abstractrunner_p.h"
#include "querymatch.h"
#include "runnercontext.h"
#include "scripting/runnerscript.h"
namespace Plasma
{
AbstractRunner::AbstractRunner(QObject *parent, const QString &path)
: QObject(parent),
d(new AbstractRunnerPrivate(this))
{
d->init(path);
}
AbstractRunner::AbstractRunner(const KService::Ptr service, QObject *parent)
: QObject(parent),
d(new AbstractRunnerPrivate(this))
{
d->init(service);
}
AbstractRunner::AbstractRunner(QObject *parent, const QVariantList &args)
: QObject(parent),
d(new AbstractRunnerPrivate(this))
{
if (args.count() > 0) {
KService::Ptr service = KService::serviceByStorageId(args[0].toString());
if (service) {
d->init(service);
}
}
}
AbstractRunner::~AbstractRunner()
{
delete d;
}
KConfigGroup AbstractRunner::config() const
{
QString group = id();
if (group.isEmpty()) {
group = "UnnamedRunner";
}
KConfigGroup runners(KGlobal::config(), "Runners");
return KConfigGroup(&runners, group);
}
void AbstractRunner::reloadConfiguration()
{
if (d->script) {
emit d->script->reloadConfiguration();
}
}
void AbstractRunner::addSyntax(const RunnerSyntax &syntax)
{
d->syntaxes.append(syntax);
}
void AbstractRunner::setDefaultSyntax(const RunnerSyntax &syntax)
{
d->syntaxes.append(syntax);
d->defaultSyntax = &(d->syntaxes.last());
}
void AbstractRunner::setSyntaxes(const QList<RunnerSyntax> &syntaxes)
{
d->syntaxes = syntaxes;
}
QList<RunnerSyntax> AbstractRunner::syntaxes() const
{
return d->syntaxes;
}
RunnerSyntax *AbstractRunner::defaultSyntax() const
{
return d->defaultSyntax;
}
void AbstractRunner::performMatch(Plasma::RunnerContext &localContext)
{
static const int reasonableRunTime = 1500;
static const int fastEnoughTime = 250;
if (d->suspendMatching) {
return;
}
QTime time;
time.restart();
//The local copy is already obtained in the job
match(localContext);
// automatically rate limit runners that become slooow
const int runtime = time.elapsed();
bool slowed = speed() == SlowSpeed;
if (!slowed && runtime > reasonableRunTime) {
// we punish runners that return too slowly, even if they don't bring
// back matches
#ifndef NDEBUG
kDebug() << id() << "runner is too slow, putting it on the back burner.";
#endif
d->fastRuns = 0;
setSpeed(SlowSpeed);
}
if (slowed && runtime < fastEnoughTime && localContext.query().size() > 2) {
++d->fastRuns;
if (d->fastRuns > 2) {
// we reward slowed runners who bring back matches fast enough
// 3 times in a row
#ifndef NDEBUG
kDebug() << id() << "runner is faster than we thought, kicking it up a notch";
#endif
setSpeed(NormalSpeed);
}
}
}
QList<QAction*> AbstractRunner::actionsForMatch(const Plasma::QueryMatch &match)
{
Q_UNUSED(match)
QList<QAction*> ret;
if (d->script) {
emit d->script->actionsForMatch(match, &ret);
}
return ret;
}
QAction* AbstractRunner::addAction(const QString &id, const QIcon &icon, const QString &text)
{
QAction *a = new QAction(icon, text, this);
d->actions.insert(id, a);
return a;
}
void AbstractRunner::addAction(const QString &id, QAction *action)
{
d->actions.insert(id, action);
}
void AbstractRunner::removeAction(const QString &id)
{
QAction *a = d->actions.take(id);
delete a;
}
QAction* AbstractRunner::action(const QString &id) const
{
return d->actions.value(id);
}
QHash<QString, QAction*> AbstractRunner::actions() const
{
return d->actions;
}
void AbstractRunner::clearActions()
{
qDeleteAll(d->actions);
d->actions.clear();
}
QMimeData *AbstractRunner::mimeDataForMatch(const QueryMatch &match)
{
Q_UNUSED(match)
return 0;
}
bool AbstractRunner::hasRunOptions()
{
return d->hasRunOptions;
}
void AbstractRunner::setHasRunOptions(bool hasRunOptions)
{
d->hasRunOptions = hasRunOptions;
}
void AbstractRunner::createRunOptions(QWidget *parent)
{
if (d->script) {
emit d->script->createRunOptions(parent);
}
}
AbstractRunner::Speed AbstractRunner::speed() const
{
// the only time the read lock will fail is if we were slow are going to speed up
// or if we were fast and are going to slow down; so don't wait in this case, just
// say we're slow. we either will be soon or were just a moment ago and it doesn't
// hurt to do one more run the slow way
if (!d->speedLock.tryLockForRead()) {
return SlowSpeed;
}
Speed s = d->speed;
d->speedLock.unlock();
return s;
}
void AbstractRunner::setSpeed(Speed speed)
{
d->speedLock.lockForWrite();
d->speed = speed;
d->speedLock.unlock();
}
AbstractRunner::Priority AbstractRunner::priority() const
{
return d->priority;
}
void AbstractRunner::setPriority(Priority priority)
{
d->priority = priority;
}
RunnerContext::Types AbstractRunner::ignoredTypes() const
{
return d->blackListed;
}
void AbstractRunner::setIgnoredTypes(RunnerContext::Types types)
{
d->blackListed = types;
}
void AbstractRunner::run(const Plasma::RunnerContext &search, const Plasma::QueryMatch &action)
{
if (d->script) {
return d->script->run(search, action);
}
}
void AbstractRunner::match(Plasma::RunnerContext &search)
{
if (d->script) {
return d->script->match(search);
}
}
QString AbstractRunner::name() const
{
if (d->runnerDescription.isValid()) {
return d->runnerDescription.name();
}
return objectName();
}
QIcon AbstractRunner::icon() const
{
if (d->runnerDescription.isValid()) {
return KIcon(d->runnerDescription.icon());
}
return QIcon();
}
QString AbstractRunner::id() const
{
if (d->runnerDescription.isValid()) {
return d->runnerDescription.pluginName();
}
return objectName();
}
QString AbstractRunner::description() const
{
if (d->runnerDescription.isValid()) {
return d->runnerDescription.property("Comment").toString();
}
return objectName();
}
Package AbstractRunner::package() const
{
return d->package ? *d->package : Package();
}
void AbstractRunner::init()
{
if (d->script) {
d->setupScriptSupport();
d->script->init();
}
reloadConfiguration();
}
DataEngine *AbstractRunner::dataEngine(const QString &name) const
{
return d->dataEngine(name);
}
bool AbstractRunner::isMatchingSuspended() const
{
return d->suspendMatching;
}
void AbstractRunner::suspendMatching(bool suspend)
{
if (d->suspendMatching == suspend) {
return;
}
d->suspendMatching = suspend;
emit matchingSuspended(suspend);
}
AbstractRunnerPrivate::AbstractRunnerPrivate(AbstractRunner *r)
: priority(AbstractRunner::NormalPriority),
speed(AbstractRunner::NormalSpeed),
blackListed(0),
script(0),
runner(r),
fastRuns(0),
package(0),
defaultSyntax(0),
hasRunOptions(false),
suspendMatching(false)
{
}
AbstractRunnerPrivate::~AbstractRunnerPrivate()
{
delete script;
script = 0;
delete package;
package = 0;
}
void AbstractRunnerPrivate::init(const KService::Ptr service)
{
runnerDescription = KPluginInfo(service);
if (runnerDescription.isValid()) {
const QString api = runnerDescription.property("X-Plasma-API").toString();
if (!api.isEmpty()) {
const QString path = KStandardDirs::locate("data", "plasma/runners/" + runnerDescription.pluginName() + '/');
prepScripting(path, api);
if (!script) {
#ifndef NDEBUG
kDebug() << "Could not create a(n)" << api << "ScriptEngine for the" << runnerDescription.name() << "Runner.";
#endif
}
}
}
}
void AbstractRunnerPrivate::init(const QString &path)
{
runnerDescription = KPluginInfo(path + "/metadata.desktop");
const QString api = runnerDescription.property("X-Plasma-API").toString();
prepScripting(path, api);
}
void AbstractRunnerPrivate::prepScripting(const QString &path, const QString &api)
{
if (script) {
return;
}
delete package;
package = 0;
if (api.isEmpty()) {
return;
}
package = new Package(PluginLoader::self()->loadPackage("Plasma/Runner", api));
package->setPath(path);
if (!package->isValid()) {
#ifndef NDEBUG
kDebug() << "Invalid Runner package at" << path;
#endif
return;
}
script = Plasma::loadScriptEngine(api, runner);
if (!script) {
delete package;
package = 0;
}
}
// put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engine
void AbstractRunnerPrivate::setupScriptSupport()
{
if (!package) {
return;
}
#ifndef NDEBUG
kDebug() << "setting up script support, package is in" << package->path()
<< ", main script is" << package->filePath("mainscript");
#endif
const QString translationsPath = package->filePath("translations");
if (!translationsPath.isEmpty()) {
KGlobal::dirs()->addResourceDir("locale", translationsPath);
KGlobal::locale()->insertCatalog(runnerDescription.pluginName());
}
}
} // Plasma namespace
+
+#include "moc_abstractrunner.cpp"
diff --git a/plasma/abstractrunner.h b/plasma/abstractrunner.h
index 8404edff83..b0bed4c8ad 100644
--- a/plasma/abstractrunner.h
+++ b/plasma/abstractrunner.h
@@ -1,473 +1,474 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PLASMA_ABSTRACTRUNNER_H
#define PLASMA_ABSTRACTRUNNER_H
#include <QtCore/QObject>
#include <QtCore/QMutex>
#include <QtCore/QStringList>
+#include <QIcon>
#include <kconfiggroup.h>
#include <kservice.h>
#include <plasma/plasma_export.h>
#include <plasma/querymatch.h>
#include <plasma/runnercontext.h>
#include <plasma/runnersyntax.h>
#include <plasma/version.h>
class QAction;
class QMimeData;
class KCompletion;
namespace Plasma
{
class DataEngine;
class Package;
class RunnerScript;
class QueryMatch;
class AbstractRunnerPrivate;
/**
* @class AbstractRunner plasma/abstractrunner.h <Plasma/AbstractRunner>
*
* @short An abstract base class for Plasma Runner plugins.
*
* Be aware that runners have to be thread-safe. This is due to the fact that
* each runner is executed in its own thread for each new term. Thus, a runner
* may be executed more than once at the same time. See match() for details.
* To let krunner expose a global shortcut for the single runner query mode, the runner
* must set the "X-Plasma-AdvertiseSingleRunnerMode" key to true in the .desktop file
* and set a default syntax. See setDefaultSyntax() for details.
*
*/
class PLASMA_EXPORT AbstractRunner : public QObject
{
Q_OBJECT
Q_PROPERTY(bool matchingSuspended READ isMatchingSuspended WRITE suspendMatching NOTIFY matchingSuspended)
Q_PROPERTY(QString id READ id);
Q_PROPERTY(QString description READ description);
Q_PROPERTY(QString name READ name);
Q_PROPERTY(QIcon icon READ icon);
public:
/** Specifies a nominal speed for the runner */
enum Speed {
SlowSpeed,
NormalSpeed
};
/** Specifies a priority for the runner */
enum Priority {
LowestPriority = 0,
LowPriority,
NormalPriority,
HighPriority,
HighestPriority
};
/** An ordered list of runners */
typedef QList<AbstractRunner*> List;
virtual ~AbstractRunner();
/**
* This is the main query method. It should trigger creation of
* QueryMatch instances through RunnerContext::addMatch and
* RunnerContext::addMatches. It is called internally by performMatch().
*
* If the runner can run precisely the requested term (RunnerContext::query()),
* it should create an exact match by setting the type to RunnerContext::ExactMatch.
* The first runner that creates a QueryMatch will be the
* default runner. Other runner's matches will be suggested in the
* interface. Non-exact matches should be offered via RunnerContext::PossibleMatch.
*
* The match will be activated via run() if the user selects it.
*
* Each runner is executed in its own thread. Whenever the user input changes this
* method is called again. Thus, it needs to be thread-safe. Also, all matches need
* to be reported once this method returns. Asynchronous runners therefore need
* to make use of a local event loop to wait for all matches.
*
* It is recommended to use local status data in async runners. The simplest way is
* to have a separate class doing all the work like so:
*
* \code
* void MyFancyAsyncRunner::match( RunnerContext& context )
* {
* QEventLoop loop;
* MyAsyncWorker worker( context );
* connect( &worker, SIGNAL(finished()),
* &loop, SLOT(quit()) );
* worker.work();
* loop.exec();
* }
* \endcode
*
* Here MyAsyncWorker creates all the matches and calls RunnerContext::addMatch
* in some internal slot. It emits the finished() signal once done which will
* quit the loop and make the match() method return. The local status is kept
* entirely in MyAsyncWorker which makes match() trivially thread-safe.
*
* If a particular match supports multiple actions, set up the corresponding
* actions in the actionsForMatch method. Do not call any of the action methods
* within this method!
*
* Execution of the correct action should be handled in the run method.
* @caution This method needs to be thread-safe since KRunner will simply
* start a new thread for each new term.
*
* @warning Returning from this method means to end execution of the runner.
*
* @sa run(), RunnerContext::addMatch, RunnerContext::addMatches, QueryMatch
*/
virtual void match(Plasma::RunnerContext &context);
/**
* Triggers a call to match. This will call match() internally.
*
* @param context the search context used in executing this match.
*/
void performMatch(Plasma::RunnerContext &context);
/**
* If the runner has options that the user can interact with to modify
* what happens when run or one of the actions created in match
* is called, the runner should return true
*/
bool hasRunOptions();
/**
* If hasRunOptions() returns true, this method may be called to get
* a widget displaying the options the user can interact with to modify
* the behaviour of what happens when a given match is selected.
*
* @param widget the parent of the options widgets.
*/
virtual void createRunOptions(QWidget *widget);
/**
* Called whenever an exact or possible match associated with this
* runner is triggered.
*
* @param context The context in which the match is triggered, i.e. for which
* the match was created.
* @param match The actual match to run/execute.
*/
virtual void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match);
/**
* The nominal speed of the runner.
* @see setSpeed
*/
Speed speed() const;
/**
* The priority of the runner.
* @see setPriority
*/
Priority priority() const;
/**
* Returns the OR'ed value of all the Information types (as defined in RunnerContext::Type)
* this runner is not interested in.
* @return OR'ed value of black listed types
*/
RunnerContext::Types ignoredTypes() const;
/**
* Sets the types this runner will ignore
* @param types OR'ed listed of ignored types
*/
void setIgnoredTypes(RunnerContext::Types types);
/**
* @return the user visible engine name for the Runner
*/
QString name() const;
/**
* @return an id string for the Runner
*/
QString id() const;
/**
* @return the description of this Runner
*/
QString description() const;
/**
* @return the icon for this Runner
*/
QIcon icon() const;
/**
* Accessor for the associated Package object if any.
*
* Note that the returned pointer is only valid for the lifetime of
* the runner.
*
* @return the Package object, which may be invalid
**/
Package package() const;
/**
* Signal runner to reload its configuration.
*/
virtual void reloadConfiguration();
/**
* @return the syntaxes the runner has registered that it accepts and understands
* @since 4.3
*/
QList<RunnerSyntax> syntaxes() const;
/**
* @return the default syntax for the runner or 0 if no default syntax has been defined
*
* @since 4.4
*/
RunnerSyntax *defaultSyntax() const;
/**
* @return true if the runner is currently busy with non-interuptable work, signaling that
* new threads should not be created for it at this time
* @since 4.6
*/
bool isMatchingSuspended() const;
Q_SIGNALS:
/**
* This signal is emitted when matching is about to commence, giving runners
* an opportunity to prepare themselves, e.g. loading data sets or preparing
* IPC or network connections. This method should be fast so as not to cause
* slow downs. Things that take longer or which should be loaded once and
* remain extant for the lifespan of the AbstractRunner should be done in init().
* @see init()
* @since 4.4
*/
void prepare();
/**
* This signal is emitted when a session of matches is complete, giving runners
* the opportunity to tear down anything set up as a result of the prepare()
* method.
* @since 4.4
*/
void teardown();
/**
* Emitted when the runner enters or exits match suspension
* @see matchingSuspended
* @since 4.6
*/
void matchingSuspended(bool suspended);
protected:
friend class RunnerManager;
friend class RunnerManagerPrivate;
explicit AbstractRunner(QObject *parent = 0, const QString &path = QString());
explicit AbstractRunner(const KService::Ptr service, QObject *parent = 0);
AbstractRunner(QObject *parent, const QVariantList &args);
/**
* Sets whether or not the runner is available for match requests. Useful to
* prevent more thread spawning when the thread is in a busy state.
*/
void suspendMatching(bool suspend);
/**
* Provides access to the runner's configuration object.
*/
KConfigGroup config() const;
/**
* Sets whether or not the runner has options for matches
*/
void setHasRunOptions(bool hasRunOptions);
/**
* Sets the nominal speed of the runner. Only slow runners need
* to call this within their constructor because the default
* speed is NormalSpeed. Runners that use DBUS should call
* this within their constructors.
*/
void setSpeed(Speed newSpeed);
/**
* Sets the priority of the runner. Lower priority runners are executed
* only after higher priority runners.
*/
void setPriority(Priority newPriority);
/**
* A given match can have more than action that can be performed on it.
* For example, a song match returned by a music player runner can be queued,
* added to the playlist, or played.
*
* Call this method to add actions that can be performed by the runner.
* Actions must first be added to the runner's action registry.
* Note: execution of correct action is left up to the runner.
*/
virtual QList<QAction*> actionsForMatch(const Plasma::QueryMatch &match);
/**
* Creates and then adds an action to the action registry.
* AbstractRunner assumes ownership of the created action.
*
* @param id A unique identifier string
* @param icon The icon to display
* @param text The text to display
* @return the created QAction
*/
QAction* addAction(const QString &id, const QIcon &icon, const QString &text);
/**
* Adds an action to the runner's action registry.
*
* The QAction must be created within the GUI thread;
* do not create it within the match method of AbstractRunner.
*
* @param id A unique identifier string
* @param action The QAction to be stored
*/
void addAction(const QString &id, QAction *action);
/**
* Removes the action from the action registry.
* AbstractRunner deletes the action once removed.
*
* @param id The id of the action to be removed
*/
void removeAction(const QString &id);
/**
* Returns the action associated with the id
*/
QAction* action(const QString &id) const;
/**
* Returns all registered actions
*/
QHash<QString, QAction*> actions() const;
/**
* Clears the action registry.
* The action pool deletes the actions.
*/
void clearActions();
/**
* Adds a registered syntax that this runner understands. This is used to
* display to the user what this runner can understand and how it can be
* used.
*
* @param syntax the syntax to register
* @since 4.3
*/
void addSyntax(const RunnerSyntax &syntax);
/**
* Set @p syntax as the default syntax for the runner; the default syntax will be
* substituted to the empty query in single runner mode. This is also used to
* display to the user what this runner can understand and how it can be
* used.
* The default syntax is automatically added to the list of registered syntaxes, there
* is no need to add it using addSyntax.
* Note that there can be only one default syntax; if called more than once, the last
* call will determine the default syntax.
* A default syntax (even trivial) is required to advertise single runner mode
*
* @param syntax the syntax to register and to set as default
* @since 4.4
**/
void setDefaultSyntax(const RunnerSyntax &syntax);
/**
* Sets the list of syntaxes; passing in an empty list effectively clears
* the syntaxes.
*
* @param the syntaxes to register for this runner
* @since 4.3
*/
void setSyntaxes(const QList<RunnerSyntax> &syns);
/**
* Loads the given DataEngine
*
* Tries to load the data engine given by @p name. Each engine is
* only loaded once, and that instance is re-used on all subsequent
* requests.
*
* If the data engine was not found, an invalid data engine is returned
* (see DataEngine::isValid()).
*
* Note that you should <em>not</em> delete the returned engine.
*
* @param name Name of the data engine to load
* @return pointer to the data engine if it was loaded,
* or an invalid data engine if the requested engine
* could not be loaded
*
* @since 4.4
*/
Q_INVOKABLE DataEngine *dataEngine(const QString &name) const;
/**
* Reimplement this slot to run any initialization routines on first load.
* By default, it calls reloadConfiguration(); for scripted Runners this
* method also sets up the ScriptEngine.
*/
virtual void init();
/**
* Reimplement this slot if you want your runner
* to support serialization and drag and drop
* @since 4.5
*/
virtual QMimeData *mimeDataForMatch(const Plasma::QueryMatch &match);
private:
friend class RunnerScript;
AbstractRunnerPrivate *const d;
};
} // Plasma namespace
#define K_EXPORT_PLASMA_RUNNER( libname, classname ) \
K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN(factory("plasma_runner_" #libname)) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
/**
* These plugins are Used by the plugin selector dialog to show
* configuration options specific to this runner. These options
* must be runner global and not pertain to a specific match.
*/
#define K_EXPORT_RUNNER_CONFIG( name, classname ) \
K_PLUGIN_FACTORY(ConfigFactory, registerPlugin<classname>();) \
K_EXPORT_PLUGIN(ConfigFactory("kcm_krunner_" #name)) \
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
#endif
diff --git a/plasma/abstracttoolbox.cpp b/plasma/abstracttoolbox.cpp
index a107e3bada..1ca59d2615 100644
--- a/plasma/abstracttoolbox.cpp
+++ b/plasma/abstracttoolbox.cpp
@@ -1,116 +1,118 @@
/*
* Copyright 2008 by 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 "abstracttoolbox.h"
#include "containment.h"
#include <kservicetypetrader.h>
namespace Plasma
{
class AbstractToolBoxPrivate
{
public:
AbstractToolBoxPrivate(Containment *c)
: containment(c)
{}
Containment *containment;
};
AbstractToolBox::AbstractToolBox(Containment *parent)
: QGraphicsWidget(parent),
d(new AbstractToolBoxPrivate(parent))
{
}
AbstractToolBox::AbstractToolBox(QObject *parent, const QVariantList & /*args*/)
: QGraphicsWidget(dynamic_cast<QGraphicsItem *>(parent)),
d(new AbstractToolBoxPrivate(qobject_cast<Containment *>(parent)))
{
if (!parentItem()) {
setParent(parent);
}
}
AbstractToolBox::~AbstractToolBox()
{
delete d;
}
AbstractToolBox *AbstractToolBox::load(const QString &name, const QVariantList &args, Plasma::Containment *containment)
{
const QString constraint = name.isEmpty() ? QString() : QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ToolBox", constraint);
if (!offers.isEmpty()) {
KService::Ptr offer = offers.first();
KPluginLoader plugin(*offer);
if (Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
return offer->createInstance<AbstractToolBox>(containment, args);
}
}
return 0;
}
KPluginInfo::List AbstractToolBox::listToolBoxInfo(const QString
&parentApp)
{
KPluginInfo::List list;
if (parentApp.isEmpty() || parentApp == KGlobal::mainComponent().componentName()) {
list = KPluginInfo::List();
}
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("not exist [X-KDE-ParentApp]");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ToolBox", constraint);
return list + KPluginInfo::fromServices(offers);
}
Containment *AbstractToolBox::containment() const
{
return d->containment;
}
void AbstractToolBox::restore(const KConfigGroup &group)
{
Q_UNUSED(group)
}
void AbstractToolBox::save(const KConfigGroup &group)
{
Q_UNUSED(group)
}
void AbstractToolBox::reposition()
{}
} // plasma namespace
+
+#include "moc_abstracttoolbox.cpp"
diff --git a/plasma/animations/animation.cpp b/plasma/animations/animation.cpp
index c3887e30fe..3332f645ef 100644
--- a/plasma/animations/animation.cpp
+++ b/plasma/animations/animation.cpp
@@ -1,91 +1,93 @@
/*
* Copyright 2009 Mehmet Ali Akmanalp <makmanalp@wpi.edu>
*
* 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 "animation.h"
#include "private/animationprivate_p.h"
#include <QMapIterator>
#include <QObject>
#include <QParallelAnimationGroup>
#include <QSequentialAnimationGroup>
#include <QDebug>
#include <kdebug.h>
#include <kglobalsettings.h>
namespace Plasma
{
AnimationPrivate::AnimationPrivate()
: easingCurve(QEasingCurve::Linear),
duration(250)
{
}
Animation::Animation(QObject* parent)
: QAbstractAnimation(parent),
d(new AnimationPrivate)
{
}
Animation::~Animation()
{
delete d;
}
int Animation::duration() const
{
return d->duration;
}
void Animation::setDuration(int duration)
{
d->duration = qMax(0, duration);
}
void Animation::setTargetWidget(QGraphicsWidget* widget)
{
d->animObject = widget;
if (parent() == 0) {
setParent(widget);
}
}
QGraphicsWidget* Animation::targetWidget() const
{
return d->animObject.data();
}
void Animation::setEasingCurve(const QEasingCurve &curve)
{
d->easingCurve = curve;
}
QEasingCurve Animation::easingCurve() const
{
return d->easingCurve;
}
void Animation::updateCurrentTime(int currentTime)
{
Q_UNUSED(currentTime)
}
} //namespace Plasma
+
+#include "moc_animation.cpp"
diff --git a/plasma/animations/stackedlayout.cpp b/plasma/animations/stackedlayout.cpp
index 29ec0b637d..46cb9ff675 100644
--- a/plasma/animations/stackedlayout.cpp
+++ b/plasma/animations/stackedlayout.cpp
@@ -1,108 +1,110 @@
/*
Copyright (C) 2009 Igor Trindade Oliveira <igor.oliveira@indt.org.br>
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, see <http://www.gnu.org/licenses/>.
*/
#include "stackedlayout.h"
#include <QGraphicsWidget>
#include <QDebug>
StackedLayout::StackedLayout(QGraphicsLayoutItem *parent)
: QObject(0),
QGraphicsLayout(parent),
m_currentWidgetIndex(-1)
{
}
StackedLayout::~StackedLayout()
{
}
void StackedLayout::setGeometry(const QRectF &rect)
{
QGraphicsLayout::setGeometry(rect);
const QRectF effectiveRect = geometry();
for(int i = 0; i < items.size(); i++) {
itemAt(i)->setGeometry(effectiveRect);
}
}
QSizeF StackedLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(which);
Q_UNUSED(constraint);
qreal left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
if (m_currentWidgetIndex <= 0 || !itemAt(m_currentWidgetIndex)) {
return QSizeF();
}
QSizeF currentWidgetSize = itemAt(m_currentWidgetIndex)->effectiveSizeHint(which, constraint);
return QSizeF( left + right + currentWidgetSize.width(), right + bottom + currentWidgetSize.height());
}
int StackedLayout::count() const
{
return items.count();
}
QGraphicsLayoutItem *StackedLayout::itemAt(int i) const
{
return items.at(i);
}
void StackedLayout::insertWidget(QGraphicsLayoutItem *item, int pos)
{
if(!pos && (m_currentWidgetIndex == -1)) {
m_currentWidgetIndex = 0;
} else {
item->graphicsItem()->hide();
}
items.insert(pos, item);
activate();
}
void StackedLayout::addWidget(QGraphicsLayoutItem *item)
{
insertWidget(item, items.size());
}
void StackedLayout::removeAt(int index)
{
items.removeAt(index);
}
void StackedLayout::setCurrentWidgetIndex(qint32 index)
{
QGraphicsItem *currentWidget = itemAt(m_currentWidgetIndex)->graphicsItem();
QGraphicsItem *hiddenWidget = itemAt(index)->graphicsItem();
currentWidget->hide();
hiddenWidget->show();
m_currentWidgetIndex = index;
}
qint32 StackedLayout::currentWidgetIndex() const
{
return m_currentWidgetIndex;
}
+
+#include "moc_stackedlayout.cpp"
diff --git a/plasma/animator.cpp b/plasma/animator.cpp
index 201c28dba7..99898070ed 100644
--- a/plasma/animator.cpp
+++ b/plasma/animator.cpp
@@ -1,131 +1,130 @@
/*
Copyright (C) 2009 Adenilson Cavalcanti <adenilson.silva@idnt.org.br>
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, see <http://www.gnu.org/licenses/>.
*/
#include "animator.h"
#include <kdebug.h>
#include "animations/animation.h"
#include "animations/fade_p.h"
#include "animations/grow_p.h"
#include "animations/pulser_p.h"
#include "animations/rotation_p.h"
#include "animations/slide_p.h"
#include "animations/rotationstacked_p.h"
#include "animations/geometry_p.h"
#include "animations/zoom_p.h"
#include "animations/pixmaptransition_p.h"
#include "animations/pendulumcurve_p.h"
#include "theme.h"
namespace Plasma
{
Animator::Animator(QObject *parent)
: QObject(parent),
d(0)
{
}
Plasma::Animation* Animator::create(Animator::Animation type, QObject *parent)
{
Plasma::Animation *result = 0;
switch (type) {
case FadeAnimation:
result = new Plasma::FadeAnimation(parent);
break;
case GrowAnimation:
result = new Plasma::GrowAnimation(parent);
break;
case PulseAnimation:
result = new Plasma::PulseAnimation(parent);
break;
case RotationAnimation:
result = new Plasma::RotationAnimation(parent);
break;
case RotationStackedAnimation:
result = new Plasma::RotationStackedAnimation(parent);
break;
case SlideAnimation:
result = new Plasma::SlideAnimation(parent);
break;
case GeometryAnimation:
result = new Plasma::GeometryAnimation(parent);
break;
case ZoomAnimation:
result = new Plasma::ZoomAnimation(parent);
break;
case PixmapTransitionAnimation:
result = new Plasma::PixmapTransition(parent);
break;
default:
//kDebug() << "Unsupported animation type.";
break;
}
return result;
}
QEasingCurve Animator::create(Animator::CurveShape type)
{
QEasingCurve result;
switch (type) {
case EaseInCurve:
result.setType(QEasingCurve::InQuad);
break;
case EaseOutCurve:
result.setType(QEasingCurve::OutQuad);
break;
case EaseInOutCurve:
result.setType(QEasingCurve::InOutQuad);
break;
case LinearCurve:
result.setType(QEasingCurve::Linear);
break;
case PendularCurve:
result = PendulumCurve();
break;
default:
#ifndef NDEBUG
kDebug() << "Unsupported easing curve type.";
#endif
break;
}
return result;
}
} // namespace Plasma
-#include <animator.moc>
-
+#include "moc_animator.cpp"
diff --git a/plasma/applet.cpp b/plasma/applet.cpp
index d59c6ab813..f3953f6b4e 100644
--- a/plasma/applet.cpp
+++ b/plasma/applet.cpp
@@ -1,2584 +1,2585 @@
/*
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
* Copyright 2008 by Mテゥnard Alexis <darktears31@gmail.com>
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* 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 "applet.h"
#include "private/applet_p.h"
#include "config-plasma.h"
#include <plasma/animations/animation.h>
#include <cmath>
#include <limits>
#include <QApplication>
#include <QEvent>
#include <QFile>
#include <QGraphicsGridLayout>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QHostInfo>
#include <QLabel>
#include <QList>
#include <QGraphicsLinearLayout>
#include <QPainter>
#include <QRegExp>
#include <QSize>
#include <QStyleOptionGraphicsItem>
#include <QTextDocument>
#include <QUiLoader>
#include <QVBoxLayout>
#include <QWidget>
#include <kaction.h>
#include <kactioncollection.h>
#include <kauthorized.h>
#include <kcolorscheme.h>
#include <kdialog.h>
#include <kdesktopfile.h>
#include <kicon.h>
#include <kiconloader.h>
#include <kkeysequencewidget.h>
#include <kplugininfo.h>
#include <kstandarddirs.h>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <kshortcut.h>
#include <kwindowsystem.h>
#include <kpushbutton.h>
#ifndef PLASMA_NO_KUTILS
#include <kcmoduleinfo.h>
#include <kcmoduleproxy.h>
#else
#include <kcmodule.h>
#endif
#ifndef PLASMA_NO_SOLID
#include <solid/powermanagement.h>
#endif
#include "abstracttoolbox.h"
#include "authorizationrule.h"
#include "configloader.h"
#include "containment.h"
#include "corona.h"
#include "dataenginemanager.h"
#include "dialog.h"
#include "package.h"
#include "plasma.h"
#include "scripting/appletscript.h"
#include "svg.h"
#include "framesvg.h"
#include "popupapplet.h"
#include "private/applethandle_p.h"
#include "private/framesvg_p.h"
#include "remote/authorizationmanager.h"
#include "remote/authorizationmanager_p.h"
#include "theme.h"
#include "view.h"
#include "widgets/iconwidget.h"
#include "widgets/label.h"
#include "tooltipmanager.h"
#include "wallpaper.h"
#include "paintutils.h"
#include "abstractdialogmanager.h"
#include "pluginloader.h"
#include "private/associatedapplicationmanager_p.h"
#include "private/containment_p.h"
#include "private/package_p.h"
#include "private/packages_p.h"
#include "private/plasmoidservice_p.h"
#include "private/popupapplet_p.h"
#include "private/remotedataengine_p.h"
#include "private/service_p.h"
#include "ui_publish.h"
namespace Plasma
{
Applet::Applet(const KPluginInfo &info, QGraphicsItem *parent, uint appletId)
: QGraphicsWidget(parent),
d(new AppletPrivate(KService::Ptr(), &info, appletId, this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
d->init();
}
Applet::Applet(QGraphicsItem *parent, const QString &serviceID, uint appletId)
: QGraphicsWidget(parent),
d(new AppletPrivate(KService::serviceByStorageId(serviceID), 0, appletId, this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
d->init();
}
Applet::Applet(QGraphicsItem *parent, const QString &serviceID, uint appletId, const QVariantList &args)
: QGraphicsWidget(parent),
d(new AppletPrivate(KService::serviceByStorageId(serviceID), 0, appletId, this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
QVariantList &mutableArgs = const_cast<QVariantList &>(args);
if (!mutableArgs.isEmpty()) {
mutableArgs.removeFirst();
if (!mutableArgs.isEmpty()) {
mutableArgs.removeFirst();
}
}
d->args = mutableArgs;
d->init();
}
Applet::Applet(QObject *parentObject, const QVariantList &args)
: QGraphicsWidget(0),
d(new AppletPrivate(
KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()), 0,
args.count() > 1 ? args[1].toInt() : 0, this))
{
// now remove those first two items since those are managed by Applet and subclasses shouldn't
// need to worry about them. yes, it violates the constness of this var, but it lets us add
// or remove items later while applets can just pretend that their args always start at 0
QVariantList &mutableArgs = const_cast<QVariantList &>(args);
if (!mutableArgs.isEmpty()) {
mutableArgs.removeFirst();
if (!mutableArgs.isEmpty()) {
mutableArgs.removeFirst();
}
}
d->args = mutableArgs;
setParent(parentObject);
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
d->init();
// the brain damage seen in the initialization list is due to the
// inflexibility of KService::createInstance
}
Applet::Applet(const QString &packagePath, uint appletId, const QVariantList &args)
: QGraphicsWidget(0),
d(new AppletPrivate(KService::Ptr(new KService(packagePath + "/metadata.desktop")), 0, appletId, this))
{
Q_UNUSED(args) // FIXME?
d->init(packagePath);
}
Applet::~Applet()
{
//let people know that i will die
emit appletDestroyed(this);
// clean up our config dialog, if any
delete KConfigDialog::exists(d->configDialogId());
delete d;
}
void Applet::init()
{
setFlag(ItemIsMovable, true);
if (d->script) {
d->setupScriptSupport();
if (!d->script->init() && !d->failed) {
setFailedToLaunch(true, i18n("Script initialization failed"));
}
}
}
uint Applet::id() const
{
return d->appletId;
}
void Applet::save(KConfigGroup &g) const
{
if (d->transient) {
return;
}
KConfigGroup group = g;
if (!group.isValid()) {
group = *d->mainConfigGroup();
}
//kDebug() << "saving to" << group.name();
// we call the dptr member directly for locked since isImmutable()
// also checks kiosk and parent containers
group.writeEntry("immutability", (int)d->immutability);
group.writeEntry("plugin", pluginName());
group.writeEntry("geometry", geometry());
group.writeEntry("zvalue", zValue());
if (!d->started) {
return;
}
//kDebug() << pluginName() << "geometry is" << geometry()
// << "pos is" << pos() << "bounding rect is" << boundingRect();
if (transform() == QTransform()) {
group.deleteEntry("transform");
} else {
QList<qreal> m;
QTransform t = transform();
m << t.m11() << t.m12() << t.m13() << t.m21() << t.m22() << t.m23() << t.m31() << t.m32() << t.m33();
group.writeEntry("transform", m);
//group.writeEntry("transform", transformToString(transform()));
}
KConfigGroup appletConfigGroup(&group, "Configuration");
saveState(appletConfigGroup);
if (d->configLoader) {
// we're saving so we know its changed, we don't need or want the configChanged
// signal bubbling up at this point due to that
disconnect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
d->configLoader->writeConfig();
connect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
}
}
void Applet::restore(KConfigGroup &group)
{
QList<qreal> m = group.readEntry("transform", QList<qreal>());
if (m.count() == 9) {
QTransform t(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
setTransform(t);
}
qreal z = group.readEntry("zvalue", 0);
if (z >= AppletPrivate::s_maxZValue) {
AppletPrivate::s_maxZValue = z;
}
if (z > 0) {
setZValue(z);
}
setImmutability((ImmutabilityType)group.readEntry("immutability", (int)Mutable));
QRectF geom = group.readEntry("geometry", QRectF());
if (geom.isValid()) {
setGeometry(geom);
}
KConfigGroup shortcutConfig(&group, "Shortcuts");
QString shortcutText = shortcutConfig.readEntryUntranslated("global", QString());
if (!shortcutText.isEmpty()) {
setGlobalShortcut(KShortcut(shortcutText));
/*
#ifndef NDEBUG
kDebug() << "got global shortcut for" << name() << "of" << QKeySequence(shortcutText);
#endif
#ifndef NDEBUG
kDebug() << "set to" << d->activationAction->objectName()
#endif
<< d->activationAction->globalShortcut().primary();
*/
}
// local shortcut, if any
//TODO: implement; the shortcut will need to be registered with the containment
/*
#include "accessmanager.h"
#include "private/plasmoidservice_p.h"
#include "authorizationmanager.h"
#include "authorizationmanager.h"
shortcutText = shortcutConfig.readEntryUntranslated("local", QString());
if (!shortcutText.isEmpty()) {
//TODO: implement; the shortcut
}
*/
}
void AppletPrivate::setFocus()
{
//kDebug() << "setting focus";
q->setFocus(Qt::ShortcutFocusReason);
}
void Applet::setFailedToLaunch(bool failed, const QString &reason)
{
d->failed = failed;
d->updateFailedToLaunch(reason);
}
void Applet::saveState(KConfigGroup &group) const
{
if (d->script) {
emit d->script->saveState(group);
}
if (group.config()->name() != config().config()->name()) {
// we're being saved to a different file!
// let's just copy the current values in our configuration over
KConfigGroup c = config();
c.copyTo(&group);
}
}
KConfigGroup Applet::config() const
{
if (d->transient) {
return KConfigGroup(KGlobal::config(), "PlasmaTransientsConfig");
}
if (d->isContainment) {
return *(d->mainConfigGroup());
}
return KConfigGroup(d->mainConfigGroup(), "Configuration");
}
KConfigGroup Applet::globalConfig() const
{
KConfigGroup globalAppletConfig;
QString group = isContainment() ? "ContainmentGlobals" : "AppletGlobals";
Corona *corona = qobject_cast<Corona*>(scene());
if (corona) {
KSharedConfig::Ptr coronaConfig = corona->config();
globalAppletConfig = KConfigGroup(coronaConfig, group);
} else {
globalAppletConfig = KConfigGroup(KGlobal::config(), group);
}
return KConfigGroup(&globalAppletConfig, d->globalName());
}
void Applet::destroy()
{
if (immutability() != Mutable || d->transient || !d->started) {
return; //don't double delete
}
d->transient = true;
//FIXME: an animation on leave if !isContainment() would be good again .. which should be handled by the containment class
d->cleanUpAndDelete();
}
bool Applet::destroyed() const
{
return d->transient;
}
void AppletPrivate::selectItemToDestroy()
{
//FIXME: this will not work nicely with multiple screens and being zoomed out!
if (isContainment) {
QGraphicsView *view = q->view();
if (view && view->transform().isScaling() &&
q->scene()->focusItem() != q) {
QGraphicsItem *focus = q->scene()->focusItem();
if (focus) {
Containment *toDestroy = dynamic_cast<Containment*>(focus->topLevelItem());
if (toDestroy) {
toDestroy->destroy();
return;
}
}
}
}
q->destroy();
}
void AppletPrivate::updateRect(const QRectF &rect)
{
q->update(rect);
}
void AppletPrivate::cleanUpAndDelete()
{
//kDebug() << "???????????????? DESTROYING APPLET" << q->name() << q->scene() << " ???????????????????????????";
QGraphicsWidget *parent = dynamic_cast<QGraphicsWidget *>(q->parentItem());
//it probably won't matter, but right now if there are applethandles, *they* are the parent.
//not the containment.
//is the applet in a containment and does the containment have a layout?
//if yes, we remove the applet in the layout
if (parent && parent->layout()) {
QGraphicsLayout *l = parent->layout();
for (int i = 0; i < l->count(); ++i) {
if (q == l->itemAt(i)) {
l->removeAt(i);
break;
}
}
}
if (configLoader) {
configLoader->setDefaults();
}
resetConfigurationObject();
if (q->scene()) {
if (isContainment) {
// prematurely emit our destruction if we are a Containment,
// giving Corona a chance to remove this Containment from its collection
emit q->QObject::destroyed(q);
}
q->scene()->removeItem(q);
}
q->deleteLater();
}
ConfigLoader *Applet::configScheme() const
{
return d->configLoader;
}
DataEngine *Applet::dataEngine(const QString &name) const
{
if (d->remoteLocation.isEmpty()) {
return d->dataEngine(name);
} else {
return d->remoteDataEngine(d->remoteLocation, name);
}
}
Package Applet::package() const
{
return d->package ? *d->package : Package();
}
QGraphicsView *Applet::view() const
{
// It's assumed that we won't be visible on more than one view here.
// Anything that actually needs view() should only really care about
// one of them anyway though.
if (!scene()) {
return 0;
}
QGraphicsView *found = 0;
QGraphicsView *possibleFind = 0;
//kDebug() << "looking through" << scene()->views().count() << "views";
foreach (QGraphicsView *view, scene()->views()) {
//kDebug() << " checking" << view << view->sceneRect()
// << "against" << sceneBoundingRect() << scenePos();
if (view->sceneRect().intersects(sceneBoundingRect()) ||
view->sceneRect().contains(scenePos())) {
//kDebug() << " found something!" << view->isActiveWindow();
if (view->isActiveWindow()) {
found = view;
} else {
possibleFind = view;
}
}
}
return found ? found : possibleFind;
}
QRectF Applet::mapFromView(const QGraphicsView *view, const QRect &rect) const
{
// Why is this adjustment needed? Qt calculation error?
return mapFromScene(view->mapToScene(rect)).boundingRect().adjusted(0, 0, 1, 1);
}
QRect Applet::mapToView(const QGraphicsView *view, const QRectF &rect) const
{
// Why is this adjustment needed? Qt calculation error?
return view->mapFromScene(mapToScene(rect)).boundingRect().adjusted(0, 0, -1, -1);
}
QPoint Applet::popupPosition(const QSize &s) const
{
return popupPosition(s, Qt::AlignLeft);
}
QPoint Applet::popupPosition(const QSize &s, Qt::AlignmentFlag alignment) const
{
Corona * corona = qobject_cast<Corona*>(scene());
Q_ASSERT(corona);
return corona->popupPosition(this, s, alignment);
}
void Applet::updateConstraints(Plasma::Constraints constraints)
{
d->scheduleConstraintsUpdate(constraints);
}
void Applet::constraintsEvent(Plasma::Constraints constraints)
{
//NOTE: do NOT put any code in here that reacts to constraints updates
// as it will not get called for any applet that reimplements constraintsEvent
// without calling the Applet:: version as well, which it shouldn't need to.
// INSTEAD put such code into flushPendingConstraintsEvents
Q_UNUSED(constraints)
//kDebug() << constraints << "constraints are FormFactor: " << formFactor()
// << ", Location: " << location();
if (d->script) {
d->script->constraintsEvent(constraints);
}
}
void Applet::setBusy(bool busy)
{
d->setBusy(busy);
}
bool Applet::isBusy() const
{
return d->isBusy();
}
QString Applet::name() const
{
if (d->isContainment) {
const Containment *c = qobject_cast<const Containment*>(this);
if (c && c->d->isPanelContainment()) {
return i18n("Panel");
} else if (!d->appletDescription.isValid()) {
return i18n("Unknown");
} else {
return d->appletDescription.name();
}
} else if (!d->appletDescription.isValid()) {
return i18n("Unknown Widget");
}
return d->appletDescription.name();
}
QFont Applet::font() const
{
return QApplication::font();
}
QString Applet::icon() const
{
if (!d->appletDescription.isValid()) {
return QString();
}
return d->appletDescription.icon();
}
QString Applet::pluginName() const
{
if (!d->appletDescription.isValid()) {
return QString();
}
return d->appletDescription.pluginName();
}
bool Applet::shouldConserveResources() const
{
#ifndef PLASMA_NO_SOLID
return Solid::PowerManagement::appShouldConserveResources();
#else
return true;
#endif
}
QString Applet::category() const
{
if (!d->appletDescription.isValid()) {
return i18nc("misc category", "Miscellaneous");
}
return d->appletDescription.category();
}
QString Applet::category(const KPluginInfo &applet)
{
return applet.property("X-KDE-PluginInfo-Category").toString();
}
QString Applet::category(const QString &appletName)
{
if (appletName.isEmpty()) {
return QString();
}
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(appletName);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
if (offers.isEmpty()) {
return QString();
}
return offers.first()->property("X-KDE-PluginInfo-Category").toString();
}
ImmutabilityType Applet::immutability() const
{
// if this object is itself system immutable, then just return that; it's the most
// restrictive setting possible and will override anything that might be happening above it
// in the Corona->Containment->Applet hierarchy
if (d->transient || (d->mainConfig && d->mainConfig->isImmutable())) {
return SystemImmutable;
}
//Returning the more strict immutability between the applet immutability, Containment and Corona
ImmutabilityType upperImmutability = Mutable;
Containment *cont = d->isContainment ? 0 : containment();
if (cont) {
upperImmutability = cont->immutability();
} else if (Corona *corona = qobject_cast<Corona*>(scene())) {
upperImmutability = corona->immutability();
}
if (upperImmutability != Mutable) {
// it's either system or user immutable, and we already check for local system immutability,
// so upperImmutability is guaranteed to be as or more severe as this object's immutability
return upperImmutability;
} else {
return d->immutability;
}
}
void Applet::setImmutability(const ImmutabilityType immutable)
{
if (d->immutability == immutable || immutable == Plasma::SystemImmutable) {
// we do not store system immutability in d->immutability since that gets saved
// out to the config file; instead, we check with
// the config group itself for this information at all times. this differs from
// corona, where SystemImmutability is stored in d->immutability.
return;
}
d->immutability = immutable;
updateConstraints(ImmutableConstraint);
}
BackgroundHints Applet::backgroundHints() const
{
return d->backgroundHints;
}
void Applet::setBackgroundHints(const Plasma::BackgroundHints hints)
{
if (d->backgroundHints == hints) {
return;
}
d->backgroundHints = hints;
d->preferredBackgroundHints = hints;
//Draw the standard background?
if ((hints & StandardBackground) || (hints & TranslucentBackground)) {
if (!d->background) {
d->background = new Plasma::FrameSvg(this);
QObject::connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(themeChanged()));
}
if ((hints & TranslucentBackground) &&
Plasma::Theme::defaultTheme()->currentThemeHasImage("widgets/translucentbackground")) {
d->background->setImagePath("widgets/translucentbackground");
} else {
d->background->setImagePath("widgets/background");
}
d->background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
qreal left, top, right, bottom;
d->background->getMargins(left, top, right, bottom);
setContentsMargins(left, right, top, bottom);
QSizeF fitSize(left + right, top + bottom);
d->background->resizeFrame(boundingRect().size());
//if the background has an "overlay" element decide a random position for it and then save it so it's consistent across plasma starts
if (d->background->hasElement("overlay")) {
QSize overlaySize = d->background->elementSize("overlay");
//position is in the boundaries overlaySize.width()*2, overlaySize.height()
qsrand(id());
d->background->d->overlayPos.rx() = - (overlaySize.width() /2) + (overlaySize.width() /4) * (qrand() % (4 + 1));
d->background->d->overlayPos.ry() = (- (overlaySize.height() /2) + (overlaySize.height() /4) * (qrand() % (4 + 1)))/2;
}
} else if (d->background) {
qreal left, top, right, bottom;
d->background->getMargins(left, top, right, bottom);
delete d->background;
d->background = 0;
setContentsMargins(0, 0, 0, 0);
}
update();
}
bool Applet::hasFailedToLaunch() const
{
return d->failed;
}
bool Applet::configurationRequired() const
{
return d->needsConfig;
}
void Applet::setConfigurationRequired(bool needsConfig, const QString &reason)
{
if (d->needsConfig == needsConfig) {
return;
}
d->needsConfig = needsConfig;
d->showConfigurationRequiredMessage(needsConfig, reason);
}
void Applet::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons)
{
d->showMessage(icon, message, buttons);
}
QVariantList Applet::startupArguments() const
{
return d->args;
}
ItemStatus Applet::status() const
{
return d->itemStatus;
}
void Applet::setStatus(const ItemStatus status)
{
d->itemStatus = status;
emit newStatus(status);
}
void Applet::flushPendingConstraintsEvents()
{
if (d->pendingConstraints == NoConstraint) {
return;
}
if (d->constraintsTimer.isActive()) {
d->constraintsTimer.stop();
}
//kDebug() << "fushing constraints: " << d->pendingConstraints << "!!!!!!!!!!!!!!!!!!!!!!!!!!!";
Plasma::Constraints c = d->pendingConstraints;
d->pendingConstraints = NoConstraint;
if (c & Plasma::StartupCompletedConstraint) {
//common actions
bool unlocked = immutability() == Mutable;
QAction *closeApplet = d->actions->action("remove");
if (closeApplet) {
closeApplet->setEnabled(unlocked);
closeApplet->setVisible(unlocked);
connect(closeApplet, SIGNAL(triggered(bool)), this, SLOT(selectItemToDestroy()), Qt::UniqueConnection);
}
QAction *configAction = d->actions->action("configure");
if (configAction) {
if (d->isContainment) {
connect(configAction, SIGNAL(triggered(bool)), this, SLOT(requestConfiguration()), Qt::UniqueConnection);
} else {
connect(configAction, SIGNAL(triggered(bool)), this, SLOT(showConfigurationInterface()), Qt::UniqueConnection);
}
if (d->hasConfigurationInterface) {
bool canConfig = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
configAction->setVisible(canConfig);
configAction->setEnabled(canConfig);
}
}
QAction *runAssociatedApplication = d->actions->action("run associated application");
if (runAssociatedApplication) {
connect(runAssociatedApplication, SIGNAL(triggered(bool)), this, SLOT(runAssociatedApplication()), Qt::UniqueConnection);
}
d->updateShortcuts();
Corona * corona = qobject_cast<Corona*>(scene());
if (corona) {
connect(corona, SIGNAL(shortcutsChanged()), this, SLOT(updateShortcuts()), Qt::UniqueConnection);
}
}
if (c & Plasma::ImmutableConstraint) {
bool unlocked = immutability() == Mutable;
QAction *action = d->actions->action("remove");
if (action) {
action->setVisible(unlocked);
action->setEnabled(unlocked);
}
action = d->actions->action("configure");
if (action && d->hasConfigurationInterface) {
bool canConfig = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
action->setVisible(canConfig);
action->setEnabled(canConfig);
}
if (!unlocked && d->handle) {
AppletHandle *h = d->handle.data();
disconnect(this);
QGraphicsScene *s = scene();
if (s && h->scene() == s) {
s->removeItem(h);
}
h->deleteLater();
}
emit immutabilityChanged(immutability());
}
if (c & Plasma::SizeConstraint) {
d->positionMessageOverlay();
if (d->started && layout()) {
layout()->updateGeometry();
}
}
if (c & Plasma::FormFactorConstraint) {
FormFactor f = formFactor();
if (!d->isContainment && f != Vertical && f != Horizontal) {
setBackgroundHints(d->preferredBackgroundHints);
} else {
BackgroundHints hints = d->preferredBackgroundHints;
setBackgroundHints(NoBackground);
d->preferredBackgroundHints = hints;
}
if (d->failed) {
if (f == Vertical || f == Horizontal) {
QGraphicsLayoutItem *item = layout()->itemAt(1);
layout()->removeAt(1);
delete item;
}
}
// avoid putting rotated applets in panels
if (f == Vertical || f == Horizontal) {
QTransform at;
at.rotateRadians(0);
setTransform(at);
}
//was a size saved for a particular form factor?
if (d->sizeForFormFactor.contains(f)) {
resize(d->sizeForFormFactor.value(f));
}
}
if (!size().isEmpty() &&
((c & Plasma::StartupCompletedConstraint) || (c & Plasma::SizeConstraint && !(c & Plasma::FormFactorConstraint)))) {
d->sizeForFormFactor[formFactor()] = size();
}
if (c & Plasma::SizeConstraint || c & Plasma::FormFactorConstraint) {
if (aspectRatioMode() == Plasma::Square || aspectRatioMode() == Plasma::ConstrainedSquare) {
// enforce square size in panels
//save the old size policy. since ignored doesn't (yet) have a valid use case in containments, use it as special unset value
if (d->preferredSizePolicy == QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)) {
d->preferredSizePolicy = sizePolicy();
}
if (formFactor() == Horizontal) {
setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
} else if (formFactor() == Vertical) {
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
} else if (d->preferredSizePolicy != QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)) {
setSizePolicy(d->preferredSizePolicy);
}
}
updateGeometry();
}
// now take care of constraints in special subclasses: Contaiment and PopupApplet
Containment* containment = qobject_cast<Plasma::Containment*>(this);
if (d->isContainment && containment) {
containment->d->containmentConstraintsEvent(c);
}
PopupApplet* popup = qobject_cast<Plasma::PopupApplet*>(this);
if (popup) {
popup->d->popupConstraintsEvent(c);
}
// pass the constraint on to the actual subclass
constraintsEvent(c);
if (c & StartupCompletedConstraint) {
// start up is done, we can now go do a mod timer
if (d->modificationsTimer) {
if (d->modificationsTimer->isActive()) {
d->modificationsTimer->stop();
}
} else {
d->modificationsTimer = new QBasicTimer;
}
}
}
int Applet::type() const
{
return Type;
}
QList<QAction*> Applet::contextualActions()
{
//kDebug() << "empty context actions";
return d->script ? d->script->contextualActions() : QList<QAction*>();
}
QAction *Applet::action(QString name) const
{
return d->actions->action(name);
}
void Applet::addAction(QString name, QAction *action)
{
d->actions->addAction(name, action);
}
void Applet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
if (!d->started) {
//kDebug() << "not started";
return;
}
if (transform().isRotating()) {
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->setRenderHint(QPainter::Antialiasing);
}
if (d->background &&
formFactor() != Plasma::Vertical &&
formFactor() != Plasma::Horizontal) {
//kDebug() << "option rect is" << option->rect;
d->background->paintFrame(painter);
}
if (d->failed) {
//kDebug() << "failed!";
return;
}
qreal left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QRect contentsRect = QRectF(QPointF(0, 0),
boundingRect().size()).adjusted(left, top, -right, -bottom).toRect();
if (widget && d->isContainment) {
// note that the widget we get is actually the viewport of the view, not the view itself
View* v = qobject_cast<Plasma::View*>(widget->parent());
Containment* c = qobject_cast<Plasma::Containment*>(this);
if (!v || v->isWallpaperEnabled()) {
// paint the wallpaper
if (c && c->drawWallpaper() && c->wallpaper()) {
Wallpaper *w = c->wallpaper();
if (!w->isInitialized()) {
// delayed paper initialization
KConfigGroup wallpaperConfig = c->config();
wallpaperConfig = KConfigGroup(&wallpaperConfig, "Wallpaper");
wallpaperConfig = KConfigGroup(&wallpaperConfig, w->pluginName());
w->restore(wallpaperConfig);
disconnect(w, SIGNAL(update(const QRectF&)), this, SLOT(updateRect(const QRectF&)));
connect(w, SIGNAL(update(const QRectF&)), this, SLOT(updateRect(const QRectF&)));
}
painter->save();
c->wallpaper()->paint(painter, option->exposedRect);
painter->restore();
}
// .. and now paint the actual containment interface, but with
// a Containment style option based on the one we get
// the view must be assigned only if its containment is actually our own
Containment::StyleOption coption(*option);
if (v && v->containment() == containment()) {
coption.view = v;
}
paintInterface(painter, &coption, contentsRect);
}
} else {
//kDebug() << "paint interface of" << (QObject*) this;
// paint the applet's interface
paintInterface(painter, option, contentsRect);
}
}
void Applet::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
if (d->script) {
d->script->paintInterface(painter, option, contentsRect);
} else {
//kDebug() << "Applet::paintInterface() default impl";
}
}
FormFactor Applet::formFactor() const
{
Containment *c = containment();
QGraphicsWidget *pw = qobject_cast<QGraphicsWidget *>(parent());
if (!pw) {
pw = dynamic_cast<QGraphicsWidget *>(parentItem());
}
Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(pw);
//assumption: this loop is usually is -really- short or doesn't run at all
while (!parentApplet && pw && pw->parentWidget()) {
QGraphicsWidget *parentWidget = qobject_cast<QGraphicsWidget *>(pw->parent());
if (!parentWidget) {
parentWidget = dynamic_cast<QGraphicsWidget *>(pw->parentItem());
}
pw = parentWidget;
parentApplet = qobject_cast<Plasma::Applet *>(pw);
}
const PopupApplet *pa = dynamic_cast<const PopupApplet *>(this);
//if the applet is in a widget that isn't a containment
//try to retrieve the formFactor from the parent size
//we can't use our own sizeHint here because it needs formFactor, so endless recursion.
// a popupapplet can always be constrained.
// a normal applet should to but
//FIXME: not always constrained to not break systemmonitor
if (parentApplet && parentApplet != c && c != this && (pa || layout())) {
if (pa || (parentApplet->size().height() < layout()->effectiveSizeHint(Qt::MinimumSize).height())) {
return Plasma::Horizontal;
} else if (pa || (parentApplet->size().width() < layout()->effectiveSizeHint(Qt::MinimumSize).width())) {
return Plasma::Vertical;
}
return parentApplet->formFactor();
}
return c ? c->d->formFactor : Plasma::Planar;
}
Containment *Applet::containment() const
{
if (d->isContainment) {
Containment *c = qobject_cast<Containment*>(const_cast<Applet*>(this));
if (c) {
return c;
}
}
QGraphicsItem *parent = parentItem();
Containment *c = 0;
while (parent) {
Containment *possibleC = dynamic_cast<Containment*>(parent);
if (possibleC && possibleC->Applet::d->isContainment) {
c = possibleC;
break;
}
parent = parent->parentItem();
}
if (!c) {
//if the applet is an offscreen widget its parentItem will be 0, while its parent
//will be its parentWidget, so here we check the QObject hierarchy.
QObject *objParent = this->parent();
while (objParent) {
Containment *possibleC = qobject_cast<Containment*>(objParent);
if (possibleC && possibleC->Applet::d->isContainment) {
c = possibleC;
break;
}
objParent = objParent->parent();
}
}
return c;
}
void Applet::setGlobalShortcut(const KShortcut &shortcut)
{
if (!d->activationAction) {
d->activationAction = new KAction(this);
d->activationAction->setText(i18n("Activate %1 Widget", name()));
d->activationAction->setObjectName(QString("activate widget %1").arg(id())); // NO I18N
connect(d->activationAction, SIGNAL(triggered()), this, SIGNAL(activate()));
connect(d->activationAction, SIGNAL(globalShortcutChanged(QKeySequence)),
this, SLOT(globalShortcutChanged()));
QList<QWidget *> widgets = d->actions->associatedWidgets();
foreach (QWidget *w, widgets) {
w->addAction(d->activationAction);
}
} else if (d->activationAction->globalShortcut() == shortcut) {
return;
}
//kDebug() << "before" << shortcut.primary() << d->activationAction->globalShortcut().primary();
d->activationAction->setGlobalShortcut(
shortcut,
KAction::ShortcutTypes(KAction::ActiveShortcut | KAction::DefaultShortcut),
KAction::NoAutoloading);
d->globalShortcutChanged();
}
void AppletPrivate::showConfigurationRequiredMessage(bool show, const QString &reason)
{
// reimplemented in the UI specific library
Q_UNUSED(show)
Q_UNUSED(reason)
}
void AppletPrivate::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons)
{
// reimplemented in the UI specific library
Q_UNUSED(icon)
Q_UNUSED(message)
Q_UNUSED(buttons)
}
void AppletPrivate::positionMessageOverlay()
{
// reimplemented in the UI specific library
}
void AppletPrivate::setBusy(bool busy)
{
// reimplemented in the UI specific library
Q_UNUSED(busy)
}
bool AppletPrivate::isBusy() const
{
// reimplemented in the UI specific library
return false;
}
void AppletPrivate::updateFailedToLaunch(const QString &reason)
{
// reimplemented in the UI specific library
Q_UNUSED(reason)
}
void AppletPrivate::globalShortcutChanged()
{
if (!activationAction) {
return;
}
KConfigGroup shortcutConfig(mainConfigGroup(), "Shortcuts");
shortcutConfig.writeEntry("global", activationAction->globalShortcut().toString());
scheduleModificationNotification();
//kDebug() << "after" << shortcut.primary() << d->activationAction->globalShortcut().primary();
}
KShortcut Applet::globalShortcut() const
{
if (d->activationAction) {
return d->activationAction->globalShortcut();
}
return KShortcut();
}
bool Applet::isPopupShowing() const
{
return false;
}
void Applet::addAssociatedWidget(QWidget *widget)
{
d->actions->addAssociatedWidget(widget);
}
void Applet::removeAssociatedWidget(QWidget *widget)
{
d->actions->removeAssociatedWidget(widget);
}
Location Applet::location() const
{
Containment *c = containment();
return c ? c->d->location : Plasma::Desktop;
}
Plasma::AspectRatioMode Applet::aspectRatioMode() const
{
return d->aspectRatioMode;
}
void Applet::setAspectRatioMode(Plasma::AspectRatioMode mode)
{
PopupApplet *popup = qobject_cast<PopupApplet *>(this);
if (popup && popup->d->dialogPtr) {
popup->d->dialogPtr.data()->setAspectRatioMode(mode);
popup->d->savedAspectRatio = mode;
}
d->aspectRatioMode = mode;
}
void Applet::registerAsDragHandle(QGraphicsItem *item)
{
if (!item || d->registeredAsDragHandle.contains(item)) {
return;
}
d->registeredAsDragHandle.insert(item);
item->installSceneEventFilter(this);
}
void Applet::unregisterAsDragHandle(QGraphicsItem *item)
{
if (!item) {
return;
}
if (d->registeredAsDragHandle.remove(item)) {
if (item != this) {
item->removeSceneEventFilter(this);
}
}
}
bool Applet::isRegisteredAsDragHandle(QGraphicsItem *item)
{
return d->registeredAsDragHandle.contains(item);
}
bool Applet::hasConfigurationInterface() const
{
return d->hasConfigurationInterface;
}
void Applet::publish(AnnouncementMethods methods, const QString &resourceName)
{
if (!d->remotingService) {
d->remotingService = new PlasmoidService(this);
}
const QString resName = resourceName.isEmpty() ? i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
"%1 on %2", name(), QHostInfo::localHostName())
: resourceName;
#ifndef NDEBUG
kDebug() << "publishing package under name " << resName;
#endif
if (d->package && d->package->isValid()) {
d->remotingService->d->publish(methods, resName, d->package->metadata());
} else if (!d->package && d->appletDescription.isValid()) {
d->remotingService->d->publish(methods, resName, d->appletDescription);
} else {
delete d->remotingService;
d->remotingService = 0;
#ifndef NDEBUG
kDebug() << "Can not publish invalid applets.";
#endif
}
}
void Applet::unpublish()
{
if (d->remotingService) {
d->remotingService->d->unpublish();
}
}
bool Applet::isPublished() const
{
return d->remotingService && d->remotingService->d->isPublished();
}
void Applet::setHasConfigurationInterface(bool hasInterface)
{
if (hasInterface == d->hasConfigurationInterface) {
return;
}
QAction *configAction = d->actions->action("configure");
if (configAction) {
bool enable = hasInterface;
if (enable) {
const bool unlocked = immutability() == Mutable;
enable = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
}
configAction->setEnabled(enable);
}
d->hasConfigurationInterface = hasInterface;
}
KActionCollection* AppletPrivate::defaultActions(QObject *parent)
{
KActionCollection *actions = new KActionCollection(parent);
actions->setConfigGroup("Shortcuts-Applet");
KAction *configAction = actions->addAction("configure");
configAction->setAutoRepeat(false);
configAction->setText(i18n("Widget Settings"));
configAction->setIcon(KIcon("configure"));
configAction->setShortcut(KShortcut("alt+d, s"));
configAction->setData(AbstractToolBox::ConfigureTool);
KAction *closeApplet = actions->addAction("remove");
closeApplet->setAutoRepeat(false);
closeApplet->setText(i18n("Remove this Widget"));
closeApplet->setIcon(KIcon("edit-delete"));
closeApplet->setShortcut(KShortcut("alt+d, r"));
closeApplet->setData(AbstractToolBox::DestructiveTool);
KAction *runAssociatedApplication = actions->addAction("run associated application");
runAssociatedApplication->setAutoRepeat(false);
runAssociatedApplication->setText(i18n("Run the Associated Application"));
runAssociatedApplication->setIcon(KIcon("system-run"));
runAssociatedApplication->setShortcut(KShortcut("alt+d, t"));
runAssociatedApplication->setVisible(false);
runAssociatedApplication->setEnabled(false);
runAssociatedApplication->setData(AbstractToolBox::ControlTool);
return actions;
}
bool Applet::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
{
if (watched == this) {
switch (event->type()) {
case QEvent::GraphicsSceneHoverEnter:
//kDebug() << "got hoverenterEvent" << immutability() << " " << immutability();
if (immutability() == Mutable) {
QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
if (d->handle) {
d->handle.data()->setHoverPos(he->pos());
} else {
//kDebug() << "generated applet handle";
AppletHandle *handle = new AppletHandle(containment(), this, he->pos());
connect(handle, SIGNAL(disappearDone(AppletHandle*)),
this, SLOT(handleDisappeared(AppletHandle*)));
connect(this, SIGNAL(geometryChanged()),
handle, SLOT(appletResized()));
d->handle = handle;
}
}
break;
case QEvent::GraphicsSceneHoverMove:
if (d->handle && !d->handle.data()->shown() && immutability() == Mutable) {
QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
d->handle.data()->setHoverPos(he->pos());
}
break;
default:
break;
}
}
switch (event->type()) {
case QEvent::GraphicsSceneMouseMove:
case QEvent::GraphicsSceneMousePress:
case QEvent::GraphicsSceneMouseRelease:
{
// don't move when the containment is not mutable,
// in the rare case the containment doesn't exists consider it as mutable
if ((flags() & ItemIsMovable) && d->registeredAsDragHandle.contains(watched)) {
Containment *c = containment();
if (!c || c->immutability() == Mutable) {
scene()->sendEvent(this, event);
return false;
}
}
break;
}
default:
break;
}
return QGraphicsItem::sceneEventFilter(watched, event);
}
void Applet::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (immutability() == Mutable && formFactor() == Plasma::Planar && (flags() & ItemIsMovable)) {
QGraphicsWidget::mouseMoveEvent(event);
}
}
void Applet::focusInEvent(QFocusEvent *event)
{
if (!isContainment() && containment()) {
//focusing an applet may trigger this event again, but we won't be here more than twice
containment()->d->focusApplet(this);
}
QGraphicsWidget::focusInEvent(event);
}
void Applet::resizeEvent(QGraphicsSceneResizeEvent *event)
{
QGraphicsWidget::resizeEvent(event);
if (d->background) {
d->background->resizeFrame(boundingRect().size());
}
updateConstraints(Plasma::SizeConstraint);
d->scheduleModificationNotification();
emit geometryChanged();
}
bool Applet::isUserConfiguring() const
{
return KConfigDialog::exists(d->configDialogId());
}
void Applet::showConfigurationInterface()
{
if (!hasConfigurationInterface()) {
return;
}
if (immutability() != Mutable && !KAuthorized::authorize("plasma/allow_configure_when_locked")) {
return;
}
KConfigDialog *dlg = KConfigDialog::exists(d->configDialogId());
if (dlg) {
KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
dlg->show();
KWindowSystem::activateWindow(dlg->winId());
return;
}
d->publishUI.publishCheckbox = 0;
if (d->package) {
KConfigDialog *dialog = 0;
const QString uiFile = d->package->filePath("mainconfigui");
KDesktopFile df(d->package->path() + "/metadata.desktop");
const QStringList kcmPlugins = df.desktopGroup().readEntry("X-Plasma-ConfigPlugins", QStringList());
if (!uiFile.isEmpty() || !kcmPlugins.isEmpty()) {
KConfigSkeleton *configLoader = d->configLoader ? d->configLoader : new KConfigSkeleton(0);
dialog = new AppletConfigDialog(0, d->configDialogId(), configLoader);
if (!d->configLoader) {
// delete the temporary when this dialog is done
configLoader->setParent(dialog);
}
dialog->setWindowTitle(d->configWindowTitle());
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
bool hasPages = false;
QFile f(uiFile);
QUiLoader loader;
QWidget *w = loader.load(&f);
if (w) {
dialog->addPage(w, i18n("Settings"), icon(), i18n("%1 Settings", name()));
hasPages = true;
}
foreach (const QString &kcm, kcmPlugins) {
#ifndef PLASMA_NO_KUTILS
KCModuleProxy *module = new KCModuleProxy(kcm);
if (module->realModule()) {
connect(module, SIGNAL(changed(bool)), dialog, SLOT(settingsModified(bool)));
dialog->addPage(module, module->moduleInfo().moduleName(), module->moduleInfo().icon());
hasPages = true;
} else {
delete module;
}
#else
KService::Ptr service = KService::serviceByStorageId(kcm);
if (service) {
QString error;
KCModule *module = service->createInstance<KCModule>(dialog, QVariantList(), &error);
if (module) {
connect(module, SIGNAL(changed(bool)), dialog, SLOT(settingsModified(bool)));
dialog->addPage(module, service->name(), service->icon());
hasPages = true;
} else {
#ifndef NDEBUG
kDebug() << "failed to load kcm" << kcm << "for" << name();
#endif
}
}
#endif
}
if (hasPages) {
d->addGlobalShortcutsPage(dialog);
d->addPublishPage(dialog);
dialog->show();
} else {
delete dialog;
dialog = 0;
}
}
if (!dialog && d->script) {
d->script->showConfigurationInterface();
}
} else if (d->script) {
d->script->showConfigurationInterface();
} else {
KConfigDialog *dialog = d->generateGenericConfigDialog();
d->addStandardConfigurationPages(dialog);
showConfigurationInterface(dialog);
}
emit releaseVisualFocus();
}
void Applet::showConfigurationInterface(QWidget *widget)
{
if (!containment() || !containment()->corona() ||
!containment()->corona()->dialogManager()) {
widget->show();
return;
}
QMetaObject::invokeMethod(containment()->corona()->dialogManager(), "showDialog", Q_ARG(QWidget *, widget), Q_ARG(Plasma::Applet *, this));
}
QString AppletPrivate::configDialogId() const
{
return QString("%1settings%2").arg(appletId).arg(q->name());
}
QString AppletPrivate::configWindowTitle() const
{
return i18nc("@title:window", "%1 Settings", q->name());
}
QSet<QString> AppletPrivate::knownCategories()
{
// this is to trick the tranlsation tools into making the correct
// strings for translation
QSet<QString> categories = s_customCategories;
categories << QString(I18N_NOOP("Accessibility")).toLower()
<< QString(I18N_NOOP("Application Launchers")).toLower()
<< QString(I18N_NOOP("Astronomy")).toLower()
<< QString(I18N_NOOP("Date and Time")).toLower()
<< QString(I18N_NOOP("Development Tools")).toLower()
<< QString(I18N_NOOP("Education")).toLower()
<< QString(I18N_NOOP("Environment and Weather")).toLower()
<< QString(I18N_NOOP("Examples")).toLower()
<< QString(I18N_NOOP("File System")).toLower()
<< QString(I18N_NOOP("Fun and Games")).toLower()
<< QString(I18N_NOOP("Graphics")).toLower()
<< QString(I18N_NOOP("Language")).toLower()
<< QString(I18N_NOOP("Mapping")).toLower()
<< QString(I18N_NOOP("Miscellaneous")).toLower()
<< QString(I18N_NOOP("Multimedia")).toLower()
<< QString(I18N_NOOP("Online Services")).toLower()
<< QString(I18N_NOOP("Productivity")).toLower()
<< QString(I18N_NOOP("System Information")).toLower()
<< QString(I18N_NOOP("Utilities")).toLower()
<< QString(I18N_NOOP("Windows and Tasks")).toLower();
return categories;
}
KConfigDialog *AppletPrivate::generateGenericConfigDialog()
{
KConfigSkeleton *nullManager = new KConfigSkeleton(0);
KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager);
nullManager->setParent(dialog);
dialog->setFaceType(KPageDialog::Auto);
dialog->setWindowTitle(configWindowTitle());
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
q->createConfigurationInterface(dialog);
dialog->showButton(KDialog::Default, false);
dialog->showButton(KDialog::Help, false);
QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()));
QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()));
return dialog;
}
void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog)
{
addGlobalShortcutsPage(dialog);
addPublishPage(dialog);
}
void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog)
{
#ifndef PLASMA_NO_GLOBAL_SHORTCUTS
if (isContainment) {
return;
}
QWidget *page = new QWidget;
QVBoxLayout *layout = new QVBoxLayout(page);
if (!shortcutEditor) {
shortcutEditor = new KKeySequenceWidget(page);
QObject::connect(shortcutEditor.data(), SIGNAL(keySequenceChanged(QKeySequence)), dialog, SLOT(settingsModified()));
}
shortcutEditor.data()->setKeySequence(q->globalShortcut().primary());
layout->addWidget(shortcutEditor.data());
layout->addStretch();
dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard");
QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
#endif
}
void AppletPrivate::addPublishPage(KConfigDialog *dialog)
{
#ifdef ENABLE_REMOTE_WIDGETS
QWidget *page = new QWidget;
publishUI.setupUi(page);
publishUI.publishCheckbox->setChecked(q->isPublished());
QObject::connect(publishUI.publishCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
publishUI.allUsersCheckbox->setEnabled(q->isPublished());
QObject::connect(publishUI.allUsersCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
QString resourceName =
i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
"%1 on %2", q->name(), QHostInfo::localHostName());
if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
publishUI.allUsersCheckbox->setChecked(true);
} else {
publishUI.allUsersCheckbox->setChecked(false);
}
q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)),
q, SLOT(publishCheckboxStateChanged(int)));
dialog->addPage(page, i18n("Share"), "applications-internet");
#endif
}
void AppletPrivate::publishCheckboxStateChanged(int state)
{
if (state == Qt::Checked) {
publishUI.allUsersCheckbox->setEnabled(true);
} else {
publishUI.allUsersCheckbox->setEnabled(false);
}
}
void AppletPrivate::configDialogFinished()
{
if (shortcutEditor) {
QKeySequence sequence = shortcutEditor.data()->keySequence();
if (sequence != q->globalShortcut().primary()) {
q->setGlobalShortcut(KShortcut(sequence));
emit q->configNeedsSaving();
}
}
#ifdef ENABLE_REMOTE_WIDGETS
if (KConfigDialog::exists(configDialogId()) && publishUI.publishCheckbox) {
q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked());
if (publishUI.publishCheckbox->isChecked()) {
QString resourceName =
i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
"%1 on %2", q->name(), QHostInfo::localHostName());
q->publish(Plasma::ZeroconfAnnouncement, resourceName);
if (publishUI.allUsersCheckbox->isChecked()) {
if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
AuthorizationRule *rule = new AuthorizationRule(resourceName, "");
rule->setPolicy(AuthorizationRule::Allow);
rule->setTargets(AuthorizationRule::AllUsers);
AuthorizationManager::self()->d->rules.append(rule);
}
} else {
AuthorizationRule *matchingRule =
AuthorizationManager::self()->d->matchingRule(resourceName, Credentials());
if (matchingRule) {
AuthorizationManager::self()->d->rules.removeAll(matchingRule);
}
}
} else {
q->unpublish();
}
}
#endif
if (!configLoader) {
// the config loader will trigger this for us, so we don't need to.
propagateConfigChanged();
if (KConfigDialog *dialog = qobject_cast<KConfigDialog *>(q->sender())) {
dialog->enableButton(KDialog::Apply, false);
}
}
}
void AppletPrivate::updateShortcuts()
{
if (isContainment) {
//a horrible hack to avoid clobbering corona settings
//we pull them out, then read, then put them back
QList<QString> names;
QList<QAction*> qactions;
names << "add sibling containment" << "configure shortcuts" << "lock widgets";
foreach (const QString &name, names) {
QAction *a = actions->action(name);
actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method
qactions << a;
}
actions->readSettings();
for (int i = 0; i < names.size(); ++i) {
QAction *a = qactions.at(i);
if (a) {
actions->addAction(names.at(i), a);
}
}
} else {
actions->readSettings();
}
}
void AppletPrivate::propagateConfigChanged()
{
if (isContainment) {
Containment *c = qobject_cast<Containment *>(q);
if (c) {
c->d->configChanged();
}
}
q->configChanged();
}
void Applet::configChanged()
{
if (d->script) {
if (d->configLoader) {
d->configLoader->readConfig();
}
d->script->configChanged();
}
}
void Applet::createConfigurationInterface(KConfigDialog *parent)
{
Q_UNUSED(parent)
// virtual method reimplemented by subclasses.
// do not put anything here ...
}
bool Applet::hasAuthorization(const QString &constraint) const
{
KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
return constraintGroup.readEntry(constraint, true);
}
void Applet::setAssociatedApplication(const QString &string)
{
AssociatedApplicationManager::self()->setApplication(this, string);
QAction *runAssociatedApplication = d->actions->action("run associated application");
if (runAssociatedApplication) {
bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
valid = valid && hasAuthorization("LaunchApp"); //obey security!
runAssociatedApplication->setVisible(valid);
runAssociatedApplication->setEnabled(valid);
}
}
void Applet::setAssociatedApplicationUrls(const KUrl::List &urls)
{
AssociatedApplicationManager::self()->setUrls(this, urls);
QAction *runAssociatedApplication = d->actions->action("run associated application");
if (runAssociatedApplication) {
bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
valid = valid && hasAuthorization("LaunchApp"); //obey security!
runAssociatedApplication->setVisible(valid);
runAssociatedApplication->setEnabled(valid);
}
}
QString Applet::associatedApplication() const
{
return AssociatedApplicationManager::self()->application(this);
}
KUrl::List Applet::associatedApplicationUrls() const
{
return AssociatedApplicationManager::self()->urls(this);
}
void Applet::runAssociatedApplication()
{
if (hasAuthorization("LaunchApp")) {
AssociatedApplicationManager::self()->run(this);
}
}
bool Applet::hasValidAssociatedApplication() const
{
return AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
}
void AppletPrivate::filterOffers(QList<KService::Ptr> &offers)
{
KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
foreach (const QString &key, constraintGroup.keyList()) {
//kDebug() << "security constraint" << key;
if (constraintGroup.readEntry(key, true)) {
continue;
}
//ugh. a qlist of ksharedptr<kservice>
QMutableListIterator<KService::Ptr> it(offers);
while (it.hasNext()) {
KService::Ptr p = it.next();
QString prop = QString("X-Plasma-Requires-").append(key);
QVariant req = p->property(prop, QVariant::String);
//valid values: Required/Optional/Unused
QString reqValue;
if (req.isValid()) {
reqValue = req.toString();
} else if (p->property("X-Plasma-API").toString().toLower() == "javascript") {
//TODO: be able to check whether or not a script engine provides "controled"
//bindings; for now we just give a pass to the qscript ones
reqValue = "Unused";
}
if (!(reqValue == "Optional" || reqValue == "Unused")) {
//if (reqValue == "Required") {
it.remove();
}
}
}
}
QString AppletPrivate::parentAppConstraint(const QString &parentApp)
{
if (parentApp.isEmpty()) {
return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')")
.arg(KGlobal::mainComponent().aboutData()->appName());
}
return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp);
}
KPluginInfo::List Applet::listAppletInfo(const QString &category, const QString &parentApp)
{
return PluginLoader::self()->listAppletInfo(category, parentApp);
}
KPluginInfo::List Applet::listAppletInfoForMimeType(const QString &mimeType)
{
QString constraint = AppletPrivate::parentAppConstraint();
constraint.append(QString(" and '%1' in [X-Plasma-DropMimeTypes]").arg(mimeType));
//kDebug() << "listAppletInfoForMimetype with" << mimeType << constraint;
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
AppletPrivate::filterOffers(offers);
return KPluginInfo::fromServices(offers);
}
KPluginInfo::List Applet::listAppletInfoForUrl(const QUrl &url)
{
QString constraint = AppletPrivate::parentAppConstraint();
constraint.append(" and exist [X-Plasma-DropUrlPatterns]");
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
AppletPrivate::filterOffers(offers);
KPluginInfo::List allApplets = KPluginInfo::fromServices(offers);
KPluginInfo::List filtered;
foreach (const KPluginInfo &info, allApplets) {
QStringList urlPatterns = info.property("X-Plasma-DropUrlPatterns").toStringList();
foreach (const QString &glob, urlPatterns) {
QRegExp rx(glob);
rx.setPatternSyntax(QRegExp::Wildcard);
if (rx.exactMatch(url.toString())) {
#ifndef NDEBUG
kDebug() << info.name() << "matches" << glob << url;
#endif
filtered << info;
}
}
}
return filtered;
}
QStringList Applet::listCategories(const QString &parentApp, bool visibleOnly)
{
QString constraint = AppletPrivate::parentAppConstraint(parentApp);
constraint.append(" and exist [X-KDE-PluginInfo-Category]");
KConfigGroup group(KGlobal::config(), "General");
const QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
foreach (const QString &category, excluded) {
constraint.append(" and [X-KDE-PluginInfo-Category] != '").append(category).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
AppletPrivate::filterOffers(offers);
QStringList categories;
QSet<QString> known = AppletPrivate::knownCategories();
foreach (const KService::Ptr &applet, offers) {
QString appletCategory = applet->property("X-KDE-PluginInfo-Category").toString();
if (visibleOnly && applet->noDisplay()) {
// we don't want to show the hidden category
continue;
}
//kDebug() << " and we have " << appletCategory;
if (!appletCategory.isEmpty() && !known.contains(appletCategory.toLower())) {
#ifndef NDEBUG
kDebug() << "Unknown category: " << applet->name() << "says it is in the"
<< appletCategory << "category which is unknown to us";
#endif
appletCategory.clear();
}
if (appletCategory.isEmpty()) {
if (!categories.contains(i18nc("misc category", "Miscellaneous"))) {
categories << i18nc("misc category", "Miscellaneous");
}
} else if (!categories.contains(appletCategory)) {
categories << appletCategory;
}
}
categories.sort();
return categories;
}
void Applet::setCustomCategories(const QStringList &categories)
{
AppletPrivate::s_customCategories = QSet<QString>::fromList(categories);
}
QStringList Applet::customCategories()
{
return AppletPrivate::s_customCategories.toList();
}
Applet *Applet::loadPlasmoid(const QString &path, uint appletId, const QVariantList &args)
{
if (QFile::exists(path + "/metadata.desktop")) {
KService service(path + "/metadata.desktop");
const QStringList &types = service.serviceTypes();
if (types.contains("Plasma/Containment")) {
return new Containment(path, appletId, args);
} else if (types.contains("Plasma/PopupApplet")) {
return new PopupApplet(path, appletId, args);
} else {
return new Applet(path, appletId, args);
}
}
return 0;
}
QVariant Applet::itemChange(GraphicsItemChange change, const QVariant &value)
{
QVariant ret = QGraphicsWidget::itemChange(change, value);
//kDebug() << change;
switch (change) {
case ItemSceneHasChanged: {
Corona *newCorona = qobject_cast<Corona *>(qvariant_cast<QGraphicsScene*>(value));
if (newCorona && newCorona->immutability() != Mutable) {
updateConstraints(ImmutableConstraint);
}
}
break;
case ItemParentChange:
if (!d->isContainment) {
Containment *c = containment();
if (d->mainConfig && !c) {
kWarning() << "Configuration object was requested prior to init(), which is too early. "
"Please fix this item:" << parentItem() << value.value<QGraphicsItem *>()
<< name();
Applet *newC = dynamic_cast<Applet*>(value.value<QGraphicsItem *>());
if (newC) {
// if this is an applet, and we've just been assigned to our first containment,
// but the applet did something stupid like ask for the config() object prior to
// this happening (e.g. inits ctor) then let's repair that situation for them.
KConfigGroup *old = d->mainConfig;
KConfigGroup appletConfig = newC->config();
appletConfig = KConfigGroup(&appletConfig, "Applets");
d->mainConfig = new KConfigGroup(&appletConfig, QString::number(d->appletId));
old->copyTo(d->mainConfig);
old->deleteGroup();
delete old;
}
}
}
break;
case ItemParentHasChanged:
{
if (isContainment()) {
removeSceneEventFilter(this);
} else {
Containment *c = containment();
if (c && c->containmentType() == Containment::DesktopContainment) {
installSceneEventFilter(this);
} else {
removeSceneEventFilter(this);
}
}
}
break;
case ItemPositionHasChanged:
emit geometryChanged();
// fall through!
case ItemTransformHasChanged:
d->scheduleModificationNotification();
break;
default:
break;
};
return ret;
}
QPainterPath Applet::shape() const
{
if (d->script) {
return d->script->shape();
}
return QGraphicsWidget::shape();
}
QSizeF Applet::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
QSizeF hint = QGraphicsWidget::sizeHint(which, constraint);
const FormFactor ff = formFactor();
// in panels make sure that the contents won't exit from the panel
if (which == Qt::MinimumSize) {
if (ff == Horizontal) {
hint.setHeight(0);
} else if (ff == Vertical) {
hint.setWidth(0);
}
}
// enforce a square size in panels
if (d->aspectRatioMode == Plasma::Square) {
if (ff == Horizontal) {
hint.setWidth(size().height());
} else if (ff == Vertical) {
hint.setHeight(size().width());
}
} else if (d->aspectRatioMode == Plasma::ConstrainedSquare) {
//enforce a size not wider than tall
if (ff == Horizontal) {
hint.setWidth(size().height());
//enforce a size not taller than wide
} else if (ff == Vertical && (which == Qt::MaximumSize || size().width() <= KIconLoader::SizeLarge)) {
hint.setHeight(size().width());
}
}
return hint;
}
void Applet::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
}
void Applet::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
}
void Applet::timerEvent(QTimerEvent *event)
{
if (d->transient) {
d->constraintsTimer.stop();
if (d->modificationsTimer) {
d->modificationsTimer->stop();
}
return;
}
if (event->timerId() == d->constraintsTimer.timerId()) {
d->constraintsTimer.stop();
// Don't flushPendingConstraints if we're just starting up
// flushPendingConstraints will be called by Corona
if(!(d->pendingConstraints & Plasma::StartupCompletedConstraint)) {
flushPendingConstraintsEvents();
}
} else if (d->modificationsTimer && event->timerId() == d->modificationsTimer->timerId()) {
d->modificationsTimer->stop();
// invalid group, will result in save using the default group
KConfigGroup cg;
save(cg);
emit configNeedsSaving();
}
}
QRect Applet::screenRect() const
{
QGraphicsView *v = view();
if (v) {
QPointF bottomRight = pos();
bottomRight.rx() += size().width();
bottomRight.ry() += size().height();
QPoint tL = v->mapToGlobal(v->mapFromScene(pos()));
QPoint bR = v->mapToGlobal(v->mapFromScene(bottomRight));
return QRect(QPoint(tL.x(), tL.y()), QSize(bR.x() - tL.x(), bR.y() - tL.y()));
}
//The applet doesn't have a view on it.
//So a screenRect isn't relevant.
return QRect(QPoint(0, 0), QSize(0, 0));
}
void Applet::raise()
{
setZValue(++AppletPrivate::s_maxZValue);
}
void Applet::lower()
{
setZValue(--AppletPrivate::s_minZValue);
}
void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate)
{
if (isContainment == nowIsContainment && !forceUpdate) {
return;
}
isContainment = nowIsContainment;
//FIXME I do not like this function.
//currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way.
//if someone calls it at some other time it'll cause headaches. :P
delete mainConfig;
mainConfig = 0;
Containment *c = q->containment();
if (c) {
c->d->checkContainmentFurniture();
}
}
bool Applet::isContainment() const
{
return d->isContainment;
}
// PRIVATE CLASS IMPLEMENTATION
AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet)
: appletId(uniqueID),
q(applet),
remotingService(0),
preferredBackgroundHints(StandardBackground),
backgroundHints(NoBackground),
aspectRatioMode(Plasma::KeepAspectRatio),
immutability(Mutable),
appletDescription(info ? *info : KPluginInfo(service)),
background(0),
mainConfig(0),
pendingConstraints(NoConstraint),
script(0),
package(0),
configLoader(0),
actions(AppletPrivate::defaultActions(applet)),
activationAction(0),
itemStatus(UnknownStatus),
preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored),
modificationsTimer(0),
hasConfigurationInterface(false),
failed(false),
isContainment(false),
transient(false),
needsConfig(false),
started(false)
{
if (appletId == 0) {
appletId = ++s_maxAppletId;
} else if (appletId > s_maxAppletId) {
s_maxAppletId = appletId;
}
}
AppletPrivate::~AppletPrivate()
{
if (activationAction && activationAction->isGlobalShortcutEnabled()) {
//kDebug() << "reseting global action for" << q->name() << activationAction->objectName();
activationAction->forgetGlobalShortcut();
}
delete script;
script = 0;
delete package;
package = 0;
delete configLoader;
configLoader = 0;
delete mainConfig;
mainConfig = 0;
delete modificationsTimer;
}
void AppletPrivate::init(const QString &packagePath)
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
q->setAcceptsHoverEvents(true);
q->setFlag(QGraphicsItem::ItemIsFocusable, true);
q->setFocusPolicy(Qt::ClickFocus);
// FIXME: adding here because nothing seems to be doing it in QGraphicsView,
// but it doesn't actually work anyways =/
q->setLayoutDirection(qApp->layoutDirection());
//set a default size before any saved settings are read
QSize size(200, 200);
q->setBackgroundHints(DefaultBackground);
q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor?
QAction *closeApplet = actions->action("remove");
if (closeApplet) {
closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name()));
}
QAction *configAction = actions->action("configure");
if (configAction) {
configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name()));
}
QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus()));
if (!appletDescription.isValid()) {
#ifndef NDEBUG
kDebug() << "Check your constructor! "
<< "You probably want to be passing in a Service::Ptr "
<< "or a QVariantList with a valid storageid as arg[0].";
#endif
q->resize(size);
return;
}
QVariant s = appletDescription.property("X-Plasma-DefaultSize");
if (s.isValid()) {
size = s.toSize();
}
//kDebug() << "size" << size;
q->resize(size);
QString api = appletDescription.property("X-Plasma-API").toString();
// we have a scripted plasmoid
if (api.isEmpty()) {
q->setFailedToLaunch(true, i18n("The %2 widget did not define which ScriptEngine to use.", appletDescription.name()));
return;
}
package = new Package(PluginLoader::self()->loadPackage("Plasma/Applet", api));
// find where the Package is
QString path = packagePath;
if (path.isEmpty()) {
const QString subPath = package->defaultPackageRoot() + appletDescription.pluginName() + '/';
path = KStandardDirs::locate("data", subPath + "metadata.desktop");
if (path.isEmpty()) {
path = KStandardDirs::locate("data", subPath);
} else {
path.remove(QString("metadata.desktop"));
}
} else if (!path.endsWith('/')) {
path.append('/');
}
if (path.isEmpty()) {
delete package;
package = 0;
q->setFailedToLaunch(true,
i18nc("Package file, name of the widget",
"Could not locate the %1 package required for the %2 widget.",
appletDescription.pluginName(), appletDescription.name()));
return;
}
package->setPath(path);
if (!package->isValid()) {
delete package;
package = 0;
q->setFailedToLaunch(true, i18nc("Package file, name of the widget",
"Could not open the %1 package required for the %2 widget.",
appletDescription.pluginName(), appletDescription.name()));
return;
}
// create the package and see if we have something real
//kDebug() << "trying for" << path;
// now we try and set up the script engine.
// it will be parented to this applet and so will get
// deleted when the applet does
script = Plasma::loadScriptEngine(api, q);
if (!script) {
delete package;
package = 0;
q->setFailedToLaunch(true,
i18nc("API or programming language the widget was written in, name of the widget",
"Could not create a %1 ScriptEngine for the %2 widget.",
api, appletDescription.name()));
}
}
// put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engine
void AppletPrivate::setupScriptSupport()
{
if (!package) {
return;
}
#ifndef NDEBUG
kDebug() << "setting up script support, package is in" << package->path()
<< ", main script is" << package->filePath("mainscript");
#endif
const QString translationsPath = package->filePath("translations");
if (!translationsPath.isEmpty()) {
KGlobal::dirs()->addResourceDir("locale", translationsPath);
KGlobal::locale()->insertCatalog(appletDescription.pluginName());
}
const QString xmlPath = package->filePath("mainconfigxml");
if (!xmlPath.isEmpty()) {
QFile file(xmlPath);
KConfigGroup config = q->config();
configLoader = new ConfigLoader(&config, &file);
QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged()));
}
if (!package->filePath("mainconfigui").isEmpty()) {
q->setHasConfigurationInterface(true);
}
}
QString AppletPrivate::globalName() const
{
if (!appletDescription.isValid()) {
return QString();
}
return appletDescription.service()->library();
}
QString AppletPrivate::instanceName()
{
if (!appletDescription.isValid()) {
return QString();
}
return appletDescription.service()->library() + QString::number(appletId);
}
void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c)
{
// Don't start up a timer if we're just starting up
// flushPendingConstraints will be called by Corona
if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) {
constraintsTimer.start(0, q);
}
if (c & Plasma::StartupCompletedConstraint) {
started = true;
}
pendingConstraints |= c;
}
void AppletPrivate::scheduleModificationNotification()
{
// modificationsTimer is not allocated until we get our notice of being started
if (modificationsTimer) {
// schedule a save
if (modificationsTimer->isActive()) {
modificationsTimer->stop();
}
modificationsTimer->start(1000, q);
}
}
KConfigGroup *AppletPrivate::mainConfigGroup()
{
if (mainConfig) {
return mainConfig;
}
bool newGroup = false;
if (isContainment) {
Corona *corona = qobject_cast<Corona*>(q->scene());
KConfigGroup containmentConfig;
//kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q;
if (corona) {
containmentConfig = KConfigGroup(corona->config(), "Containments");
} else {
containmentConfig = KConfigGroup(KGlobal::config(), "Containments");
}
if (package && !containmentConfig.hasGroup(QString::number(appletId))) {
newGroup = true;
}
mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId));
} else {
KConfigGroup appletConfig;
Containment *c = q->containment();
Applet *parentApplet = qobject_cast<Applet *>(q->parent());
if (parentApplet && parentApplet != static_cast<Applet *>(c)) {
// this applet is nested inside another applet! use it's config
// as the parent group in the config
appletConfig = parentApplet->config();
appletConfig = KConfigGroup(&appletConfig, "Applets");
} else if (c) {
// applet directly in a Containment, as usual
appletConfig = c->config();
appletConfig = KConfigGroup(&appletConfig, "Applets");
} else {
kWarning() << "requesting config for" << q->name() << "without a containment!";
appletConfig = KConfigGroup(KGlobal::config(), "Applets");
}
if (package && !appletConfig.hasGroup(QString::number(appletId))) {
newGroup = true;
}
mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId));
}
if (newGroup) {
//see if we have a default configuration in our package
const QString defaultConfigFile = package->filePath("defaultconfig");
if (!defaultConfigFile.isEmpty()) {
#ifndef NDEBUG
kDebug() << "copying default config: " << package->filePath("defaultconfig");
#endif
KConfigGroup defaultConfig(KSharedConfig::openConfig(defaultConfigFile)->group("Configuration"));
defaultConfig.copyTo(mainConfig);
}
}
return mainConfig;
}
QString AppletPrivate::visibleFailureText(const QString &reason)
{
QString text;
if (reason.isEmpty()) {
text = i18n("This object could not be created.");
} else {
text = i18n("This object could not be created for the following reason:<p><b>%1</b></p>", reason);
}
return text;
}
void AppletPrivate::themeChanged()
{
if (background) {
//do again the translucent background fallback
q->setBackgroundHints(backgroundHints);
qreal left;
qreal right;
qreal top;
qreal bottom;
background->getMargins(left, top, right, bottom);
q->setContentsMargins(left, right, top, bottom);
}
q->update();
}
void AppletPrivate::resetConfigurationObject()
{
// make sure mainConfigGroup exists in all cases
mainConfigGroup();
mainConfig->deleteGroup();
delete mainConfig;
mainConfig = 0;
Corona * corona = qobject_cast<Corona*>(q->scene());
if (corona) {
corona->requireConfigSync();
}
}
void AppletPrivate::handleDisappeared(AppletHandle *h)
{
if (h == handle.data()) {
h->detachApplet();
QGraphicsScene *scene = q->scene();
if (scene && h->scene() == scene) {
scene->removeItem(h);
}
h->deleteLater();
}
}
void ContainmentPrivate::checkRemoveAction()
{
q->enableAction("remove", q->immutability() == Mutable);
}
uint AppletPrivate::s_maxAppletId = 0;
int AppletPrivate::s_maxZValue = 0;
int AppletPrivate::s_minZValue = 0;
QSet<QString> AppletPrivate::s_customCategories;
} // Plasma namespace
-#include "moc_applet_p.cpp"
+#include "moc_applet.cpp"
+#include "private/moc_applet_p.cpp"
diff --git a/plasma/containment.cpp b/plasma/containment.cpp
index 02565dd424..5e389d10a9 100644
--- a/plasma/containment.cpp
+++ b/plasma/containment.cpp
@@ -1,2430 +1,2432 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Mテゥnard Alexis <darktears31@gmail.com>
* Copyright 2009 Chani Armitage <chani@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "containment.h"
#include "private/containment_p.h"
#include "config-plasma.h"
#include <QApplication>
#include <QClipboard>
#include <QFile>
#include <QGraphicsSceneContextMenuEvent>
#include <QGraphicsView>
#include <QMimeData>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QGraphicsLayout>
#include <QGraphicsLinearLayout>
#include <qtemporaryfile.h>
#include <kaction.h>
#include <kauthorized.h>
#include <kicon.h>
#include <kmenu.h>
#include <kmessagebox.h>
#include <kmimetype.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#include <kwindowsystem.h>
#ifndef PLASMA_NO_KIO
#include "kio/jobclasses.h" // for KIO::JobFlags
#include "kio/job.h"
#include "kio/scheduler.h"
#endif
#include "abstracttoolbox.h"
#include "animator.h"
#include "containmentactions.h"
#include "containmentactionspluginsconfig.h"
#include "corona.h"
#include "pluginloader.h"
#include "svg.h"
#include "wallpaper.h"
#include "remote/accessappletjob.h"
#include "remote/accessmanager.h"
#include "private/applet_p.h"
#include "private/containmentactionspluginsconfig_p.h"
#include "private/wallpaper_p.h"
#include "plasma/plasma.h"
namespace Plasma
{
bool ContainmentPrivate::s_positioningPanels = false;
QHash<QString, ContainmentActions*> ContainmentPrivate::globalActionPlugins;
static const char defaultWallpaper[] = "image";
static const char defaultWallpaperMode[] = "SingleImage";
Containment::StyleOption::StyleOption()
: QStyleOptionGraphicsItem(),
view(0)
{
version = Version;
type = Type;
}
Containment::StyleOption::StyleOption(const Containment::StyleOption & other)
: QStyleOptionGraphicsItem(other),
view(other.view)
{
version = Version;
type = Type;
}
Containment::StyleOption::StyleOption(const QStyleOptionGraphicsItem &other)
: QStyleOptionGraphicsItem(other),
view(0)
{
version = Version;
type = Type;
}
Containment::Containment(QGraphicsItem *parent,
const QString &serviceId,
uint containmentId)
: Applet(parent, serviceId, containmentId),
d(new ContainmentPrivate(this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
setPos(0, 0);
setBackgroundHints(NoBackground);
setContainmentType(CustomContainment);
setHasConfigurationInterface(false);
}
Containment::Containment(QObject *parent, const QVariantList &args)
: Applet(parent, args),
d(new ContainmentPrivate(this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
setPos(0, 0);
setBackgroundHints(NoBackground);
setHasConfigurationInterface(false);
}
Containment::Containment(const QString &packagePath, uint appletId, const QVariantList &args)
: Applet(packagePath, appletId, args),
d(new ContainmentPrivate(this))
{
// WARNING: do not access config() OR globalConfig() in this method!
// that requires a scene, which is not available at this point
setPos(0, 0);
setBackgroundHints(NoBackground);
setHasConfigurationInterface(false);
}
Containment::~Containment()
{
delete d;
// Applet touches our dptr if we are a containment and is the superclass (think of dtors)
// so we reset this as we exit the building
Applet::d->isContainment = false;
}
void Containment::init()
{
Applet::init();
if (!isContainment()) {
return;
}
setCacheMode(NoCache);
setFlag(QGraphicsItem::ItemIsMovable, false);
setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
setAcceptDrops(true);
setAcceptsHoverEvents(true);
if (d->type == NoContainmentType) {
setContainmentType(DesktopContainment);
}
//connect actions
ContainmentPrivate::addDefaultActions(d->actions(), this);
bool unlocked = immutability() == Mutable;
//fix the text of the actions that need name()
//btw, do we really want to use name() when it's a desktopcontainment?
QAction *closeApplet = action("remove");
if (closeApplet) {
closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", name()));
}
QAction *configAction = action("configure");
if (configAction) {
configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", name()));
}
QAction *appletBrowserAction = action("add widgets");
if (appletBrowserAction) {
appletBrowserAction->setVisible(unlocked);
appletBrowserAction->setEnabled(unlocked);
connect(appletBrowserAction, SIGNAL(triggered()), this, SLOT(triggerShowAddWidgets()));
}
QAction *act = action("next applet");
if (act) {
connect(act, SIGNAL(triggered()), this, SLOT(focusNextApplet()));
}
act = action("previous applet");
if (act) {
connect(act, SIGNAL(triggered()), this, SLOT(focusPreviousApplet()));
}
if (immutability() != SystemImmutable && corona()) {
QAction *lockDesktopAction = corona()->action("lock widgets");
//keep a pointer so nobody notices it moved to corona
if (lockDesktopAction) {
d->actions()->addAction("lock widgets", lockDesktopAction);
}
}
if (d->type != PanelContainment && d->type != CustomPanelContainment) {
if (corona()) {
//FIXME this is just here because of the darn keyboard shortcut :/
act = corona()->action("manage activities");
if (act) {
d->actions()->addAction("manage activities", act);
}
//a stupid hack to make this one's keyboard shortcut work
act = corona()->action("configure shortcuts");
if (act) {
d->actions()->addAction("configure shortcuts", act);
}
}
if (d->type == DesktopContainment) {
addToolBoxAction(action("add widgets"));
//TODO: do we need some way to allow this be overridden?
// it's always available because shells rely on this
// to offer their own custom configuration as well
QAction *configureContainment = action("configure");
if (configureContainment) {
addToolBoxAction(configureContainment);
}
}
}
}
void ContainmentPrivate::addDefaultActions(KActionCollection *actions, Containment *c)
{
actions->setConfigGroup("Shortcuts-Containment");
//adjust applet actions
KAction *appAction = qobject_cast<KAction*>(actions->action("remove"));
appAction->setShortcut(KShortcut("alt+d, alt+r"));
if (c && c->d->isPanelContainment()) {
appAction->setText(i18n("Remove this Panel"));
} else {
appAction->setText(i18n("Remove this Activity"));
}
appAction = qobject_cast<KAction*>(actions->action("configure"));
if (appAction) {
appAction->setShortcut(KShortcut("alt+d, alt+s"));
appAction->setText(i18n("Activity Settings"));
}
//add our own actions
KAction *appletBrowserAction = actions->addAction("add widgets");
appletBrowserAction->setAutoRepeat(false);
appletBrowserAction->setText(i18n("Add Widgets..."));
appletBrowserAction->setIcon(KIcon("list-add"));
appletBrowserAction->setShortcut(KShortcut("alt+d, a"));
appletBrowserAction->setData(AbstractToolBox::AddTool);
KAction *action = actions->addAction("next applet");
action->setText(i18n("Next Widget"));
//no icon
action->setShortcut(KShortcut("alt+d, n"));
action->setData(AbstractToolBox::ControlTool);
action = actions->addAction("previous applet");
action->setText(i18n("Previous Widget"));
//no icon
action->setShortcut(KShortcut("alt+d, p"));
action->setData(AbstractToolBox::ControlTool);
}
// helper function for sorting the list of applets
bool appletConfigLessThan(const KConfigGroup &c1, const KConfigGroup &c2)
{
QPointF p1 = c1.readEntry("geometry", QRectF()).topLeft();
QPointF p2 = c2.readEntry("geometry", QRectF()).topLeft();
if (!qFuzzyCompare(p1.x(), p2.x())) {
if (QApplication::layoutDirection() == Qt::RightToLeft) {
return p1.x() > p2.x();
}
return p1.x() < p2.x();
}
return qFuzzyCompare(p1.y(), p2.y()) || p1.y() < p2.y();
}
void Containment::restore(KConfigGroup &group)
{
/*
#ifndef NDEBUG
kDebug() << "!!!!!!!!!!!!initConstraints" << group.name() << d->type;
kDebug() << " location:" << group.readEntry("location", (int)d->location);
kDebug() << " geom:" << group.readEntry("geometry", geometry());
kDebug() << " formfactor:" << group.readEntry("formfactor", (int)d->formFactor);
kDebug() << " screen:" << group.readEntry("screen", d->screen);
#endif
*/
if (!isContainment()) {
Applet::restore(group);
return;
}
QRectF geo = group.readEntry("geometry", geometry());
//override max/min
//this ensures panels are set to their saved size even when they have max & min set to prevent
//resizing
if (geo.size() != geo.size().boundedTo(maximumSize())) {
setMaximumSize(maximumSize().expandedTo(geo.size()));
}
if (geo.size() != geo.size().expandedTo(minimumSize())) {
setMinimumSize(minimumSize().boundedTo(geo.size()));
}
resize(geo.size());
//are we an offscreen containment?
if (containmentType() != PanelContainment && containmentType() != CustomPanelContainment && geo.right() < 0) {
corona()->addOffscreenWidget(this);
}
setLocation((Plasma::Location)group.readEntry("location", (int)d->location));
setFormFactor((Plasma::FormFactor)group.readEntry("formfactor", (int)d->formFactor));
//kDebug() << "setScreen from restore";
d->lastScreen = group.readEntry("lastScreen", d->lastScreen);
d->lastDesktop = group.readEntry("lastDesktop", d->lastDesktop);
d->setScreen(group.readEntry("screen", d->screen), group.readEntry("desktop", d->desktop), false);
d->activityId = group.readEntry("activityId", QString());
flushPendingConstraintsEvents();
restoreContents(group);
setImmutability((ImmutabilityType)group.readEntry("immutability", (int)Mutable));
setWallpaper(group.readEntry("wallpaperplugin", defaultWallpaper),
group.readEntry("wallpaperpluginmode", defaultWallpaperMode));
if (d->toolBox) {
d->toolBox.data()->restore(group);
}
KConfigGroup cfg;
if (containmentType() == PanelContainment || containmentType() == CustomPanelContainment) {
//don't let global desktop actions conflict with panels
//this also prevents panels from sharing config with each other
//but the panels aren't configurable anyways, and I doubt that'll change.
d->containmentActionsSource = ContainmentPrivate::Local;
cfg = KConfigGroup(&group, "ActionPlugins");
} else {
const QString source = group.readEntry("ActionPluginsSource", QString());
if (source == "Global") {
cfg = KConfigGroup(corona()->config(), "ActionPlugins");
d->containmentActionsSource = ContainmentPrivate::Global;
} else if (source == "Activity") {
cfg = KConfigGroup(corona()->config(), "Activities");
cfg = KConfigGroup(&cfg, d->activityId);
cfg = KConfigGroup(&cfg, "ActionPlugins");
d->containmentActionsSource = ContainmentPrivate::Activity;
} else if (source == "Local") {
cfg = group;
d->containmentActionsSource = ContainmentPrivate::Local;
} else {
//default to global
//but, if there is no global config, try copying it from local.
cfg = KConfigGroup(corona()->config(), "ActionPlugins");
if (!cfg.exists()) {
cfg = KConfigGroup(&group, "ActionPlugins");
}
d->containmentActionsSource = ContainmentPrivate::Global;
group.writeEntry("ActionPluginsSource", "Global");
}
}
//kDebug() << cfg.keyList();
if (cfg.exists()) {
foreach (const QString &key, cfg.keyList()) {
//kDebug() << "loading" << key;
setContainmentActions(key, cfg.readEntry(key, QString()));
}
} else { //shell defaults
ContainmentActionsPluginsConfig conf = corona()->containmentActionsDefaults(d->type);
//steal the data directly, for efficiency
QHash<QString,QString> defaults = conf.d->plugins;
for (QHash<QString,QString>::const_iterator it = defaults.constBegin(),
end = defaults.constEnd(); it != end; ++it) {
setContainmentActions(it.key(), it.value());
}
}
/*
#ifndef NDEBUG
kDebug() << "Containment" << id() <<
#endif
"screen" << screen() <<
"geometry is" << geometry() <<
"wallpaper" << ((d->wallpaper) ? d->wallpaper->pluginName() : QString()) <<
"wallpaper mode" << wallpaperMode() <<
"config entries" << group.entryMap();
*/
}
void Containment::save(KConfigGroup &g) const
{
if (Applet::d->transient) {
return;
}
KConfigGroup group = g;
if (!group.isValid()) {
group = config();
}
// locking is saved in Applet::save
Applet::save(group);
if (!isContainment()) {
return;
}
group.writeEntry("screen", d->screen);
group.writeEntry("lastScreen", d->lastScreen);
group.writeEntry("desktop", d->desktop);
group.writeEntry("lastDesktop", d->lastDesktop);
group.writeEntry("formfactor", (int)d->formFactor);
group.writeEntry("location", (int)d->location);
group.writeEntry("activityId", d->activityId);
if (d->toolBox) {
d->toolBox.data()->save(group);
}
if (d->wallpaper) {
group.writeEntry("wallpaperplugin", d->wallpaper->pluginName());
group.writeEntry("wallpaperpluginmode", d->wallpaper->renderingMode().name());
if (d->wallpaper->isInitialized()) {
KConfigGroup wallpaperConfig(&group, "Wallpaper");
wallpaperConfig = KConfigGroup(&wallpaperConfig, d->wallpaper->pluginName());
d->wallpaper->save(wallpaperConfig);
}
}
saveContents(group);
}
void Containment::saveContents(KConfigGroup &group) const
{
KConfigGroup applets(&group, "Applets");
foreach (const Applet *applet, d->applets) {
KConfigGroup appletConfig(&applets, QString::number(applet->id()));
applet->save(appletConfig);
}
}
void ContainmentPrivate::initApplets()
{
foreach (Applet *applet, applets) {
applet->restore(*applet->d->mainConfigGroup());
applet->init();
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Applet" << applet->name();
#endif
}
q->flushPendingConstraintsEvents();
foreach (Applet *applet, applets) {
applet->flushPendingConstraintsEvents();
}
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Containment's applets initialized" << q->name();
#endif
}
void Containment::restoreContents(KConfigGroup &group)
{
KConfigGroup applets(&group, "Applets");
// Sort the applet configs in order of geometry to ensure that applets
// are added from left to right or top to bottom for a panel containment
QList<KConfigGroup> appletConfigs;
foreach (const QString &appletGroup, applets.groupList()) {
//kDebug() << "reading from applet group" << appletGroup;
KConfigGroup appletConfig(&applets, appletGroup);
appletConfigs.append(appletConfig);
}
qStableSort(appletConfigs.begin(), appletConfigs.end(), appletConfigLessThan);
QMutableListIterator<KConfigGroup> it(appletConfigs);
while (it.hasNext()) {
KConfigGroup &appletConfig = it.next();
int appId = appletConfig.name().toUInt();
QString plugin = appletConfig.readEntry("plugin", QString());
if (plugin.isEmpty()) {
continue;
}
d->addApplet(plugin, QVariantList(), appletConfig.readEntry("geometry", QRectF()), appId, true);
}
}
Containment::Type Containment::containmentType() const
{
return d->type;
}
void Containment::setContainmentType(Containment::Type type)
{
if (d->type == type) {
return;
}
delete d->toolBox.data();
d->type = type;
d->checkContainmentFurniture();
}
void ContainmentPrivate::checkContainmentFurniture()
{
if (q->isContainment() &&
(type == Containment::DesktopContainment || type == Containment::PanelContainment)) {
createToolBox();
}
}
Corona *Containment::corona() const
{
return qobject_cast<Corona*>(scene());
}
void Containment::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
event->ignore();
if (d->wallpaper && d->wallpaper->isInitialized()) {
QGraphicsItem *item = scene()->itemAt(event->scenePos());
if (item == this) {
d->wallpaper->mouseMoveEvent(event);
}
}
if (!event->isAccepted()) {
event->accept();
Applet::mouseMoveEvent(event);
}
}
void Containment::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
event->ignore();
if (d->appletAt(event->scenePos())) {
return; //no unexpected click-throughs
}
if (d->wallpaper && d->wallpaper->isInitialized() && !event->isAccepted()) {
d->wallpaper->mousePressEvent(event);
}
if (event->isAccepted()) {
setFocus(Qt::MouseFocusReason);
} else if (event->button() == Qt::RightButton && event->modifiers() == Qt::NoModifier) {
// we'll catch this in the context menu even
Applet::mousePressEvent(event);
} else {
QString trigger = ContainmentActions::eventToString(event);
if (d->prepareContainmentActions(trigger, event->screenPos())) {
d->actionPlugins()->value(trigger)->contextEvent(event);
}
if (!event->isAccepted()) {
Applet::mousePressEvent(event);
}
}
}
void Containment::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
event->ignore();
if (d->appletAt(event->scenePos())) {
return; //no unexpected click-throughs
}
QString trigger = ContainmentActions::eventToString(event);
if (d->wallpaper && d->wallpaper->isInitialized()) {
d->wallpaper->mouseReleaseEvent(event);
}
if (!event->isAccepted() && isContainment()) {
if (d->prepareContainmentActions(trigger, event->screenPos())) {
d->actionPlugins()->value(trigger)->contextEvent(event);
}
event->accept();
Applet::mouseReleaseEvent(event);
}
}
void Containment::showDropZone(const QPoint pos)
{
Q_UNUSED(pos)
//Base implementation does nothing, don't put code here
}
void Containment::showContextMenu(const QPointF &containmentPos, const QPoint &screenPos)
{
//kDebug() << containmentPos << screenPos;
QGraphicsSceneContextMenuEvent gvevent;
gvevent.setScreenPos(screenPos);
gvevent.setScenePos(mapToScene(containmentPos));
gvevent.setPos(containmentPos);
gvevent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
gvevent.setWidget(view());
contextMenuEvent(&gvevent);
}
void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
if (!isContainment() || !KAuthorized::authorizeKAction("plasma/containment_context_menu")) {
Applet::contextMenuEvent(event);
return;
}
KMenu desktopMenu;
Applet *applet = d->appletAt(event->scenePos());
//kDebug() << "context menu event " << (QObject*)applet;
if (applet) {
d->addAppletActions(desktopMenu, applet, event);
} else {
d->addContainmentActions(desktopMenu, event);
}
//kDebug() << "executing at" << screenPos;
QMenu *menu = &desktopMenu;
//kDebug() << "showing menu, actions" << desktopMenu.actions().size() << desktopMenu.actions().first()->menu();
if (desktopMenu.actions().size() == 1 && desktopMenu.actions().first()->menu()) {
// we have a menu with a single top level menu; just show that top level menu instad.
menu = desktopMenu.actions().first()->menu();
}
if (!menu->isEmpty()) {
QPoint pos = event->screenPos();
if (applet && d->isPanelContainment()) {
menu->adjustSize();
pos = applet->popupPosition(menu->size());
if (event->reason() == QGraphicsSceneContextMenuEvent::Mouse) {
// if the menu pops up way away from the mouse press, then move it
// to the mouse press
if (d->formFactor == Vertical) {
if (pos.y() + menu->height() < event->screenPos().y()) {
pos.setY(event->screenPos().y());
}
} else if (d->formFactor == Horizontal) {
if (pos.x() + menu->width() < event->screenPos().x()) {
pos.setX(event->screenPos().x());
}
}
}
}
menu->exec(pos);
event->accept();
} else {
Applet::contextMenuEvent(event);
}
}
void ContainmentPrivate::addContainmentActions(KMenu &desktopMenu, QEvent *event)
{
if (static_cast<Corona*>(q->scene())->immutability() != Mutable &&
!KAuthorized::authorizeKAction("plasma/containment_actions")) {
//kDebug() << "immutability";
return;
}
const QString trigger = ContainmentActions::eventToString(event);
prepareContainmentActions(trigger, QPoint(), &desktopMenu);
}
void ContainmentPrivate::addAppletActions(KMenu &desktopMenu, Applet *applet, QEvent *event)
{
foreach (QAction *action, applet->contextualActions()) {
if (action) {
desktopMenu.addAction(action);
}
}
if (!applet->d->failed) {
QAction *configureApplet = applet->d->actions->action("configure");
if (configureApplet && configureApplet->isEnabled()) {
desktopMenu.addAction(configureApplet);
}
QAction *runAssociatedApplication = applet->d->actions->action("run associated application");
if (runAssociatedApplication && runAssociatedApplication->isEnabled()) {
desktopMenu.addAction(runAssociatedApplication);
}
}
KMenu *containmentMenu = new KMenu(i18nc("%1 is the name of the containment", "%1 Options", q->name()), &desktopMenu);
addContainmentActions(*containmentMenu, event);
if (!containmentMenu->isEmpty()) {
int enabled = 0;
//count number of real actions
QListIterator<QAction *> actionsIt(containmentMenu->actions());
while (enabled < 3 && actionsIt.hasNext()) {
QAction *action = actionsIt.next();
if (action->isVisible() && !action->isSeparator()) {
++enabled;
}
}
if (enabled) {
//if there is only one, don't create a submenu
if (enabled < 2) {
foreach (QAction *action, containmentMenu->actions()) {
if (action->isVisible() && !action->isSeparator()) {
desktopMenu.addAction(action);
}
}
} else {
desktopMenu.addMenu(containmentMenu);
}
}
}
if (q->immutability() == Mutable) {
QAction *closeApplet = applet->d->actions->action("remove");
//kDebug() << "checking for removal" << closeApplet;
if (closeApplet) {
if (!desktopMenu.isEmpty()) {
desktopMenu.addSeparator();
}
//kDebug() << "adding close action" << closeApplet->isEnabled() << closeApplet->isVisible();
desktopMenu.addAction(closeApplet);
}
}
}
Applet* ContainmentPrivate::appletAt(const QPointF &point)
{
Applet *applet = 0;
QGraphicsItem *item = q->scene()->itemAt(point);
if (item == q) {
item = 0;
}
while (item) {
if (item->isWidget()) {
applet = qobject_cast<Applet*>(static_cast<QGraphicsWidget*>(item));
if (applet) {
if (applet->isContainment()) {
applet = 0;
}
break;
}
}
AppletHandle *handle = dynamic_cast<AppletHandle*>(item);
if (handle) {
//pretend it was on the applet
applet = handle->applet();
break;
}
item = item->parentItem();
}
return applet;
}
void Containment::setFormFactor(FormFactor formFactor)
{
if (d->formFactor == formFactor) {
return;
}
//kDebug() << "switching FF to " << formFactor;
d->formFactor = formFactor;
if (isContainment() &&
(d->type == PanelContainment || d->type == CustomPanelContainment)) {
// we are a panel and we have chaged our orientation
d->positionPanel(true);
}
if (d->toolBox) {
d->toolBox.data()->reposition();
}
updateConstraints(Plasma::FormFactorConstraint);
KConfigGroup c = config();
c.writeEntry("formfactor", (int)formFactor);
emit configNeedsSaving();
}
void Containment::setLocation(Location location)
{
if (d->location == location) {
return;
}
bool emitGeomChange = false;
if ((location == TopEdge || location == BottomEdge) &&
(d->location == TopEdge || d->location == BottomEdge)) {
emitGeomChange = true;
}
if ((location == RightEdge || location == LeftEdge) &&
(d->location == RightEdge || d->location == LeftEdge)) {
emitGeomChange = true;
}
d->location = location;
foreach (Applet *applet, d->applets) {
applet->updateConstraints(Plasma::LocationConstraint);
}
if (emitGeomChange) {
// our geometry on the scene will not actually change,
// but for the purposes of views it has
emit geometryChanged();
}
updateConstraints(Plasma::LocationConstraint);
KConfigGroup c = config();
c.writeEntry("location", (int)location);
emit configNeedsSaving();
}
void Containment::addSiblingContainment()
{
emit addSiblingContainment(this);
}
void Containment::clearApplets()
{
foreach (Applet *applet, d->applets) {
applet->d->cleanUpAndDelete();
}
d->applets.clear();
}
Applet *Containment::addApplet(const QString &name, const QVariantList &args,
const QRectF &appletGeometry)
{
return d->addApplet(name, args, appletGeometry);
}
void Containment::addApplet(Applet *applet, const QPointF &pos, bool delayInit)
{
if (!isContainment() || (!delayInit && immutability() != Mutable)) {
return;
}
if (!applet) {
#ifndef NDEBUG
kDebug() << "adding null applet!?!";
#endif
return;
}
if (d->applets.contains(applet)) {
#ifndef NDEBUG
kDebug() << "already have this applet!";
#endif
}
Containment *currentContainment = applet->containment();
if (d->type == PanelContainment) {
//panels don't want backgrounds, which is important when setting geometry
setBackgroundHints(NoBackground);
}
if (currentContainment && currentContainment != this) {
emit currentContainment->appletRemoved(applet);
if (currentContainment->d->focusedApplet == applet) {
currentContainment->d->focusedApplet = 0;
}
disconnect(applet, 0, currentContainment, 0);
KConfigGroup oldConfig = applet->config();
currentContainment->d->applets.removeAll(applet);
applet->setParentItem(this);
applet->setParent(this);
// now move the old config to the new location
//FIXME: this doesn't seem to get the actual main config group containing plugin=, etc
KConfigGroup c = config().group("Applets").group(QString::number(applet->id()));
oldConfig.reparent(&c);
applet->d->resetConfigurationObject();
disconnect(applet, SIGNAL(activate()), currentContainment, SIGNAL(activate()));
} else {
applet->setParentItem(this);
applet->setParent(this);
}
d->applets << applet;
connect(applet, SIGNAL(configNeedsSaving()), this, SIGNAL(configNeedsSaving()));
connect(applet, SIGNAL(releaseVisualFocus()), this, SIGNAL(releaseVisualFocus()));
connect(applet, SIGNAL(appletDestroyed(Plasma::Applet*)), this, SLOT(appletDestroyed(Plasma::Applet*)));
connect(applet, SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(checkStatus(Plasma::ItemStatus)));
connect(applet, SIGNAL(activate()), this, SIGNAL(activate()));
if (pos != QPointF(-1, -1)) {
applet->setPos(pos);
}
if (!delayInit && !currentContainment) {
applet->restore(*applet->d->mainConfigGroup());
applet->init();
//FIXME: an on-appear animation would be nice to have again
d->appletAppeared(applet);
}
applet->setFlag(QGraphicsItem::ItemIsMovable, true);
applet->updateConstraints(Plasma::AllConstraints);
if (!delayInit) {
applet->flushPendingConstraintsEvents();
}
emit appletAdded(applet, pos);
if (!currentContainment) {
applet->updateConstraints(Plasma::StartupCompletedConstraint);
if (!delayInit) {
applet->flushPendingConstraintsEvents();
}
}
if (!delayInit) {
applet->d->scheduleModificationNotification();
}
}
Applet::List Containment::applets() const
{
return d->applets;
}
void Containment::setScreen(int newScreen, int newDesktop)
{
d->setScreen(newScreen, newDesktop);
}
void ContainmentPrivate::setScreen(int newScreen, int newDesktop, bool preventInvalidDesktops)
{
// What we want to do in here is:
// * claim the screen as our own
// * signal whatever may be watching this containment about the switch
// * if we are a full screen containment, then:
// * resize to match the screen if we're that kind of containment
// * kick other full-screen containments off this screen
// * if we had a screen, then give our screen to the containment
// we kick out
//
// a screen of -1 means no associated screen.
Corona *corona = q->corona();
Q_ASSERT(corona);
//if it's an offscreen widget, don't allow to claim a screen, after all it's *off*screen
if (corona->offscreenWidgets().contains(q)) {
return;
}
int numScreens = corona->numScreens();
if (newScreen < -1) {
newScreen = -1;
}
// -1 == All desktops
if (newDesktop < -1 || (preventInvalidDesktops && newDesktop > KWindowSystem::numberOfDesktops() - 1)) {
newDesktop = -1;
}
//kDebug() << activity() << "setting screen to " << newScreen << newDesktop << "and type is" << type;
Containment *swapScreensWith(0);
const bool isDesktopContainment = type == Containment::DesktopContainment ||
type == Containment::CustomContainment;
if (isDesktopContainment) {
// we want to listen to changes in work area if our screen changes
if (toolBox) {
if (screen < 0 && newScreen > -1) {
QObject::connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), toolBox.data(), SLOT(reposition()), Qt::UniqueConnection);
} else if (newScreen < 0) {
QObject::disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), toolBox.data(), SLOT(reposition()));
}
}
if (newScreen > -1) {
// sanity check to make sure someone else doesn't have this screen already!
Containment *currently = corona->containmentForScreen(newScreen, newDesktop);
if (currently && currently != q) {
#ifndef NDEBUG
kDebug() << "currently is on screen" << currently->screen()
<< "desktop" << currently->desktop()
<< "and is" << currently->activity()
<< (QObject*)currently << "i'm" << (QObject*)q;
#endif
currently->setScreen(-1, currently->desktop());
swapScreensWith = currently;
}
}
}
if (newScreen < numScreens && newScreen > -1 && isDesktopContainment) {
q->resize(corona->screenGeometry(newScreen).size());
}
int oldDesktop = desktop;
desktop = newDesktop;
int oldScreen = screen;
screen = newScreen;
q->updateConstraints(Plasma::ScreenConstraint);
if (oldScreen != newScreen || oldDesktop != newDesktop) {
/*
#ifndef NDEBUG
kDebug() << "going to signal change for" << q
#endif
<< ", old screen & desktop:" << oldScreen << oldDesktop
<< ", new:" << screen << desktop;
*/
KConfigGroup c = q->config();
c.writeEntry("screen", screen);
c.writeEntry("desktop", desktop);
if (newScreen != -1) {
lastScreen = newScreen;
lastDesktop = newDesktop;
c.writeEntry("lastScreen", lastScreen);
c.writeEntry("lastDesktop", lastDesktop);
}
emit q->configNeedsSaving();
emit q->screenChanged(oldScreen, newScreen, q);
}
if (swapScreensWith) {
//kDebug() << "setScreen due to swap, part 2";
swapScreensWith->setScreen(oldScreen, oldDesktop);
}
checkRemoveAction();
if (newScreen >= 0) {
emit q->activate();
}
}
int Containment::screen() const
{
return d->screen;
}
int Containment::lastScreen() const
{
return d->lastScreen;
}
int Containment::desktop() const
{
return d->desktop;
}
int Containment::lastDesktop() const
{
return d->lastDesktop;
}
KPluginInfo::List Containment::listContainments(const QString &category,
const QString &parentApp)
{
return listContainmentsOfType(QString(), category, parentApp);
}
KPluginInfo::List Containment::listContainmentsOfType(const QString &type,
const QString &category,
const QString &parentApp)
{
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
if (!type.isEmpty()) {
if (!constraint.isEmpty()) {
constraint.append(" and ");
}
constraint.append("'").append(type).append("' ~in [X-Plasma-ContainmentCategories]");
}
if (!category.isEmpty()) {
if (!constraint.isEmpty()) {
constraint.append(" and ");
}
constraint.append("[X-KDE-PluginInfo-Category] == '").append(category).append("'");
if (category == "Miscellaneous") {
constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
}
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
//kDebug() << "constraint was" << constraint << "which got us" << offers.count() << "matches";
return KPluginInfo::fromServices(offers);
}
KPluginInfo::List Containment::listContainmentsForMimeType(const QString &mimeType)
{
const QString constraint = QString("'%1' in [X-Plasma-DropMimeTypes]").arg(mimeType);
//kDebug() << mimeType << constraint;
const KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
return KPluginInfo::fromServices(offers);
}
QStringList Containment::listContainmentTypes()
{
KPluginInfo::List containmentInfos = listContainments();
QSet<QString> types;
foreach (const KPluginInfo &containmentInfo, containmentInfos) {
QStringList theseTypes = containmentInfo.service()->property("X-Plasma-ContainmentCategories").toStringList();
foreach (const QString &type, theseTypes) {
types.insert(type);
}
}
return types.toList();
}
void Containment::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
//kDebug() << immutability() << Mutable << (immutability() == Mutable);
event->setAccepted(immutability() == Mutable &&
(event->mimeData()->hasFormat(static_cast<Corona*>(scene())->appletMimeType()) ||
KUrl::List::canDecode(event->mimeData())));
if (!event->isAccepted()) {
// check to see if we have an applet that accepts the format.
QStringList formats = event->mimeData()->formats();
foreach (const QString &format, formats) {
KPluginInfo::List appletList = Applet::listAppletInfoForMimeType(format);
if (!appletList.isEmpty()) {
event->setAccepted(true);
break;
}
}
if (!event->isAccepted()) {
foreach (const QString &format, formats) {
KPluginInfo::List wallpaperList = Wallpaper::listWallpaperInfoForMimetype(format);
if (!wallpaperList.isEmpty()) {
event->setAccepted(true);
break;
}
}
}
}
if (event->isAccepted()) {
if (d->dropZoneStarted) {
showDropZone(event->pos().toPoint());
} else {
if (!d->showDropZoneDelayTimer) {
d->showDropZoneDelayTimer = new QTimer(this);
d->showDropZoneDelayTimer->setInterval(300);
d->showDropZoneDelayTimer->setSingleShot(true);
connect(d->showDropZoneDelayTimer, SIGNAL(timeout()), this, SLOT(showDropZoneDelayed()));
}
d->dropPoints.insert(0, event->pos());
d->showDropZoneDelayTimer->start();
}
}
}
void Containment::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
//kDebug() << event->pos() << size().height() << size().width();
if (d->showDropZoneDelayTimer) {
d->showDropZoneDelayTimer->stop();
}
if (event->pos().y() < 1 || event->pos().y() > size().height() ||
event->pos().x() < 1 || event->pos().x() > size().width()) {
showDropZone(QPoint());
d->dropZoneStarted = false;
}
}
void ContainmentPrivate::showDropZoneDelayed()
{
dropZoneStarted = true;
q->showDropZone(dropPoints.value(0).toPoint());
dropPoints.remove(0);
}
void Containment::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
QGraphicsItem *item = scene()->itemAt(event->scenePos());
event->setAccepted(item == this || item == d->toolBox.data() || !item);
//kDebug() << event->isAccepted() << d->showDropZoneDelayTimer->isActive();
if (!event->isAccepted()) {
if (d->showDropZoneDelayTimer) {
d->showDropZoneDelayTimer->stop();
}
} else if (!d->showDropZoneDelayTimer->isActive() && immutability() == Plasma::Mutable) {
showDropZone(event->pos().toPoint());
}
}
void Containment::dropEvent(QGraphicsSceneDragDropEvent *event)
{
if (isContainment()) {
d->dropData(event->scenePos(), event->screenPos(), event);
} else {
Applet::dropEvent(event);
}
}
void ContainmentPrivate::dropData(QPointF scenePos, QPoint screenPos, QGraphicsSceneDragDropEvent *dropEvent)
{
if (q->immutability() != Mutable) {
return;
}
QPointF pos = q->mapFromScene(scenePos);
const QMimeData *mimeData = 0;
if (dropEvent) {
mimeData = dropEvent->mimeData();
} else {
QClipboard *clipboard = QApplication::clipboard();
mimeData = clipboard->mimeData(QClipboard::Selection);
//TODO if that's not supported (ie non-linux) should we try clipboard instead of selection?
}
if (!mimeData) {
//Selection is either empty or not supported on this OS
#ifndef NDEBUG
kDebug() << "no mime data";
#endif
return;
}
//kDebug() << event->mimeData()->text();
QString appletMimetype(q->corona() ? q->corona()->appletMimeType() : QString());
if (!appletMimetype.isEmpty() && mimeData->hasFormat(appletMimetype)) {
QString data = mimeData->data(appletMimetype);
const QStringList appletNames = data.split('\n', QString::SkipEmptyParts);
foreach (const QString &appletName, appletNames) {
//kDebug() << "doing" << appletName;
QRectF geom(pos, QSize(0, 0));
q->addApplet(appletName, QVariantList(), geom);
}
if (dropEvent) {
dropEvent->acceptProposedAction();
}
} else if (KUrl::List::canDecode(mimeData)) {
//TODO: collect the mimeTypes of available script engines and offer
// to create widgets out of the matching URLs, if any
const KUrl::List urls = KUrl::List::fromMimeData(mimeData);
foreach (const KUrl &url, urls) {
if (AccessManager::supportedProtocols().contains(url.scheme())) {
AccessAppletJob *job = AccessManager::self()->accessRemoteApplet(url);
if (dropEvent) {
dropPoints[job] = dropEvent->pos();
} else {
dropPoints[job] = scenePos;
}
QObject::connect(AccessManager::self(), SIGNAL(finished(Plasma::AccessAppletJob*)),
q, SLOT(remoteAppletReady(Plasma::AccessAppletJob*)));
}
#ifndef PLASMA_NO_KIO
else {
KMimeType::Ptr mime = KMimeType::findByUrl(url);
QString mimeName = mime->name();
QRectF geom(pos, QSize());
QVariantList args;
args << url.url();
#ifndef NDEBUG
kDebug() << "can decode" << mimeName << args;
#endif
// It may be a directory or a file, let's stat
KIO::JobFlags flags = KIO::HideProgressInfo;
KIO::MimetypeJob *job = KIO::mimetype(url, flags);
if (dropEvent) {
dropPoints[job] = dropEvent->pos();
} else {
dropPoints[job] = scenePos;
}
QObject::connect(job, SIGNAL(result(KJob*)), q, SLOT(dropJobResult(KJob*)));
QObject::connect(job, SIGNAL(mimeType(KIO::Job *, const QString&)),
q, SLOT(mimeTypeRetrieved(KIO::Job *, const QString&)));
KMenu *choices = new KMenu("Content dropped");
choices->addAction(KIcon("process-working"), i18n("Fetching file type..."));
if (dropEvent) {
choices->popup(dropEvent->screenPos());
} else {
choices->popup(screenPos);
}
dropMenus[job] = choices;
}
#endif
}
if (dropEvent) {
dropEvent->acceptProposedAction();
}
} else {
QStringList formats = mimeData->formats();
QHash<QString, KPluginInfo> seenPlugins;
QHash<QString, QString> pluginFormats;
foreach (const QString &format, formats) {
KPluginInfo::List plugins = Applet::listAppletInfoForMimeType(format);
foreach (const KPluginInfo &plugin, plugins) {
if (seenPlugins.contains(plugin.pluginName())) {
continue;
}
seenPlugins.insert(plugin.pluginName(), plugin);
pluginFormats.insert(plugin.pluginName(), format);
}
}
//kDebug() << "Mimetype ..." << formats << seenPlugins.keys() << pluginFormats.values();
QString selectedPlugin;
if (seenPlugins.isEmpty()) {
// do nothing
} else if (seenPlugins.count() == 1) {
selectedPlugin = seenPlugins.constBegin().key();
} else {
KMenu choices;
QHash<QAction *, QString> actionsToPlugins;
foreach (const KPluginInfo &info, seenPlugins) {
QAction *action;
if (!info.icon().isEmpty()) {
action = choices.addAction(KIcon(info.icon()), info.name());
} else {
action = choices.addAction(info.name());
}
actionsToPlugins.insert(action, info.pluginName());
}
QAction *choice = choices.exec(screenPos);
if (choice) {
selectedPlugin = actionsToPlugins[choice];
}
}
if (!selectedPlugin.isEmpty()) {
if (!dropEvent) {
// since we may have entered an event loop up above with the menu,
// the clipboard item may no longer be valid, as QClipboard resets
// the object behind the back of the application with a zero timer
// so we fetch it again here
QClipboard *clipboard = QApplication::clipboard();
mimeData = clipboard->mimeData(QClipboard::Selection);
}
QTemporaryFile tempFile;
if (mimeData && tempFile.open()) {
//TODO: what should we do with files after the applet is done with them??
tempFile.setAutoRemove(false);
{
QDataStream stream(&tempFile);
QByteArray data = mimeData->data(pluginFormats[selectedPlugin]);
stream.writeRawData(data, data.size());
}
QRectF geom(pos, QSize());
QVariantList args;
args << tempFile.fileName();
#ifndef NDEBUG
kDebug() << args;
#endif
tempFile.close();
q->addApplet(selectedPlugin, args, geom);
}
}
}
}
void ContainmentPrivate::clearDataForMimeJob(KIO::Job *job)
{
#ifndef PLASMA_NO_KIO
QObject::disconnect(job, 0, q, 0);
dropPoints.remove(job);
KMenu *choices = dropMenus.take(job);
delete choices;
job->kill();
#endif // PLASMA_NO_KIO
}
void ContainmentPrivate::remoteAppletReady(Plasma::AccessAppletJob *job)
{
QPointF pos = dropPoints.take(job);
if (job->error()) {
//TODO: nice user visible error handling (knotification probably?)
#ifndef NDEBUG
kDebug() << "remote applet access failed: " << job->errorText();
#endif
return;
}
if (!job->applet()) {
#ifndef NDEBUG
kDebug() << "how did we end up here? if applet is null, the job->error should be nonzero";
#endif
return;
}
q->addApplet(job->applet(), pos);
}
void ContainmentPrivate::dropJobResult(KJob *job)
{
#ifndef PLASMA_NO_KIO
KIO::TransferJob* tjob = dynamic_cast<KIO::TransferJob*>(job);
if (!tjob) {
#ifndef NDEBUG
kDebug() << "job is not a KIO::TransferJob, won't handle the drop...";
#endif
clearDataForMimeJob(tjob);
return;
}
if (job->error()) {
#ifndef NDEBUG
kDebug() << "ERROR" << tjob->error() << ' ' << tjob->errorString();
#endif
}
// We call mimeTypeRetrieved since there might be other mechanisms
// for finding suitable applets. Cleanup happens there as well.
mimeTypeRetrieved(qobject_cast<KIO::Job *>(job), QString());
#endif // PLASMA_NO_KIO
}
void ContainmentPrivate::mimeTypeRetrieved(KIO::Job *job, const QString &mimeType)
{
#ifndef PLASMA_NO_KIO
#ifndef NDEBUG
kDebug() << "Mimetype Job returns." << mimeType;
#endif
KIO::TransferJob* tjob = dynamic_cast<KIO::TransferJob*>(job);
if (!tjob) {
#ifndef NDEBUG
kDebug() << "job should be a TransferJob, but isn't";
#endif
clearDataForMimeJob(job);
return;
}
KPluginInfo::List appletList = Applet::listAppletInfoForUrl(tjob->url());
if (mimeType.isEmpty() && !appletList.count()) {
clearDataForMimeJob(job);
#ifndef NDEBUG
kDebug() << "No applets found matching the url (" << tjob->url() << ") or the mimeType (" << mimeType << ")";
#endif
return;
} else {
QPointF posi; // will be overwritten with the event's position
if (dropPoints.keys().contains(tjob)) {
posi = dropPoints[tjob];
#ifndef NDEBUG
kDebug() << "Received a suitable dropEvent at" << posi;
#endif
} else {
#ifndef NDEBUG
kDebug() << "Bailing out. Cannot find associated dropEvent related to the TransferJob";
#endif
clearDataForMimeJob(job);
return;
}
KMenu *choices = dropMenus.value(tjob);
if (!choices) {
#ifndef NDEBUG
kDebug() << "Bailing out. No QMenu found for this job.";
#endif
clearDataForMimeJob(job);
return;
}
QVariantList args;
args << tjob->url().url() << mimeType;
#ifndef NDEBUG
kDebug() << "Creating menu for:" << mimeType << posi << args;
#endif
appletList << Applet::listAppletInfoForMimeType(mimeType);
KPluginInfo::List wallpaperList;
if (drawWallpaper) {
if (wallpaper && wallpaper->supportsMimetype(mimeType)) {
wallpaperList << wallpaper->d->wallpaperDescription;
} else {
wallpaperList = Wallpaper::listWallpaperInfoForMimetype(mimeType);
}
}
if (!appletList.isEmpty() || !wallpaperList.isEmpty()) {
choices->clear();
QHash<QAction *, QString> actionsToApplets;
choices->addTitle(i18n("Widgets"));
foreach (const KPluginInfo &info, appletList) {
#ifndef NDEBUG
kDebug() << info.name();
#endif
QAction *action;
if (!info.icon().isEmpty()) {
action = choices->addAction(KIcon(info.icon()), info.name());
} else {
action = choices->addAction(info.name());
}
actionsToApplets.insert(action, info.pluginName());
#ifndef NDEBUG
kDebug() << info.pluginName();
#endif
}
actionsToApplets.insert(choices->addAction(i18n("Icon")), "icon");
QHash<QAction *, QString> actionsToWallpapers;
if (!wallpaperList.isEmpty()) {
choices->addTitle(i18n("Wallpaper"));
QMap<QString, KPluginInfo> sorted;
foreach (const KPluginInfo &info, appletList) {
sorted.insert(info.name(), info);
}
foreach (const KPluginInfo &info, wallpaperList) {
QAction *action;
if (!info.icon().isEmpty()) {
action = choices->addAction(KIcon(info.icon()), info.name());
} else {
action = choices->addAction(info.name());
}
actionsToWallpapers.insert(action, info.pluginName());
}
}
QAction *choice = choices->exec();
if (choice) {
// Put the job on hold so it can be recycled to fetch the actual content,
// which is to be expected when something's dropped onto the desktop and
// an applet is to be created with this URL
if (!mimeType.isEmpty() && !tjob->error()) {
tjob->putOnHold();
KIO::Scheduler::publishSlaveOnHold();
}
QString plugin = actionsToApplets.value(choice);
if (plugin.isEmpty()) {
//set wallpapery stuff
plugin = actionsToWallpapers.value(choice);
if (!wallpaper || plugin != wallpaper->pluginName()) {
//kDebug() << "Wallpaper dropped:" << tjob->url();
q->setWallpaper(plugin);
}
if (wallpaper) {
//kDebug() << "Wallpaper dropped:" << tjob->url();
wallpaper->addUrls(KUrl::List() << tjob->url());
}
} else {
addApplet(actionsToApplets[choice], args, QRectF(posi, QSize()));
}
clearDataForMimeJob(job);
return;
}
} else {
// we can at least create an icon as a link to the URL
addApplet("icon", args, QRectF(posi, QSize()));
}
}
clearDataForMimeJob(job);
#endif // PLASMA_NO_KIO
}
void Containment::setToolBox(AbstractToolBox *toolBox)
{
if (d->toolBox.data()) {
d->toolBox.data()->deleteLater();
}
d->toolBox = toolBox;
}
AbstractToolBox *Containment::toolBox() const
{
return d->toolBox.data();
}
void Containment::resizeEvent(QGraphicsSceneResizeEvent *event)
{
Applet::resizeEvent(event);
if (isContainment()) {
if (d->isPanelContainment()) {
d->positionPanel();
} else if (corona()) {
corona()->layoutContainments();
}
if (d->wallpaper) {
d->wallpaper->setBoundingRect(QRectF(QPointF(0, 0), size()));
}
}
}
void Containment::keyPressEvent(QKeyEvent *event)
{
//kDebug() << "keyPressEvent with" << event->key()
// << "and hoping and wishing for a" << Qt::Key_Tab;
if (event->key() == Qt::Key_Tab) { // && event->modifiers() == 0) {
if (!d->applets.isEmpty()) {
#ifndef NDEBUG
kDebug() << "let's give focus to...." << (QObject*)d->applets.first();
#endif
d->applets.first()->setFocus(Qt::TabFocusReason);
}
}
}
void Containment::wheelEvent(QGraphicsSceneWheelEvent *event)
{
event->ignore();
if (d->appletAt(event->scenePos())) {
return; //no unexpected click-throughs
}
if (d->wallpaper && d->wallpaper->isInitialized()) {
QGraphicsItem *item = scene()->itemAt(event->scenePos());
if (item == this) {
event->ignore();
d->wallpaper->wheelEvent(event);
if (event->isAccepted()) {
return;
}
}
}
QString trigger = ContainmentActions::eventToString(event);
if (d->prepareContainmentActions(trigger, event->screenPos())) {
d->actionPlugins()->value(trigger)->contextEvent(event);
event->accept();
} else {
event->ignore();
Applet::wheelEvent(event);
}
}
QVariant Containment::itemChange(GraphicsItemChange change, const QVariant &value)
{
//FIXME if the applet is moved to another containment we need to unfocus it
if (isContainment() &&
(change == QGraphicsItem::ItemSceneHasChanged ||
change == QGraphicsItem::ItemPositionHasChanged)) {
switch (d->type) {
case PanelContainment:
case CustomPanelContainment:
d->positionPanel();
break;
default:
if (corona()) {
corona()->layoutContainments();
}
break;
}
}
return Applet::itemChange(change, value);
}
void Containment::enableAction(const QString &name, bool enable)
{
QAction *action = this->action(name);
if (action) {
action->setEnabled(enable);
action->setVisible(enable);
}
}
void Containment::addToolBoxAction(QAction *action)
{
d->createToolBox();
if (d->toolBox) {
d->toolBox.data()->addTool(action);
}
}
void Containment::removeToolBoxAction(QAction *action)
{
if (d->toolBox) {
d->toolBox.data()->removeTool(action);
}
}
void Containment::setToolBoxOpen(bool open)
{
if (open) {
openToolBox();
} else {
closeToolBox();
}
}
bool Containment::isToolBoxOpen() const
{
return (d->toolBox && d->toolBox.data()->isShowing());
}
void Containment::openToolBox()
{
if (d->toolBox && !d->toolBox.data()->isShowing()) {
d->toolBox.data()->setShowing(true);
emit toolBoxVisibilityChanged(true);
}
}
void Containment::closeToolBox()
{
if (d->toolBox && d->toolBox.data()->isShowing()) {
d->toolBox.data()->setShowing(false);
emit toolBoxVisibilityChanged(false);
}
}
void Containment::addAssociatedWidget(QWidget *widget)
{
Applet::addAssociatedWidget(widget);
if (d->focusedApplet) {
d->focusedApplet->addAssociatedWidget(widget);
}
foreach (const Applet *applet, d->applets) {
if (applet->d->activationAction) {
widget->addAction(applet->d->activationAction);
}
}
}
void Containment::removeAssociatedWidget(QWidget *widget)
{
Applet::removeAssociatedWidget(widget);
if (d->focusedApplet) {
d->focusedApplet->removeAssociatedWidget(widget);
}
foreach (const Applet *applet, d->applets) {
if (applet->d->activationAction) {
widget->removeAction(applet->d->activationAction);
}
}
}
void Containment::setDrawWallpaper(bool drawWallpaper)
{
d->drawWallpaper = drawWallpaper;
if (drawWallpaper) {
KConfigGroup cfg = config();
const QString wallpaper = cfg.readEntry("wallpaperplugin", defaultWallpaper);
const QString mode = cfg.readEntry("wallpaperpluginmode", defaultWallpaperMode);
setWallpaper(wallpaper, mode);
} else {
delete d->wallpaper;
d->wallpaper = 0;
}
}
bool Containment::drawWallpaper()
{
return d->drawWallpaper;
}
void Containment::setWallpaper(const QString &pluginName, const QString &mode)
{
KConfigGroup cfg = config();
bool newPlugin = true;
bool newMode = true;
if (d->drawWallpaper) {
if (d->wallpaper) {
// we have a wallpaper, so let's decide whether we need to swap it out
if (d->wallpaper->pluginName() != pluginName) {
delete d->wallpaper;
d->wallpaper = 0;
} else {
// it's the same plugin, so let's save its state now so when
// we call restore later on we're safe
newMode = d->wallpaper->renderingMode().name() != mode;
newPlugin = false;
}
}
if (!pluginName.isEmpty() && !d->wallpaper) {
d->wallpaper = Plasma::Wallpaper::load(pluginName);
}
if (d->wallpaper) {
d->wallpaper->setParent(this);
d->wallpaper->setBoundingRect(QRectF(QPointF(0, 0), size()));
d->wallpaper->setRenderingMode(mode);
if (newPlugin) {
cfg.writeEntry("wallpaperplugin", pluginName);
}
if (d->wallpaper->isInitialized()) {
KConfigGroup wallpaperConfig = KConfigGroup(&cfg, "Wallpaper");
wallpaperConfig = KConfigGroup(&wallpaperConfig, pluginName);
d->wallpaper->restore(wallpaperConfig);
}
if (newMode) {
cfg.writeEntry("wallpaperpluginmode", mode);
}
}
update();
}
if (!d->wallpaper) {
cfg.deleteEntry("wallpaperplugin");
cfg.deleteEntry("wallpaperpluginmode");
}
if (newPlugin || newMode) {
if (newPlugin && d->wallpaper) {
connect(d->wallpaper, SIGNAL(configureRequested()), this, SLOT(requestConfiguration()));
connect(d->wallpaper, SIGNAL(configNeedsSaving()), this, SIGNAL(configNeedsSaving()));
}
emit configNeedsSaving();
}
}
Plasma::Wallpaper *Containment::wallpaper() const
{
return d->wallpaper;
}
void Containment::setContainmentActions(const QString &trigger, const QString &pluginName)
{
KConfigGroup cfg = containmentActionsConfig();
ContainmentActions *plugin = 0;
if (d->actionPlugins()->contains(trigger)) {
plugin = d->actionPlugins()->value(trigger);
if (plugin->pluginName() != pluginName) {
d->actionPlugins()->remove(trigger);
delete plugin;
plugin=0;
}
}
if (pluginName.isEmpty()) {
cfg.deleteEntry(trigger);
} else if (plugin) {
//it already existed, just reload config
if (plugin->isInitialized()) {
plugin->setContainment(this); //to be safe
//FIXME make a truly unique config group
KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
plugin->restore(pluginConfig);
}
} else {
switch (d->containmentActionsSource) {
case ContainmentPrivate::Activity:
//FIXME
case ContainmentPrivate::Local:
plugin = PluginLoader::self()->loadContainmentActions(this, pluginName);
break;
default:
plugin = PluginLoader::self()->loadContainmentActions(0, pluginName);
}
if (plugin) {
cfg.writeEntry(trigger, pluginName);
d->actionPlugins()->insert(trigger, plugin);
} else {
//bad plugin... gets removed. is this a feature or a bug?
cfg.deleteEntry(trigger);
}
}
emit configNeedsSaving();
}
QStringList Containment::containmentActionsTriggers()
{
return d->actionPlugins()->keys();
}
QString Containment::containmentActions(const QString &trigger)
{
ContainmentActions *c = d->actionPlugins()->value(trigger);
return c ? c->pluginName() : QString();
}
void Containment::setActivity(const QString &activityId)
{
if (activityId.isEmpty()) {
return;
}
d->activityId = activityId;
KConfigGroup c = config();
c.writeEntry("activityId", activityId);
if (d->toolBox) {
d->toolBox.data()->update();
}
emit configNeedsSaving();
}
QString Containment::activity() const
{
return d->activityId;
}
KActionCollection* ContainmentPrivate::actions()
{
return static_cast<Applet*>(q)->d->actions;
}
void ContainmentPrivate::focusApplet(Plasma::Applet *applet)
{
if (focusedApplet == applet) {
return;
}
QList<QWidget *> widgets = actions()->associatedWidgets();
if (focusedApplet) {
foreach (QWidget *w, widgets) {
focusedApplet->removeAssociatedWidget(w);
}
}
if (applet && applets.contains(applet)) {
//kDebug() << "switching to" << applet->name();
focusedApplet = applet;
foreach (QWidget *w, widgets) {
focusedApplet->addAssociatedWidget(w);
}
if (!focusedApplet->hasFocus()) {
focusedApplet->setFocus(Qt::ShortcutFocusReason);
}
} else {
focusedApplet = 0;
}
}
void Containment::focusNextApplet()
{
if (d->applets.isEmpty()) {
return;
}
int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) + 1 : 0;
if (index >= d->applets.size()) {
index = 0;
}
#ifndef NDEBUG
kDebug() << "index" << index;
#endif
d->focusApplet(d->applets.at(index));
}
void Containment::focusPreviousApplet()
{
if (d->applets.isEmpty()) {
return;
}
int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) - 1 : -1;
if (index < 0) {
index = d->applets.size() - 1;
}
#ifndef NDEBUG
kDebug() << "index" << index;
#endif
d->focusApplet(d->applets.at(index));
}
void Containment::destroy()
{
destroy(true);
}
void Containment::showConfigurationInterface()
{
Applet::showConfigurationInterface();
}
void ContainmentPrivate::configChanged()
{
if (drawWallpaper) {
KConfigGroup group = q->config();
q->setWallpaper(group.readEntry("wallpaperplugin", defaultWallpaper),
group.readEntry("wallpaperpluginmode", defaultWallpaperMode));
}
}
void ContainmentPrivate::requestConfiguration()
{
emit q->configureRequested(q);
}
void ContainmentPrivate::checkStatus(Plasma::ItemStatus appletStatus)
{
//kDebug() << "================== "<< appletStatus << q->status();
if (appletStatus == q->status()) {
emit q->newStatus(appletStatus);
return;
}
if (appletStatus < q->status()) {
// check to see if any other applet has a higher status, and stick with that
// if we do
foreach (Applet *applet, applets) {
if (applet->status() > appletStatus) {
appletStatus = applet->status();
}
}
}
q->setStatus(appletStatus);
}
void Containment::destroy(bool confirm)
{
if (immutability() != Mutable || Applet::d->transient) {
return;
}
if (isContainment() && confirm) {
//FIXME: should not be blocking
const QString title = i18nc("@title:window %1 is the name of the containment", "Remove %1", name());
KGuiItem remove = KStandardGuiItem::remove();
remove.setText(title);
if (KMessageBox::warningContinueCancel(view(),
i18nc("%1 is the name of the containment", "Do you really want to remove this %1?", name()),
title, remove) != KMessageBox::Continue) {
return;
}
}
Applet::destroy();
}
void ContainmentPrivate::createToolBox()
{
if (!toolBox && KAuthorized::authorizeKAction("plasma/containment_context_menu")) {
toolBox = Plasma::AbstractToolBox::load(q->corona()->preferredToolBoxPlugin(type), QVariantList(), q);
if (toolBox) {
QObject::connect(toolBox.data(), SIGNAL(toggled()), q, SIGNAL(toolBoxToggled()));
QObject::connect(toolBox.data(), SIGNAL(toggled()), q, SLOT(updateToolBoxVisibility()));
positionToolBox();
}
}
}
void ContainmentPrivate::positionToolBox()
{
if (toolBox) {
toolBox.data()->reposition();
}
}
void ContainmentPrivate::updateToolBoxVisibility()
{
emit q->toolBoxVisibilityChanged(toolBox.data()->isShowing());
}
void ContainmentPrivate::triggerShowAddWidgets()
{
emit q->showAddWidgetsInterface(QPointF());
}
void ContainmentPrivate::containmentConstraintsEvent(Plasma::Constraints constraints)
{
if (!q->isContainment()) {
return;
}
//kDebug() << "got containmentConstraintsEvent" << constraints << (QObject*)toolBox;
if (constraints & Plasma::ImmutableConstraint) {
//update actions
checkRemoveAction();
const bool unlocked = q->immutability() == Mutable;
q->setAcceptDrops(unlocked);
q->enableAction("add widgets", unlocked);
// tell the applets too
foreach (Applet *a, applets) {
a->setImmutability(q->immutability());
a->updateConstraints(ImmutableConstraint);
}
}
// pass on the constraints that are relevant here
Constraints appletConstraints = NoConstraint;
if (constraints & FormFactorConstraint) {
appletConstraints |= FormFactorConstraint;
}
if (constraints & ScreenConstraint) {
appletConstraints |= ScreenConstraint;
}
if (appletConstraints != NoConstraint) {
foreach (Applet *applet, applets) {
applet->updateConstraints(appletConstraints);
}
}
if (toolBox && (constraints & Plasma::SizeConstraint ||
constraints & Plasma::FormFactorConstraint ||
constraints & Plasma::ScreenConstraint ||
constraints & Plasma::StartupCompletedConstraint)) {
//kDebug() << "Positioning toolbox";
positionToolBox();
}
if (constraints & Plasma::StartupCompletedConstraint && type < Containment::CustomContainment) {
q->addToolBoxAction(q->action("remove"));
checkRemoveAction();
}
}
Applet *ContainmentPrivate::addApplet(const QString &name, const QVariantList &args,
const QRectF &appletGeometry, uint id, bool delayInit)
{
if (!q->isContainment()) {
return 0;
}
if (!delayInit && q->immutability() != Mutable) {
#ifndef NDEBUG
kDebug() << "addApplet for" << name << "requested, but we're currently immutable!";
#endif
return 0;
}
QGraphicsView *v = q->view();
if (v) {
v->setCursor(Qt::BusyCursor);
}
Applet *applet = PluginLoader::self()->loadApplet(name, id, args);
if (v) {
v->unsetCursor();
}
if (!applet) {
#ifndef NDEBUG
kDebug() << "Applet" << name << "could not be loaded.";
#endif
applet = new Applet(0, QString(), id);
applet->setFailedToLaunch(true, i18n("Could not find requested component: %1", name));
}
//kDebug() << applet->name() << "sizehint:" << applet->sizeHint() << "geometry:" << applet->geometry();
q->addApplet(applet, appletGeometry.topLeft(), delayInit);
return applet;
}
bool ContainmentPrivate::regionIsEmpty(const QRectF &region, Applet *ignoredApplet) const
{
foreach (Applet *applet, applets) {
if (applet != ignoredApplet && applet->geometry().intersects(region)) {
return false;
}
}
return true;
}
void ContainmentPrivate::appletDestroyed(Plasma::Applet *applet)
{
applets.removeAll(applet);
if (focusedApplet == applet) {
focusedApplet = 0;
}
emit q->appletRemoved(applet);
emit q->configNeedsSaving();
}
void ContainmentPrivate::appletAppeared(Applet *applet)
{
//kDebug() << type << Containment::DesktopContainment;
KConfigGroup *cg = applet->d->mainConfigGroup();
applet->save(*cg);
emit q->configNeedsSaving();
}
void ContainmentPrivate::positionPanel(bool force)
{
if (!q->scene()) {
#ifndef NDEBUG
kDebug() << "no scene yet";
#endif
return;
}
// already positioning the panel - avoid infinite loops
if (ContainmentPrivate::s_positioningPanels) {
return;
}
// we position panels in negative coordinates, and stack all horizontal
// and all vertical panels with each other.
const QPointF p = q->pos();
if (!force &&
p.y() + q->size().height() < -INTER_CONTAINMENT_MARGIN &&
q->scene()->collidingItems(q).isEmpty()) {
// already positioned and not running into any other panels
return;
}
QPointF newPos = preferredPanelPos(q->corona());
if (p != newPos) {
ContainmentPrivate::s_positioningPanels = true;
q->setPos(newPos);
ContainmentPrivate::s_positioningPanels = false;
}
}
bool ContainmentPrivate::isPanelContainment() const
{
return type == Containment::PanelContainment || type == Containment::CustomPanelContainment;
}
QPointF ContainmentPrivate::preferredPos(Corona *corona) const
{
Q_ASSERT(corona);
if (isPanelContainment()) {
//kDebug() << "is a panel, so put it at" << preferredPanelPos(corona);
return preferredPanelPos(corona);
}
QPointF pos(0, 0);
QTransform t;
while (QGraphicsItem *i = corona->itemAt(pos, t)) {
pos.setX(i->scenePos().x() + i->boundingRect().width() + 10);
}
//kDebug() << "not a panel, put it at" << pos;
return pos;
}
QPointF ContainmentPrivate::preferredPanelPos(Corona *corona) const
{
Q_ASSERT(corona);
//TODO: research how non-Horizontal, non-Vertical (e.g. Planar) panels behave here
bool horiz = formFactor == Plasma::Horizontal;
qreal bottom = horiz ? 0 : VERTICAL_STACKING_OFFSET;
qreal lastHeight = 0;
// this should be ok for small numbers of panels, but if we ever end
// up managing hundreds of them, this simplistic alogrithm will
// likely be too slow.
foreach (const Containment *other, corona->containments()) {
if (other == q ||
!other->d->isPanelContainment() ||
horiz != (other->formFactor() == Plasma::Horizontal)) {
// only line up with panels of the same orientation
continue;
}
if (horiz) {
qreal y = other->pos().y();
if (y < bottom) {
lastHeight = other->size().height();
bottom = y;
}
} else {
qreal width = other->size().width();
qreal x = other->pos().x() + width;
if (x > bottom) {
lastHeight = width;
bottom = x + lastHeight;
}
}
}
// give a space equal to the height again of the last item so there is
// room to grow.
QPointF newPos;
if (horiz) {
bottom -= lastHeight + INTER_CONTAINMENT_MARGIN;
//TODO: fix x position for non-flush-left panels
#ifndef NDEBUG
kDebug() << "moved to" << QPointF(0, bottom - q->size().height());
#endif
newPos = QPointF(0, bottom - q->size().height());
} else {
bottom += lastHeight + INTER_CONTAINMENT_MARGIN;
//TODO: fix y position for non-flush-top panels
#ifndef NDEBUG
kDebug() << "moved to" << QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
#endif
newPos = QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
}
return newPos;
}
bool ContainmentPrivate::prepareContainmentActions(const QString &trigger, const QPoint &screenPos, KMenu *menu)
{
ContainmentActions *plugin = actionPlugins()->value(trigger);
if (!plugin) {
return false;
}
plugin->setContainment(q);
if (!plugin->isInitialized()) {
KConfigGroup cfg = q->containmentActionsConfig();
KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
plugin->restore(pluginConfig);
}
if (plugin->configurationRequired()) {
KMenu *localMenu = menu ? menu : new KMenu();
localMenu->addTitle(i18n("This plugin needs to be configured"));
localMenu->addAction(q->action("configure"));
if (!menu) {
localMenu->exec(screenPos);
delete localMenu;
}
return false;
} else if (menu) {
QList<QAction*> actions = plugin->contextualActions();
if (actions.isEmpty()) {
//it probably didn't bother implementing the function. give the user a chance to set
//a better plugin. note that if the user sets no-plugin this won't happen...
if (!isPanelContainment() && q->action("configure")) {
menu->addAction(q->action("configure"));
}
} else {
menu->addActions(actions);
}
}
return true;
}
KConfigGroup Containment::containmentActionsConfig()
{
KConfigGroup cfg;
switch (d->containmentActionsSource) {
case ContainmentPrivate::Local:
cfg = config();
cfg = KConfigGroup(&cfg, "ActionPlugins");
break;
case ContainmentPrivate::Activity:
cfg = KConfigGroup(corona()->config(), "Activities");
cfg = KConfigGroup(&cfg, d->activityId);
cfg = KConfigGroup(&cfg, "ActionPlugins");
break;
default:
cfg = KConfigGroup(corona()->config(), "ActionPlugins");
}
return cfg;
}
QHash<QString, ContainmentActions*> * ContainmentPrivate::actionPlugins()
{
switch (containmentActionsSource) {
case Activity:
//FIXME
case Local:
return &localActionPlugins;
default:
return &globalActionPlugins;
}
}
} // Plasma namespace
+
+#include "moc_containment.cpp"
diff --git a/plasma/containmentactions.cpp b/plasma/containmentactions.cpp
index 0bb3c392e1..dacd13b83f 100644
--- a/plasma/containmentactions.cpp
+++ b/plasma/containmentactions.cpp
@@ -1,334 +1,336 @@
/*
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "containmentactions.h"
#include "containment.h"
#include "private/dataengineconsumer_p.h"
#include "private/packages_p.h"
#include "private/containmentactions_p.h"
#include "private/containment_p.h"
#include <QMetaEnum>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QGraphicsSceneContextMenuEvent>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneWheelEvent>
#include <kdebug.h>
#include <kglobal.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#include <version.h>
namespace Plasma
{
ContainmentActions::ContainmentActions(QObject * parentObject)
: d(new ContainmentActionsPrivate(KService::serviceByStorageId(QString()), this))
{
setParent(parentObject);
}
ContainmentActions::ContainmentActions(QObject *parentObject, const QVariantList &args)
: d(new ContainmentActionsPrivate(KService::serviceByStorageId(args.count() > 0 ?
args[0].toString() : QString()), this))
{
// now remove first item since those are managed by Wallpaper and subclasses shouldn't
// need to worry about them. yes, it violates the constness of this var, but it lets us add
// or remove items later while applets can just pretend that their args always start at 0
QVariantList &mutableArgs = const_cast<QVariantList &>(args);
if (!mutableArgs.isEmpty()) {
mutableArgs.removeFirst();
}
setParent(parentObject);
}
ContainmentActions::~ContainmentActions()
{
delete d;
}
Containment *ContainmentActions::containment()
{
if (d->containment) {
return d->containment;
}
return qobject_cast<Containment*>(parent());
}
QString ContainmentActions::name() const
{
if (!d->containmentActionsDescription.isValid()) {
return i18n("Unknown ContainmentActions");
}
return d->containmentActionsDescription.name();
}
QString ContainmentActions::icon() const
{
if (!d->containmentActionsDescription.isValid()) {
return QString();
}
return d->containmentActionsDescription.icon();
}
QString ContainmentActions::pluginName() const
{
if (!d->containmentActionsDescription.isValid()) {
return QString();
}
return d->containmentActionsDescription.pluginName();
}
bool ContainmentActions::isInitialized() const
{
return d->initialized;
}
void ContainmentActions::restore(const KConfigGroup &config)
{
init(config);
d->initialized = true;
}
void ContainmentActions::init(const KConfigGroup &config)
{
Q_UNUSED(config);
}
void ContainmentActions::save(KConfigGroup &config)
{
Q_UNUSED(config);
}
QWidget *ContainmentActions::createConfigurationInterface(QWidget *parent)
{
Q_UNUSED(parent);
return 0;
}
void ContainmentActions::configurationAccepted()
{
//do nothing by default
}
void ContainmentActions::contextEvent(QEvent *event)
{
Q_UNUSED(event)
}
QList<QAction*> ContainmentActions::contextualActions()
{
//empty list
return QList<QAction*>();
}
DataEngine *ContainmentActions::dataEngine(const QString &name) const
{
return d->dataEngine(name);
}
bool ContainmentActions::configurationRequired() const
{
return d->needsConfig;
}
void ContainmentActions::setConfigurationRequired(bool needsConfig)
{
//TODO: reason?
d->needsConfig = needsConfig;
}
QString ContainmentActions::eventToString(QEvent *event)
{
QString trigger;
Qt::KeyboardModifiers modifiers;
switch (event->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
{
QMouseEvent *e = static_cast<QMouseEvent*>(event);
int m = QObject::staticQtMetaObject.indexOfEnumerator("MouseButtons");
QMetaEnum mouse = QObject::staticQtMetaObject.enumerator(m);
trigger += mouse.valueToKey(e->button());
modifiers = e->modifiers();
break;
}
case QEvent::GraphicsSceneMousePress:
case QEvent::GraphicsSceneMouseRelease:
case QEvent::GraphicsSceneMouseDoubleClick:
{
QGraphicsSceneMouseEvent *e = static_cast<QGraphicsSceneMouseEvent*>(event);
int m = QObject::staticQtMetaObject.indexOfEnumerator("MouseButtons");
QMetaEnum mouse = QObject::staticQtMetaObject.enumerator(m);
trigger += mouse.valueToKey(e->button());
modifiers = e->modifiers();
break;
}
case QEvent::Wheel:
{
QWheelEvent *e = static_cast<QWheelEvent*>(event);
int o = QObject::staticQtMetaObject.indexOfEnumerator("Orientations");
QMetaEnum orient = QObject::staticQtMetaObject.enumerator(o);
trigger = "wheel:";
trigger += orient.valueToKey(e->orientation());
modifiers = e->modifiers();
break;
}
case QEvent::GraphicsSceneWheel:
{
QGraphicsSceneWheelEvent *e = static_cast<QGraphicsSceneWheelEvent*>(event);
int o = QObject::staticQtMetaObject.indexOfEnumerator("Orientations");
QMetaEnum orient = QObject::staticQtMetaObject.enumerator(o);
trigger = "wheel:";
trigger += orient.valueToKey(e->orientation());
modifiers = e->modifiers();
break;
}
case QEvent::GraphicsSceneContextMenu:
case QEvent::ContextMenu:
{
int m = QObject::staticQtMetaObject.indexOfEnumerator("MouseButtons");
QMetaEnum mouse = QObject::staticQtMetaObject.enumerator(m);
trigger = mouse.valueToKey(Qt::RightButton);
modifiers = Qt::NoModifier;
break;
}
default:
return QString();
}
int k = QObject::staticQtMetaObject.indexOfEnumerator("KeyboardModifiers");
QMetaEnum kbd = QObject::staticQtMetaObject.enumerator(k);
trigger += ';';
trigger += kbd.valueToKeys(modifiers);
return trigger;
}
void ContainmentActions::paste(QPointF scenePos, QPoint screenPos)
{
Containment *c = containment();
if (c) {
c->d->dropData(scenePos, screenPos);
}
}
QPoint screenPosFromEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::GraphicsSceneMousePress:
case QEvent::GraphicsSceneMouseRelease:
case QEvent::GraphicsSceneMouseDoubleClick:
return static_cast<QGraphicsSceneMouseEvent*>(event)->screenPos();
break;
case QEvent::GraphicsSceneWheel:
return static_cast<QGraphicsSceneWheelEvent*>(event)->screenPos();
break;
case QEvent::GraphicsSceneContextMenu:
return static_cast<QGraphicsSceneContextMenuEvent*>(event)->screenPos();
break;
default:
break;
}
return QPoint();
}
QPointF scenePosFromEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::GraphicsSceneMousePress:
case QEvent::GraphicsSceneMouseRelease:
case QEvent::GraphicsSceneMouseDoubleClick:
return static_cast<QGraphicsSceneMouseEvent*>(event)->scenePos();
break;
case QEvent::GraphicsSceneWheel:
return static_cast<QGraphicsSceneWheelEvent*>(event)->scenePos();
break;
case QEvent::GraphicsSceneContextMenu:
return static_cast<QGraphicsSceneContextMenuEvent*>(event)->scenePos();
break;
default:
break;
}
return QPoint();
}
bool isNonSceneEvent(QEvent *event)
{
return dynamic_cast<QGraphicsSceneEvent *>(event) == 0;
}
QPoint ContainmentActions::popupPosition(const QSize &s, QEvent *event)
{
if (isNonSceneEvent(event)) {
return screenPosFromEvent(event);
}
Containment *c = containment();
if (!c) {
return screenPosFromEvent(event);
}
Applet *applet = c->d->appletAt(scenePosFromEvent(event));
QPoint screenPos = screenPosFromEvent(event);
QPoint pos = screenPos;
if (applet && containment()->d->isPanelContainment()) {
pos = applet->popupPosition(s);
if (event->type() != QEvent::GraphicsSceneContextMenu ||
static_cast<QGraphicsSceneContextMenuEvent *>(event)->reason() == QGraphicsSceneContextMenuEvent::Mouse) {
// if the menu pops up way away from the mouse press, then move it
// to the mouse press
if (c->formFactor() == Vertical) {
if (pos.y() + s.height() < screenPos.y()) {
pos.setY(screenPos.y());
}
} else if (c->formFactor() == Horizontal) {
if (pos.x() + s.width() < screenPos.x()) {
pos.setX(screenPos.x());
}
}
}
}
return pos;
}
bool ContainmentActions::event(QEvent *)
{
//no longer needed
return false;
}
void ContainmentActions::setContainment(Containment *newContainment) {
d->containment = newContainment;
}
} // Plasma namespace
+
+#include "moc_containmentactions.cpp"
diff --git a/plasma/corona.cpp b/plasma/corona.cpp
index 6f880da8fb..0d70558d48 100644
--- a/plasma/corona.cpp
+++ b/plasma/corona.cpp
@@ -1,1049 +1,1051 @@
/*
* Copyright 2007 Matt Broadstone <mbroadst@gmail.com>
* Copyright 2007-2011 Aaron Seigo <aseigo@kde.org>
* Copyright 2007 Riccardo Iaconelli <riccardo@kde.org>
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "corona.h"
#include "private/corona_p.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QGraphicsView>
#include <QGraphicsGridLayout>
#include <QMimeData>
#include <QPainter>
#include <QTimer>
#include <cmath>
#include <kaction.h>
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <kmimetype.h>
#include <kshortcutsdialog.h>
#include <kwindowsystem.h>
#include "abstractdialogmanager.h"
#include "abstracttoolbox.h"
#include "containment.h"
#include "containmentactionspluginsconfig.h"
#include "pluginloader.h"
#include "private/applet_p.h"
#include "private/containment_p.h"
#include "tooltipmanager.h"
#include "view.h"
using namespace Plasma;
namespace Plasma
{
bool CoronaPrivate::s_positioningContainments = false;
Corona::Corona(QObject *parent)
: QGraphicsScene(parent),
d(new CoronaPrivate(this))
{
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Corona ctor start";
#endif
d->init();
//setViewport(new QGLWidget(QGLFormat(QGL::StencilBuffer | QGL::AlphaChannel)));
}
Corona::~Corona()
{
KConfigGroup trans(KGlobal::config(), "PlasmaTransientsConfig");
trans.deleteGroup();
// 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();
delete d;
}
void Corona::setAppletMimeType(const QString &type)
{
d->mimetype = type;
}
QString Corona::appletMimeType()
{
return d->mimetype;
}
void Corona::setDefaultContainmentPlugin(const QString &name)
{
// we could check if it is in:
// Containment::listContainments().contains(name) ||
// Containment::listContainments(QString(), KGlobal::mainComponent().componentName()).contains(name)
// but that seems like overkill
d->defaultContainmentPlugin = name;
}
QString Corona::defaultContainmentPlugin() const
{
return d->defaultContainmentPlugin;
}
void Corona::saveLayout(const QString &configName) const
{
KSharedConfigPtr c;
if (configName.isEmpty() || configName == d->configName) {
c = config();
} else {
c = KSharedConfig::openConfig(configName, KConfig::SimpleConfig);
}
d->saveLayout(c);
}
void Corona::exportLayout(KConfigGroup &config, QList<Containment*> containments)
{
foreach (const QString &group, config.groupList()) {
KConfigGroup cg(&config, group);
cg.deleteGroup();
}
//temporarily unlock so that removal works
ImmutabilityType oldImm = immutability();
d->immutability = Mutable;
KConfigGroup dest(&config, "Containments");
KConfigGroup dummy;
foreach (Plasma::Containment *c, containments) {
c->save(dummy);
c->config().reparent(&dest);
//ensure the containment is unlocked
//this is done directly because we have to bypass any SystemImmutable checks
c->Applet::d->immutability = Mutable;
foreach (Applet *a, c->applets()) {
a->d->immutability = Mutable;
}
c->destroy(false);
}
//restore immutability
d->immutability = oldImm;
config.sync();
}
void Corona::requestConfigSync()
{
// constant controlling how long between requesting a configuration sync
// and one happening should occur. currently 10 seconds
static const int CONFIG_SYNC_TIMEOUT = 10000;
// TODO: should we check into our immutability before doing this?
//NOTE: this is a pretty simplistic model: we simply save no more than CONFIG_SYNC_TIMEOUT
// after the first time this is called. not much of a heuristic for save points, but
// it should at least compress these activities a bit and provide a way for applet
// authors to ween themselves from the sync() disease. A more interesting/dynamic
// algorithm for determining when to actually sync() to disk might be better, though.
if (!d->configSyncTimer.isActive()) {
d->configSyncTimer.start(CONFIG_SYNC_TIMEOUT);
}
}
void Corona::requireConfigSync()
{
d->syncConfig();
}
void Corona::initializeLayout(const QString &configName)
{
clearContainments();
loadLayout(configName);
if (d->containments.isEmpty()) {
loadDefaultLayout();
if (!d->containments.isEmpty()) {
requestConfigSync();
}
}
if (config()->isImmutable()) {
setImmutability(SystemImmutable);
} else {
KConfigGroup coronaConfig(config(), "General");
setImmutability((ImmutabilityType)coronaConfig.readEntry("immutability", (int)Mutable));
}
}
bool containmentSortByPosition(const Containment *c1, const Containment *c2)
{
return c1->id() < c2->id();
}
void Corona::layoutContainments()
{
if (CoronaPrivate::s_positioningContainments) {
return;
}
CoronaPrivate::s_positioningContainments = true;
//TODO: we should avoid running this too often; consider compressing requests
// with a timer.
QList<Containment*> c = containments();
QMutableListIterator<Containment*> it(c);
while (it.hasNext()) {
Containment *containment = it.next();
if (containment->containmentType() == Containment::PanelContainment ||
containment->containmentType() == Containment::CustomPanelContainment ||
offscreenWidgets().contains(containment)) {
// weed out all containments we don't care about at all
// e.g. Panels and ourself
it.remove();
continue;
}
}
qSort(c.begin(), c.end(), containmentSortByPosition);
if (c.isEmpty()) {
CoronaPrivate::s_positioningContainments = false;
return;
}
int column = 0;
int x = 0;
int y = 0;
int rowHeight = 0;
it.toFront();
while (it.hasNext()) {
Containment *containment = it.next();
containment->setPos(x, y);
//kDebug() << ++count << "setting to" << x << y;
int height = containment->size().height();
if (height > rowHeight) {
rowHeight = height;
}
++column;
if (column == CONTAINMENT_COLUMNS) {
column = 0;
x = 0;
y += rowHeight + INTER_CONTAINMENT_MARGIN + TOOLBOX_MARGIN;
rowHeight = 0;
} else {
x += containment->size().width() + INTER_CONTAINMENT_MARGIN;
}
//kDebug() << "column: " << column << "; x " << x << "; y" << y << "; width was"
// << containment->size().width();
}
CoronaPrivate::s_positioningContainments = false;
}
void Corona::loadLayout(const QString &configName)
{
if (!configName.isEmpty() && configName != d->configName) {
// if we have a new config name passed in, then use that as the config file for this Corona
d->config = 0;
d->configName = configName;
}
KConfigGroup conf(config(), QString());
d->importLayout(conf, false);
}
QList<Plasma::Containment *> Corona::importLayout(const KConfigGroup &conf)
{
return d->importLayout(conf, true);
}
Containment *Corona::containmentForScreen(int screen, int desktop) const
{
foreach (Containment *containment, d->containments) {
if (containment->screen() == screen &&
(desktop < 0 || containment->desktop() == desktop) &&
(containment->containmentType() == Containment::DesktopContainment ||
containment->containmentType() == Containment::CustomContainment)) {
return containment;
}
}
return 0;
}
Containment *Corona::containmentForScreen(int screen, int desktop,
const QString &defaultPluginIfNonExistent, const QVariantList &defaultArgs)
{
Containment *containment = containmentForScreen(screen, desktop);
if (!containment && !defaultPluginIfNonExistent.isEmpty()) {
// screen requests are allowed to bypass immutability
if (screen >= 0 && screen < numScreens() &&
desktop >= -1 && desktop < KWindowSystem::numberOfDesktops()) {
containment = d->addContainment(defaultPluginIfNonExistent, defaultArgs, 0, false);
if (containment) {
containment->setScreen(screen, desktop);
}
}
}
return containment;
}
QList<Containment*> Corona::containments() const
{
return d->containments;
}
void Corona::clearContainments()
{
foreach (Containment *containment, d->containments) {
containment->clearApplets();
}
}
KSharedConfigPtr Corona::config() const
{
if (!d->config) {
d->config = KSharedConfig::openConfig(d->configName, KConfig::SimpleConfig);
}
return d->config;
}
Containment *Corona::addContainment(const QString &name, const QVariantList &args)
{
if (d->immutability == Mutable) {
return d->addContainment(name, args, 0, false);
}
return 0;
}
Containment *Corona::addContainmentDelayed(const QString &name, const QVariantList &args)
{
if (d->immutability == Mutable) {
return d->addContainment(name, args, 0, true);
}
return 0;
}
void Corona::addOffscreenWidget(QGraphicsWidget *widget)
{
foreach (QGraphicsWidget *w, d->offscreenWidgets) {
if (w == widget) {
#ifndef NDEBUG
kDebug() << "widget is already an offscreen widget!";
#endif
return;
}
}
//search for an empty spot in the topleft quadrant of the scene. each 'slot' is QWIDGETSIZE_MAX
//x QWIDGETSIZE_MAX, so we're guaranteed to never have to move widgets once they're placed here.
int i = 0;
while (d->offscreenWidgets.contains(i)) {
i++;
}
d->offscreenWidgets[i] = widget;
widget->setPos((-i - 1) * QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
QGraphicsWidget *pw = widget->parentWidget();
widget->setParentItem(0);
if (pw) {
widget->setParent(pw);
}
//kDebug() << "adding offscreen widget at slot " << i;
if (!widget->scene()) {
addItem(widget);
}
connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(offscreenWidgetDestroyed(QObject*)));
}
void Corona::removeOffscreenWidget(QGraphicsWidget *widget)
{
QMutableHashIterator<uint, QGraphicsWidget *> it(d->offscreenWidgets);
while (it.hasNext()) {
if (it.next().value() == widget) {
it.remove();
return;
}
}
}
QList <QGraphicsWidget *> Corona::offscreenWidgets() const
{
return d->offscreenWidgets.values();
}
void CoronaPrivate::offscreenWidgetDestroyed(QObject *o)
{
// at this point, it's just a QObject, not a QGraphicsWidget, but we still need
// a pointer of the appropriate type.
// WARNING: DO NOT USE THE WIDGET POINTER FOR ANYTHING OTHER THAN POINTER COMPARISONS
QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(o);
q->removeOffscreenWidget(widget);
}
int Corona::numScreens() const
{
return 1;
}
QRect Corona::screenGeometry(int id) const
{
Q_UNUSED(id);
QGraphicsView *v = views().value(0);
if (v) {
QRect r = sceneRect().toRect();
r.moveTo(v->mapToGlobal(QPoint(0, 0)));
return r;
}
return sceneRect().toRect();
}
QRegion Corona::availableScreenRegion(int id) const
{
return QRegion(screenGeometry(id));
}
QPoint Corona::popupPosition(const QGraphicsItem *item, const QSize &s, Qt::AlignmentFlag alignment)
{
const QGraphicsItem *actualItem = item;
const QGraphicsView *v = viewFor(item);
if (!v) {
return QPoint(0, 0);
}
//its own view could be hidden, for instance if item is in an hidden Dialog
//try to position it using the parent applet as the item
if (!v->isVisible()) {
actualItem = item->parentItem();
if (!actualItem) {
const QGraphicsWidget *widget = qgraphicsitem_cast<const QGraphicsWidget*>(item);
if (widget) {
actualItem = qobject_cast<QGraphicsItem*>(widget->parent());
}
}
#ifndef NDEBUG
kDebug() << actualItem;
#endif
if (actualItem) {
v = viewFor(actualItem);
if (!v) {
return QPoint(0, 0);
}
}
}
if (!actualItem) {
actualItem = item;
}
QPoint pos;
QTransform sceneTransform = actualItem->sceneTransform();
//swap direction if necessary
if (QApplication::isRightToLeft() && alignment != Qt::AlignCenter) {
if (alignment == Qt::AlignRight) {
alignment = Qt::AlignLeft;
} else {
alignment = Qt::AlignRight;
}
}
//if the applet is rotated the popup position has to be un-transformed
if (sceneTransform.isRotating()) {
qreal angle = acos(sceneTransform.m11());
QTransform newTransform;
QPointF center = actualItem->sceneBoundingRect().center();
newTransform.translate(center.x(), center.y());
newTransform.rotateRadians(-angle);
newTransform.translate(-center.x(), -center.y());
pos = v->mapFromScene(newTransform.inverted().map(actualItem->scenePos()));
} else {
pos = v->mapFromScene(actualItem->scenePos());
}
pos = v->mapToGlobal(pos);
//kDebug() << "==> position is" << actualItem->scenePos() << v->mapFromScene(actualItem->scenePos()) << pos;
const Plasma::View *pv = qobject_cast<const Plasma::View *>(v);
Plasma::Location loc = Floating;
if (pv && pv->containment()) {
loc = pv->containment()->location();
}
switch (loc) {
case BottomEdge:
case TopEdge: {
if (alignment == Qt::AlignCenter) {
pos.setX(pos.x() + actualItem->boundingRect().width()/2 - s.width()/2);
} else if (alignment == Qt::AlignRight) {
pos.setX(pos.x() + actualItem->boundingRect().width() - s.width());
}
if (pos.x() + s.width() > v->geometry().x() + v->geometry().width()) {
pos.setX((v->geometry().x() + v->geometry().width()) - s.width());
} else {
pos.setX(qMax(pos.x(), v->geometry().left()));
}
break;
}
case LeftEdge:
case RightEdge: {
if (alignment == Qt::AlignCenter) {
pos.setY(pos.y() + actualItem->boundingRect().height()/2 - s.height()/2);
} else if (alignment == Qt::AlignRight) {
pos.setY(pos.y() + actualItem->boundingRect().height() - s.height());
}
if (pos.y() + s.height() > v->geometry().y() + v->geometry().height()) {
pos.setY((v->geometry().y() + v->geometry().height()) - s.height());
} else {
pos.setY(qMax(pos.y(), v->geometry().top()));
}
break;
}
default:
if (alignment == Qt::AlignCenter) {
pos.setX(pos.x() + actualItem->boundingRect().width()/2 - s.width()/2);
} else if (alignment == Qt::AlignRight) {
pos.setX(pos.x() + actualItem->boundingRect().width() - s.width());
}
break;
}
//are we out of screen?
int screen = ((pv && pv->containment()) ? pv->containment()->screen() : -1);
if (screen == -1) {
if (pv) {
screen = pv->screen();
} else {
// fall back to asking the actual system what screen the view is on
// in the case we are dealing with a non-PlasmaView QGraphicsView
screen = QApplication::desktop()->screenNumber(v);
}
}
QRect screenRect = screenGeometry(screen);
switch (loc) {
case BottomEdge:
pos.setY(v->geometry().y() - s.height());
break;
case TopEdge:
pos.setY(v->geometry().y() + v->geometry().height());
break;
case LeftEdge:
pos.setX(v->geometry().x() + v->geometry().width());
break;
case RightEdge:
pos.setX(v->geometry().x() - s.width());
break;
default:
if (pos.y() - s.height() > screenRect.top()) {
pos.ry() = pos.y() - s.height();
} else {
pos.ry() = pos.y() + (int)actualItem->boundingRect().size().height() + 1;
}
}
//kDebug() << "==> rect for" << screen << "is" << screenRect;
if (loc != LeftEdge && pos.x() + s.width() > screenRect.x() + screenRect.width()) {
pos.rx() -= ((pos.x() + s.width()) - (screenRect.x() + screenRect.width()));
}
if (loc != TopEdge && pos.y() + s.height() > screenRect.y() + screenRect.height()) {
pos.ry() -= ((pos.y() + s.height()) - (screenRect.y() + screenRect.height()));
}
pos.rx() = qMax(0, pos.x());
pos.ry() = qMax(0, pos.y());
return pos;
}
void Corona::loadDefaultLayout()
{
}
void Corona::setPreferredToolBoxPlugin(const Containment::Type type, const QString &plugin)
{
d->toolBoxPlugins[type] = plugin;
//TODO: react to plugin changes on the fly? still don't see the use case (maybe for laptops that become tablets?)
}
QString Corona::preferredToolBoxPlugin(const Containment::Type type) const
{
return d->toolBoxPlugins.value(type);
}
ImmutabilityType Corona::immutability() const
{
return d->immutability;
}
void Corona::setImmutability(const ImmutabilityType immutable)
{
if (d->immutability == immutable || d->immutability == SystemImmutable) {
return;
}
#ifndef NDEBUG
kDebug() << "setting immutability to" << immutable;
#endif
d->immutability = immutable;
d->updateContainmentImmutability();
//tell non-containments that might care (like plasmaapp or a custom corona)
emit immutabilityChanged(immutable);
//update our actions
QAction *action = d->actions.action("lock widgets");
if (action) {
if (d->immutability == SystemImmutable) {
action->setEnabled(false);
action->setVisible(false);
} else {
bool unlocked = d->immutability == Mutable;
action->setText(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets"));
action->setIcon(KIcon(unlocked ? "object-locked" : "object-unlocked"));
action->setEnabled(true);
action->setVisible(true);
}
}
if (d->immutability != SystemImmutable) {
KConfigGroup cg(config(), "General");
// we call the dptr member directly for locked since isImmutable()
// also checks kiosk and parent containers
cg.writeEntry("immutability", (int)d->immutability);
requestConfigSync();
}
}
QList<Plasma::Location> Corona::freeEdges(int screen) const
{
QList<Plasma::Location> freeEdges;
freeEdges << Plasma::TopEdge << Plasma::BottomEdge
<< Plasma::LeftEdge << Plasma::RightEdge;
foreach (Containment *containment, containments()) {
if (containment->screen() == screen &&
freeEdges.contains(containment->location())) {
freeEdges.removeAll(containment->location());
}
}
return freeEdges;
}
QAction *Corona::action(QString name) const
{
return d->actions.action(name);
}
void Corona::addAction(QString name, QAction *action)
{
d->actions.addAction(name, action);
}
KAction* Corona::addAction(QString name)
{
return d->actions.addAction(name);
}
QList<QAction*> Corona::actions() const
{
return d->actions.actions();
}
void Corona::enableAction(const QString &name, bool enable)
{
QAction *action = d->actions.action(name);
if (action) {
action->setEnabled(enable);
action->setVisible(enable);
}
}
void Corona::updateShortcuts()
{
QMutableListIterator<QWeakPointer<KActionCollection> > it(d->actionCollections);
while (it.hasNext()) {
it.next();
KActionCollection *collection = it.value().data();
if (!collection) {
// get rid of KActionCollections that have been deleted behind our backs
it.remove();
continue;
}
collection->readSettings();
if (d->shortcutsDlg) {
d->shortcutsDlg.data()->addCollection(collection);
}
}
}
void Corona::addShortcuts(KActionCollection *newShortcuts)
{
d->actionCollections << newShortcuts;
if (d->shortcutsDlg) {
d->shortcutsDlg.data()->addCollection(newShortcuts);
}
}
void Corona::setContainmentActionsDefaults(Containment::Type containmentType, const ContainmentActionsPluginsConfig &config)
{
d->containmentActionsDefaults.insert(containmentType, config);
}
ContainmentActionsPluginsConfig Corona::containmentActionsDefaults(Containment::Type containmentType)
{
return d->containmentActionsDefaults.value(containmentType);
}
void Corona::setDialogManager(AbstractDialogManager *dialogManager)
{
d->dialogManager = dialogManager;
}
AbstractDialogManager *Corona::dialogManager()
{
return d->dialogManager.data();
}
CoronaPrivate::CoronaPrivate(Corona *corona)
: q(corona),
immutability(Mutable),
mimetype("text/x-plasmoidservicename"),
defaultContainmentPlugin("desktop"),
config(0),
actions(corona)
{
if (KGlobal::hasMainComponent()) {
configName = KGlobal::mainComponent().componentName() + "-appletsrc";
} else {
configName = "plasma-appletsrc";
}
}
CoronaPrivate::~CoronaPrivate()
{
qDeleteAll(containments);
}
void CoronaPrivate::init()
{
q->setStickyFocus(true);
configSyncTimer.setSingleShot(true);
QObject::connect(&configSyncTimer, SIGNAL(timeout()), q, SLOT(syncConfig()));
//some common actions
actions.setConfigGroup("Shortcuts");
KAction *lockAction = actions.addAction("lock widgets");
QObject::connect(lockAction, SIGNAL(triggered(bool)), q, SLOT(toggleImmutability()));
lockAction->setText(i18n("Lock Widgets"));
lockAction->setAutoRepeat(true);
lockAction->setIcon(KIcon("object-locked"));
lockAction->setData(AbstractToolBox::ControlTool);
lockAction->setShortcut(KShortcut("alt+d, l"));
lockAction->setShortcutContext(Qt::ApplicationShortcut);
//FIXME this doesn't really belong here. desktop KCM maybe?
//but should the shortcuts be per-app or really-global?
//I don't know how to make kactioncollections use plasmarc
KAction *action = actions.addAction("configure shortcuts");
QObject::connect(action, SIGNAL(triggered()), q, SLOT(showShortcutConfig()));
action->setText(i18n("Shortcut Settings"));
action->setIcon(KIcon("configure-shortcuts"));
action->setAutoRepeat(false);
action->setData(AbstractToolBox::ConfigureTool);
//action->setShortcut(KShortcut("ctrl+h"));
action->setShortcutContext(Qt::ApplicationShortcut);
//fake containment/applet actions
KActionCollection *containmentActions = AppletPrivate::defaultActions(q); //containment has to start with applet stuff
ContainmentPrivate::addDefaultActions(containmentActions); //now it's really containment
actionCollections << &actions << AppletPrivate::defaultActions(q) << containmentActions;
q->updateShortcuts();
}
void CoronaPrivate::showShortcutConfig()
{
//show a kshortcutsdialog with the actions
KShortcutsDialog *dlg = shortcutsDlg.data();
if (!dlg) {
dlg = new KShortcutsDialog();
dlg->setModal(false);
dlg->setAttribute(Qt::WA_DeleteOnClose, true);
QObject::connect(dlg, SIGNAL(saved()), q, SIGNAL(shortcutsChanged()));
dlg->addCollection(&actions);
QMutableListIterator<QWeakPointer<KActionCollection> > it(actionCollections);
while (it.hasNext()) {
it.next();
KActionCollection *collection = it.value().data();
if (!collection) {
// get rid of KActionCollections that have been deleted behind our backs
it.remove();
continue;
}
dlg->addCollection(collection);
}
}
KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
dlg->configure();
dlg->raise();
}
void CoronaPrivate::toggleImmutability()
{
if (immutability == Mutable) {
q->setImmutability(UserImmutable);
} else {
q->setImmutability(Mutable);
}
}
void CoronaPrivate::saveLayout(KSharedConfigPtr cg) const
{
KConfigGroup containmentsGroup(cg, "Containments");
foreach (const Containment *containment, containments) {
QString cid = QString::number(containment->id());
KConfigGroup containmentConfig(&containmentsGroup, cid);
containment->save(containmentConfig);
}
}
void CoronaPrivate::updateContainmentImmutability()
{
foreach (Containment *c, containments) {
// we need to tell each containment that immutability has been altered
c->updateConstraints(ImmutableConstraint);
}
}
void CoronaPrivate::containmentDestroyed(QObject *obj)
{
// we do a static_cast here since it really isn't an Containment by this
// point anymore since we are in the qobject dtor. we don't actually
// try and do anything with it, we just need the value of the pointer
// so this unsafe looking code is actually just fine.
Containment* containment = static_cast<Plasma::Containment*>(obj);
int index = containments.indexOf(containment);
if (index > -1) {
containments.removeAt(index);
q->requestConfigSync();
}
}
void CoronaPrivate::syncConfig()
{
q->config()->sync();
emit q->configSynced();
}
Containment *CoronaPrivate::addContainment(const QString &name, const QVariantList &args, uint id, bool delayedInit)
{
QString pluginName = name;
Containment *containment = 0;
Applet *applet = 0;
//kDebug() << "Loading" << name << args << id;
if (pluginName.isEmpty() || pluginName == "default") {
// default to the desktop containment
pluginName = defaultContainmentPlugin;
}
bool loadingNull = pluginName == "null";
if (!loadingNull) {
applet = PluginLoader::self()->loadApplet(pluginName, id, args);
containment = dynamic_cast<Containment*>(applet);
}
if (!containment) {
if (!loadingNull) {
#ifndef NDEBUG
kDebug() << "loading of containment" << name << "failed.";
#endif
}
// in case we got a non-Containment from Applet::loadApplet or
// a null containment was requested
if (applet) {
// the applet probably doesn't know what's hit it, so let's pretend it can be
// initialized to make assumptions in the applet's dtor safer
q->addItem(applet);
applet->init();
q->removeItem(applet);
delete applet;
}
applet = containment = new Containment(0, 0, id);
if (loadingNull) {
containment->setDrawWallpaper(false);
} else {
containment->setFailedToLaunch(false);
}
// we want to provide something and don't care about the failure to launch
containment->setFormFactor(Plasma::Planar);
}
// if this is a new containment, we need to ensure that there are no stale
// configuration data around
if (id == 0) {
KConfigGroup conf(q->config(), "Containments");
conf = KConfigGroup(&conf, QString::number(containment->id()));
conf.deleteGroup();
}
applet->d->isContainment = true;
containment->setPos(containment->d->preferredPos(q));
q->addItem(containment);
applet->d->setIsContainment(true, true);
containments.append(containment);
if (!delayedInit) {
containment->init();
KConfigGroup cg = containment->config();
containment->restore(cg);
containment->updateConstraints(Plasma::StartupCompletedConstraint);
containment->save(cg);
q->requestConfigSync();
containment->flushPendingConstraintsEvents();
}
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;
}
QList<Plasma::Containment *> CoronaPrivate::importLayout(const KConfigGroup &conf, bool mergeConfig)
{
if (!conf.isValid()) {
return QList<Containment *>();
}
QList<Plasma::Containment *> newContainments;
QSet<uint> containmentsIds;
foreach (Containment *containment, containments) {
containmentsIds.insert(containment->id());
}
KConfigGroup containmentsGroup(&conf, "Containments");
foreach (const QString &group, containmentsGroup.groupList()) {
KConfigGroup containmentConfig(&containmentsGroup, group);
if (containmentConfig.entryMap().isEmpty()) {
continue;
}
uint cid = group.toUInt();
if (containmentsIds.contains(cid)) {
cid = ++AppletPrivate::s_maxAppletId;
} else if (cid > AppletPrivate::s_maxAppletId) {
AppletPrivate::s_maxAppletId = cid;
}
if (mergeConfig) {
KConfigGroup realConf(q->config(), "Containments");
realConf = KConfigGroup(&realConf, QString::number(cid));
// in case something was there before us
realConf.deleteGroup();
containmentConfig.copyTo(&realConf);
}
//kDebug() << "got a containment in the config, trying to make a" << containmentConfig.readEntry("plugin", QString()) << "from" << group;
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Adding Containment" << containmentConfig.readEntry("plugin", QString());
#endif
Containment *c = addContainment(containmentConfig.readEntry("plugin", QString()), QVariantList(), cid, true);
if (!c) {
continue;
}
newContainments.append(c);
containmentsIds.insert(c->id());
c->init();
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Init Containment" << c->pluginName();
#endif
c->restore(containmentConfig);
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Restored Containment" << c->pluginName();
#endif
}
foreach (Containment *containment, newContainments) {
containment->updateConstraints(Plasma::StartupCompletedConstraint);
containment->d->initApplets();
emit q->containmentAdded(containment);
#ifndef NDEBUG
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Containment" << containment->name();
#endif
}
return newContainments;
}
} // namespace Plasma
+
+#include "moc_corona.cpp"
diff --git a/plasma/datacontainer.cpp b/plasma/datacontainer.cpp
index 36f08b513a..2b2ee0915a 100644
--- a/plasma/datacontainer.cpp
+++ b/plasma/datacontainer.cpp
@@ -1,359 +1,361 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "datacontainer.h"
#include "private/datacontainer_p.h"
#include "private/storage_p.h"
#include <kdebug.h>
#include "plasma.h"
namespace Plasma
{
DataContainer::DataContainer(QObject *parent)
: QObject(parent),
d(new DataContainerPrivate(this))
{
}
DataContainer::~DataContainer()
{
delete d;
}
const DataEngine::Data DataContainer::data() const
{
return d->data;
}
void DataContainer::setData(const QString &key, const QVariant &value)
{
if (!value.isValid()) {
d->data.remove(key);
} else {
d->data.insert(key, value);
}
d->dirty = true;
d->updateTs.start();
//check if storage is enabled and if storage is needed.
//If it is not set to be stored,then this is the first
//setData() since the last time it was stored. This
//gives us only one singleShot timer.
if (isStorageEnabled() || !needsToBeStored()) {
d->storageTimer.start(180000, this);
}
setNeedsToBeStored(true);
}
void DataContainer::removeAllData()
{
if (d->data.isEmpty()) {
// avoid an update if we don't have any data anyways
return;
}
d->data.clear();
d->dirty = true;
d->updateTs.start();
}
bool DataContainer::visualizationIsConnected(QObject *visualization) const
{
return d->relayObjects.contains(visualization);
}
void DataContainer::connectVisualization(QObject *visualization, uint pollingInterval,
Plasma::IntervalAlignment alignment)
{
//kDebug() << "connecting visualization" << visualization << "at interval of"
// << pollingInterval << "to" << objectName();
QMap<QObject *, SignalRelay *>::iterator objIt = d->relayObjects.find(visualization);
bool connected = objIt != d->relayObjects.end();
if (connected) {
// this visualization is already connected. just adjust the update
// frequency if necessary
SignalRelay *relay = objIt.value();
if (relay) {
// connected to a relay
//kDebug() << " already connected, but to a relay";
if (relay->m_interval == pollingInterval) {
//kDebug() << " already connected to a relay of the same interval of"
// << pollingInterval << ", nothing to do";
return;
}
if (relay->receiverCount() == 1) {
//kDebug() << " removing relay, as it is now unused";
d->relays.remove(relay->m_interval);
delete relay;
} else {
disconnect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
//relay->isUnused();
}
} else if (pollingInterval < 1) {
// the visualization was connected already, but not to a relay
// and it still doesn't want to connect to a relay, so we have
// nothing to do!
//kDebug() << " already connected, nothing to do";
return;
} else {
disconnect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
}
} else {
connect(visualization, SIGNAL(destroyed(QObject*)),
this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection);
}
if (pollingInterval < 1) {
//kDebug() << " connecting directly";
d->relayObjects[visualization] = 0;
connect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
} else {
//kDebug() << " connecting to a relay";
// we only want to do an imediate update if this is not the first object to connect to us
// if it is the first visualization, then the source will already have been populated
// engine's sourceRequested method
bool immediateUpdate = connected || d->relayObjects.count() > 1;
SignalRelay *relay = d->signalRelay(this, visualization, pollingInterval,
alignment, immediateUpdate);
connect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
}
}
void DataContainer::setStorageEnabled(bool store)
{
QTime time = QTime::currentTime();
qsrand((uint)time.msec());
d->enableStorage = store;
if (store) {
QTimer::singleShot(qrand() % (2000 + 1) , this, SLOT(retrieve()));
}
}
bool DataContainer::isStorageEnabled() const
{
return d->enableStorage;
}
bool DataContainer::needsToBeStored() const
{
return !d->isStored;
}
void DataContainer::setNeedsToBeStored(bool store)
{
d->isStored = !store;
}
DataEngine* DataContainer::getDataEngine()
{
QObject *o = NULL;
DataEngine *de = NULL;
o = this;
while (de == NULL)
{
o = dynamic_cast<QObject *> (o->parent());
if (o == NULL) {
return NULL;
}
de = dynamic_cast<DataEngine *> (o);
}
return de;
}
void DataContainerPrivate::store()
{
if (!q->needsToBeStored() || !q->isStorageEnabled()) {
return;
}
DataEngine* de = q->getDataEngine();
if (!de) {
return;
}
q->setNeedsToBeStored(false);
if (!storage) {
storage = new Storage(q);
}
KConfigGroup op = storage->operationDescription("save");
op.writeEntry("group", q->objectName());
StorageJob *job = static_cast<StorageJob *>(storage->startOperationCall(op));
job->setData(data);
storageCount++;
QObject::connect(job, SIGNAL(finished(KJob*)), q, SLOT(storeJobFinished(KJob*)));
}
void DataContainerPrivate::storeJobFinished(KJob* )
{
--storageCount;
if (storageCount < 1) {
storage->deleteLater();
storage = 0;
}
}
void DataContainerPrivate::retrieve()
{
DataEngine* de = q->getDataEngine();
if (de == NULL) {
return;
}
if (!storage) {
storage = new Storage(q);
}
KConfigGroup retrieveGroup = storage->operationDescription("retrieve");
retrieveGroup.writeEntry("group", q->objectName());
ServiceJob* retrieveJob = storage->startOperationCall(retrieveGroup);
QObject::connect(retrieveJob, SIGNAL(result(KJob*)), q,
SLOT(populateFromStoredData(KJob*)));
}
void DataContainerPrivate::populateFromStoredData(KJob *job)
{
if (job->error()) {
return;
}
StorageJob *ret = dynamic_cast<StorageJob*>(job);
if (!ret) {
return;
}
// Only fill the source with old stored
// data if it is not already populated with new data.
if (data.isEmpty() && !ret->data().isEmpty()) {
data = ret->data();
dirty = true;
q->forceImmediateUpdate();
}
KConfigGroup expireGroup = storage->operationDescription("expire");
//expire things older than 4 days
expireGroup.writeEntry("age", 345600);
storage->startOperationCall(expireGroup);
}
void DataContainer::disconnectVisualization(QObject *visualization)
{
QMap<QObject *, SignalRelay *>::iterator objIt = d->relayObjects.find(visualization);
disconnect(visualization, SIGNAL(destroyed(QObject*)),
this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection);
if (objIt == d->relayObjects.end() || !objIt.value()) {
// it is connected directly to the DataContainer itself
disconnect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
} else {
SignalRelay *relay = objIt.value();
if (relay->receiverCount() == 1) {
d->relays.remove(relay->m_interval);
delete relay;
} else {
disconnect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
}
}
d->relayObjects.erase(objIt);
d->checkUsage();
}
void DataContainer::checkForUpdate()
{
//kDebug() << objectName() << d->dirty;
if (d->dirty) {
emit dataUpdated(objectName(), d->data);
foreach (SignalRelay *relay, d->relays) {
relay->checkQueueing();
}
d->dirty = false;
}
}
void DataContainer::forceImmediateUpdate()
{
if (d->dirty) {
d->dirty = false;
emit dataUpdated(objectName(), d->data);
}
foreach (SignalRelay *relay, d->relays) {
relay->forceImmediateUpdate();
}
}
uint DataContainer::timeSinceLastUpdate() const
{
//FIXME: we still assume it's been <24h
//and ignore possible daylight savings changes
return d->updateTs.elapsed();
}
void DataContainer::setNeedsUpdate(bool update)
{
d->cached = update;
}
bool DataContainer::isUsed() const
{
return !d->relays.isEmpty() &&
receivers(SIGNAL(dataUpdated(QString, Plasma::DataEngine::Data))) > 0;
}
void DataContainerPrivate::checkUsage()
{
if (!checkUsageTimer.isActive()) {
checkUsageTimer.start(10, q);
}
}
void DataContainer::timerEvent(QTimerEvent * event)
{
if (event->timerId() == d->checkUsageTimer.timerId()) {
if (!isUsed()) {
// DO NOT CALL ANYTHING AFTER THIS LINE AS IT MAY GET DELETED!
//kDebug() << objectName() << "is unused";
emit becameUnused(objectName());
}
d->checkUsageTimer.stop();
} else if (event->timerId() == d->storageTimer.timerId()) {
d->store();
d->storageTimer.stop();
}
}
} // Plasma namespace
+
+#include "moc_datacontainer.cpp"
diff --git a/plasma/dataengine.cpp b/plasma/dataengine.cpp
index 680abe7ac2..0da11e53fd 100644
--- a/plasma/dataengine.cpp
+++ b/plasma/dataengine.cpp
@@ -1,712 +1,714 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "dataengine.h"
#include "private/dataengine_p.h"
#include "private/datacontainer_p.h"
#include <QQueue>
#include <QTimer>
#include <QTime>
#include <QTimerEvent>
#include <QVariant>
#include <kdebug.h>
#include <kplugininfo.h>
#include <kservice.h>
#include <kstandarddirs.h>
#include "datacontainer.h"
#include "package.h"
#include "pluginloader.h"
#include "remote/authorizationmanager.h"
#include "remote/authorizationmanager_p.h"
#include "service.h"
#include "scripting/dataenginescript.h"
#include "private/datacontainer_p.h"
#include "private/dataengineservice_p.h"
#include "private/remotedataengine_p.h"
#include "private/service_p.h"
#include "private/storage_p.h"
namespace Plasma
{
DataEngine::DataEngine(QObject *parent, KService::Ptr service)
: QObject(parent),
d(new DataEnginePrivate(this, KPluginInfo(service)))
{
}
DataEngine::DataEngine(QObject *parent, const QVariantList &args)
: QObject(parent),
d(new DataEnginePrivate(this, KPluginInfo(KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()))))
{
}
DataEngine::~DataEngine()
{
//kDebug() << objectName() << ": bye bye birdy! ";
delete d;
}
QStringList DataEngine::sources() const
{
if (d->script) {
return d->script->sources();
} else {
return d->sources.keys();
}
}
Service *DataEngine::serviceForSource(const QString &source)
{
if (d->script) {
Service * s = d->script->serviceForSource(source);
if (s) {
return s;
}
}
return new NullService(source, this);
}
void DataEngine::connectSource(const QString &source, QObject *visualization,
uint pollingInterval,
Plasma::IntervalAlignment intervalAlignment) const
{
//kDebug() << "connectSource" << source;
bool newSource;
DataContainer *s = d->requestSource(source, &newSource);
if (s) {
// we suppress the immediate invocation of dataUpdated here if the
// source was prexisting and they don't request delayed updates
// (we want to do an immediate update in that case so they don't
// have to wait for the first time out)
if (newSource && !s->data().isEmpty()) {
newSource = false;
}
d->connectSource(s, visualization, pollingInterval, intervalAlignment,
!newSource || pollingInterval > 0);
//kDebug() << " ==> source connected";
}
}
void DataEngine::connectAllSources(QObject *visualization, uint pollingInterval,
Plasma::IntervalAlignment intervalAlignment) const
{
foreach (DataContainer *s, d->sources) {
d->connectSource(s, visualization, pollingInterval, intervalAlignment);
}
}
void DataEngine::disconnectSource(const QString &source, QObject *visualization) const
{
DataContainer *s = d->source(source, false);
if (s) {
s->disconnectVisualization(visualization);
}
}
DataContainer *DataEngine::containerForSource(const QString &source)
{
return d->source(source, false);
}
DataEngine::Data DataEngine::query(const QString &source) const
{
bool newSource;
DataContainer *s = d->requestSource(source, &newSource);
if (!s) {
return DataEngine::Data();
} else if (!newSource && d->minPollingInterval >= 0 &&
s->timeSinceLastUpdate() >= uint(d->minPollingInterval)) {
DataEngine *unconstThis = const_cast<DataEngine*>(this);
if (unconstThis->updateSourceEvent(source)) {
unconstThis->scheduleSourcesUpdated();
}
}
DataEngine::Data data = s->data();
s->d->checkUsage();
return data;
}
void DataEngine::init()
{
if (d->script) {
d->setupScriptSupport();
d->script->init();
} else {
// kDebug() << "called";
// default implementation does nothing. this is for engines that have to
// start things in motion external to themselves before they can work
}
}
bool DataEngine::sourceRequestEvent(const QString &name)
{
if (d->script) {
return d->script->sourceRequestEvent(name);
} else {
return false;
}
}
bool DataEngine::updateSourceEvent(const QString &source)
{
if (d->script) {
return d->script->updateSourceEvent(source);
} else {
//kDebug() << source;
return false; //TODO: should this be true to trigger, even needless, updates on every tick?
}
}
void DataEngine::setData(const QString &source, const QVariant &value)
{
setData(source, source, value);
}
void DataEngine::setData(const QString &source, const QString &key, const QVariant &value)
{
DataContainer *s = d->source(source, false);
bool isNew = !s;
if (isNew) {
s = d->source(source);
}
s->setData(key, value);
if (isNew && source != d->waitingSourceRequest) {
emit sourceAdded(source);
}
scheduleSourcesUpdated();
}
void DataEngine::setData(const QString &source, const Data &data)
{
DataContainer *s = d->source(source, false);
bool isNew = !s;
if (isNew) {
s = d->source(source);
}
Data::const_iterator it = data.constBegin();
while (it != data.constEnd()) {
s->setData(it.key(), it.value());
++it;
}
if (isNew && source != d->waitingSourceRequest) {
emit sourceAdded(source);
}
scheduleSourcesUpdated();
}
void DataEngine::removeAllData(const QString &source)
{
DataContainer *s = d->source(source, false);
if (s) {
s->removeAllData();
scheduleSourcesUpdated();
}
}
void DataEngine::removeData(const QString &source, const QString &key)
{
DataContainer *s = d->source(source, false);
if (s) {
s->setData(key, QVariant());
scheduleSourcesUpdated();
}
}
void DataEngine::addSource(DataContainer *source)
{
if (d->sources.contains(source->objectName())) {
#ifndef NDEBUG
kDebug() << "source named \"" << source->objectName() << "\" already exists.";
#endif
return;
}
QObject::connect(source, SIGNAL(updateRequested(DataContainer*)),
this, SLOT(internalUpdateSource(DataContainer*)));
QObject::connect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
d->sources.insert(source->objectName(), source);
emit sourceAdded(source->objectName());
scheduleSourcesUpdated();
}
void DataEngine::setMinimumPollingInterval(int minimumMs)
{
d->minPollingInterval = minimumMs;
}
int DataEngine::minimumPollingInterval() const
{
return d->minPollingInterval;
}
void DataEngine::setPollingInterval(uint frequency)
{
killTimer(d->updateTimerId);
d->updateTimerId = 0;
if (frequency > 0) {
d->updateTimerId = startTimer(frequency);
}
}
void DataEngine::removeSource(const QString &source)
{
SourceDict::iterator it = d->sources.find(source);
if (it != d->sources.end()) {
DataContainer *s = it.value();
s->d->store();
s->disconnect(this);
s->deleteLater();
d->sources.erase(it);
emit sourceRemoved(source);
}
}
void DataEngine::removeAllSources()
{
QMutableHashIterator<QString, Plasma::DataContainer*> it(d->sources);
while (it.hasNext()) {
it.next();
Plasma::DataContainer *s = it.value();
const QString source = it.key();
it.remove();
s->disconnect(this);
s->deleteLater();
emit sourceRemoved(source);
}
}
bool DataEngine::isValid() const
{
return d->valid;
}
bool DataEngine::isEmpty() const
{
return d->sources.isEmpty();
}
void DataEngine::setValid(bool valid)
{
d->valid = valid;
}
DataEngine::SourceDict DataEngine::containerDict() const
{
return d->sources;
}
void DataEngine::timerEvent(QTimerEvent *event)
{
//kDebug();
if (event->timerId() == d->updateTimerId) {
// if the freq update is less than 0, don't bother
if (d->minPollingInterval < 0) {
//kDebug() << "uh oh.. no polling allowed!";
return;
}
// minPollingInterval
if (d->updateTimestamp.elapsed() < d->minPollingInterval) {
//kDebug() << "hey now.. slow down!";
return;
}
d->updateTimestamp.restart();
updateAllSources();
} else if (event->timerId() == d->checkSourcesTimerId) {
killTimer(d->checkSourcesTimerId);
d->checkSourcesTimerId = 0;
QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
while (it.hasNext()) {
it.next();
it.value()->checkForUpdate();
}
} else {
QObject::timerEvent(event);
}
}
void DataEngine::updateAllSources()
{
QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
while (it.hasNext()) {
it.next();
//kDebug() << "updating" << it.key();
updateSourceEvent(it.key());
}
scheduleSourcesUpdated();
}
void DataEngine::forceImmediateUpdateOfAllVisualizations()
{
foreach (DataContainer *source, d->sources) {
source->forceImmediateUpdate();
}
}
void DataEngine::setIcon(const QString &icon)
{
d->icon = icon;
}
QString DataEngine::icon() const
{
return d->icon;
}
QString DataEngine::pluginName() const
{
if (!d->dataEngineDescription.isValid()) {
return QString();
}
return d->dataEngineDescription.pluginName();
}
void DataEngine::setDefaultService(const QString &serviceName)
{
d->serviceName = serviceName;
}
Service* DataEngine::createDefaultService(QObject *parent)
{
QVariantList args;
args << QVariant::fromValue<DataEngine*>(this);
return PluginLoader::self()->loadService(d->serviceName, args, parent);
}
void DataEnginePrivate::publish(AnnouncementMethods methods, const QString &name)
{
if (!publishedService) {
publishedService = new DataEngineService(q);
}
//QString resourceName =
//i18nc("%1 is the name of a dataengine, %2 the name of the machine that engine is published
//on",
//"%1 dataengine on %2", name(), AuthorizationManager::self()->d->myCredentials.name());
#ifndef NDEBUG
kDebug() << "name: " << name;
#endif
publishedService->d->publish(methods, name);
}
void DataEnginePrivate::unpublish(const QString &name)
{
Q_UNUSED(name)
if (publishedService) {
publishedService->d->unpublish();
}
}
bool DataEnginePrivate::isPublished() const
{
if (publishedService) {
return publishedService->d->isPublished();
} else {
return false;
}
}
Package DataEngine::package() const
{
return d->package ? *d->package : Package();
}
void DataEngine::scheduleSourcesUpdated()
{
if (d->checkSourcesTimerId) {
return;
}
d->checkSourcesTimerId = startTimer(0);
}
QString DataEngine::name() const
{
return d->engineName;
}
void DataEngine::setName(const QString &name)
{
d->engineName = name;
setObjectName(name);
}
void DataEngine::setStorageEnabled(const QString &source, bool store)
{
DataContainer *s = d->source(source, false);
if (s) {
s->setStorageEnabled(store);
}
}
// Private class implementations
DataEnginePrivate::DataEnginePrivate(DataEngine *e, const KPluginInfo &info)
: q(e),
dataEngineDescription(info),
refCount(-1), // first ref
checkSourcesTimerId(0),
updateTimerId(0),
minPollingInterval(-1),
valid(true),
script(0),
package(0),
publishedService(0)
{
updateTimestamp.start();
if (!info.isValid()) {
engineName = i18n("Unnamed");
return;
}
engineName = info.name();
if (engineName.isEmpty()) {
engineName = i18n("Unnamed");
}
e->setObjectName(engineName);
icon = info.icon();
if (dataEngineDescription.isValid()) {
QString api = dataEngineDescription.property("X-Plasma-API").toString();
if (!api.isEmpty()) {
const QString path =
KStandardDirs::locate("data",
"plasma/dataengines/" + dataEngineDescription.pluginName() + '/');
package = new Package(PluginLoader::self()->loadPackage("Plasma/DataEngine", api));
package->setPath(path);
if (package->isValid()) {
script = Plasma::loadScriptEngine(api, q);
}
if (!script) {
#ifndef NDEBUG
kDebug() << "Could not create a" << api << "ScriptEngine for the"
<< dataEngineDescription.name() << "DataEngine.";
#endif
delete package;
package = 0;
}
}
}
}
DataEnginePrivate::~DataEnginePrivate()
{
delete script;
script = 0;
delete package;
package = 0;
}
void DataEnginePrivate::internalUpdateSource(DataContainer *source)
{
if (minPollingInterval > 0 &&
source->timeSinceLastUpdate() < (uint)minPollingInterval) {
// skip updating this source; it's been too soon
//kDebug() << "internal update source is delaying" << source->timeSinceLastUpdate() << minPollingInterval;
//but fake an update so that the signalrelay that triggered this gets the data from the
//recent update. this way we don't have to worry about queuing - the relay will send a
//signal immediately and everyone else is undisturbed.
source->setNeedsUpdate();
return;
}
if (q->updateSourceEvent(source->objectName())) {
//kDebug() << "queuing an update";
q->scheduleSourcesUpdated();
}/* else {
#ifndef NDEBUG
kDebug() << "no update";
#endif
}*/
}
void DataEnginePrivate::ref()
{
--refCount;
}
void DataEnginePrivate::deref()
{
++refCount;
}
bool DataEnginePrivate::isUsed() const
{
return refCount != 0;
}
DataContainer *DataEnginePrivate::source(const QString &sourceName, bool createWhenMissing)
{
DataEngine::SourceDict::const_iterator it = sources.constFind(sourceName);
if (it != sources.constEnd()) {
DataContainer *s = it.value();
return s;
}
if (!createWhenMissing) {
return 0;
}
//kDebug() << "DataEngine " << q->objectName() << ": could not find DataContainer " << sourceName << ", creating";
DataContainer *s = new DataContainer(q);
s->setObjectName(sourceName);
sources.insert(sourceName, s);
QObject::connect(s, SIGNAL(destroyed(QObject *)), q, SLOT(sourceDestroyed(QObject *)));
QObject::connect(s, SIGNAL(updateRequested(DataContainer*)),
q, SLOT(internalUpdateSource(DataContainer*)));
return s;
}
void DataEnginePrivate::connectSource(DataContainer *s, QObject *visualization,
uint pollingInterval,
Plasma::IntervalAlignment align,
bool immediateCall)
{
//kDebug() << "connect source called" << s->objectName() << "with interval" << pollingInterval;
//FIXME: at the moment a remote dataengine can only poll, a push mechanism will be needed instead
if (pollingInterval == 0 && qobject_cast<RemoteDataEngine *>(q)) {
pollingInterval = 5000;
}
if (pollingInterval > 0) {
// never more frequently than allowed, never more than 20 times per second
uint min = qMax(50, minPollingInterval); // for qMax below
pollingInterval = qMax(min, pollingInterval);
// align on the 50ms
pollingInterval = pollingInterval - (pollingInterval % 50);
}
if (immediateCall) {
// we don't want to do an immediate call if we are simply
// reconnecting
//kDebug() << "immediate call requested, we have:" << s->visualizationIsConnected(visualization);
immediateCall = !s->data().isEmpty() &&
!s->visualizationIsConnected(visualization);
}
s->connectVisualization(visualization, pollingInterval, align);
if (immediateCall) {
QMetaObject::invokeMethod(visualization, "dataUpdated",
Q_ARG(QString, s->objectName()),
Q_ARG(Plasma::DataEngine::Data, s->data()));
s->d->dirty = false;
}
}
void DataEnginePrivate::sourceDestroyed(QObject *object)
{
DataEngine::SourceDict::iterator it = sources.begin();
while (it != sources.end()) {
if (it.value() == object) {
sources.erase(it);
emit q->sourceRemoved(object->objectName());
break;
}
++it;
}
}
DataContainer *DataEnginePrivate::requestSource(const QString &sourceName, bool *newSource)
{
if (newSource) {
*newSource = false;
}
//kDebug() << "requesting source " << sourceName;
DataContainer *s = source(sourceName, false);
if (!s) {
// we didn't find a data source, so give the engine an opportunity to make one
/*kDebug() << "DataEngine " << q->objectName()
<< ": could not find DataContainer " << sourceName
<< " will create on request" << endl;*/
waitingSourceRequest = sourceName;
if (q->sourceRequestEvent(sourceName)) {
s = source(sourceName, false);
if (s) {
// now we have a source; since it was created on demand, assume
// it should be removed when not used
if (newSource) {
*newSource = true;
}
QObject::connect(s, SIGNAL(becameUnused(QString)), q, SLOT(removeSource(QString)));
emit q->sourceAdded(sourceName);
}
}
waitingSourceRequest.clear();
}
return s;
}
// put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engine
void DataEnginePrivate::setupScriptSupport()
{
if (!package) {
return;
}
/*
#ifndef NDEBUG
kDebug() << "sletting up script support, package is in" << package->path()
#endif
<< "which is a" << package->structure()->type() << "package"
<< ", main script is" << package->filePath("mainscript");
*/
const QString translationsPath = package->filePath("translations");
if (!translationsPath.isEmpty()) {
KGlobal::dirs()->addResourceDir("locale", translationsPath);
KGlobal::locale()->insertCatalog(dataEngineDescription.pluginName());
}
}
}
+
+#include "moc_dataengine.cpp"
diff --git a/plasma/dataenginemanager.cpp b/plasma/dataenginemanager.cpp
index aa7e33f29b..afff5a076b 100644
--- a/plasma/dataenginemanager.cpp
+++ b/plasma/dataenginemanager.cpp
@@ -1,252 +1,254 @@
/*
* 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 <QFile>
#include <QTextStream>
#include <kdebug.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kservicetypetrader.h>
#include "datacontainer.h"
#include "pluginloader.h"
#include "private/componentinstaller_p.h"
#include "private/dataengine_p.h"
#include "private/datacontainer_p.h"
#include "scripting/scriptengine.h"
namespace Plasma
{
class NullEngine : public DataEngine
{
public:
NullEngine(QObject *parent = 0)
: DataEngine(parent)
{
setValid(false);
// ref() ourselves to ensure we never get deleted
d->ref();
}
};
class DataEngineManagerPrivate
{
public:
DataEngineManagerPrivate()
: nullEng(0)
{}
~DataEngineManagerPrivate()
{
foreach (Plasma::DataEngine *engine, engines) {
delete engine;
}
engines.clear();
delete nullEng;
}
DataEngine *nullEngine()
{
if (!nullEng) {
nullEng = new NullEngine;
}
return nullEng;
}
DataEngine::Dict engines;
DataEngine *nullEng;
};
class DataEngineManagerSingleton
{
public:
DataEngineManager self;
};
K_GLOBAL_STATIC(DataEngineManagerSingleton, privateDataEngineManagerSelf)
DataEngineManager *DataEngineManager::self()
{
return &privateDataEngineManagerSelf->self;
}
DataEngineManager::DataEngineManager()
: d(new DataEngineManagerPrivate)
{
//startTimer(30000);
}
DataEngineManager::~DataEngineManager()
{
delete d;
}
Plasma::DataEngine *DataEngineManager::engine(const QString &name) const
{
if (name.isEmpty()) {
return d->nullEngine();
}
Plasma::DataEngine::Dict::const_iterator it = d->engines.constFind(name);
if (it != d->engines.constEnd()) {
// ref and return the engine
//Plasma::DataEngine *engine = *it;
return *it;
}
return d->nullEngine();
}
Plasma::DataEngine *DataEngineManager::loadEngine(const QString &name)
{
Plasma::DataEngine::Dict::const_iterator it = d->engines.constFind(name);
if (it != d->engines.constEnd()) {
DataEngine *engine = *it;
engine->d->ref();
return engine;
}
DataEngine *engine = PluginLoader::self()->loadDataEngine(name);
if (!engine) {
// Try installing the engine. However, it's too late for this request.
ComponentInstaller::self()->installMissingComponent("dataengine", name);
return d->nullEngine();
}
engine->init();
d->engines[name] = engine;
return engine;
}
void DataEngineManager::unloadEngine(const QString &name)
{
Plasma::DataEngine::Dict::iterator it = d->engines.find(name);
if (it != d->engines.end()) {
Plasma::DataEngine *engine = *it;
engine->d->deref();
if (!engine->d->isUsed()) {
d->engines.erase(it);
delete engine;
}
}
}
QStringList DataEngineManager::listAllEngines(const QString &parentApp)
{
QString constraint;
if (parentApp.isEmpty()) {
constraint.append("(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
} else {
constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
QStringList engines;
foreach (const KService::Ptr &service, offers) {
QString name = service->property("X-KDE-PluginInfo-Name").toString();
if (!name.isEmpty()) {
engines.append(name);
}
}
return engines;
}
KPluginInfo::List DataEngineManager::listEngineInfo(const QString &parentApp)
{
return PluginLoader::self()->listDataEngineInfo(parentApp);
}
KPluginInfo::List DataEngineManager::listEngineInfoByCategory(const QString &category, const QString &parentApp)
{
QString constraint = QString("[X-KDE-PluginInfo-Category] == '%1'").arg(category);
if (parentApp.isEmpty()) {
constraint.append(" and not exist [X-KDE-ParentApp]");
} else {
constraint.append(" and [X-KDE-ParentApp] == '").append(parentApp).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
return KPluginInfo::fromServices(offers);
}
void DataEngineManager::timerEvent(QTimerEvent *)
{
#ifndef NDEBUG
QString path = KGlobal::dirs()->locateLocal("appdata", "plasma_dataenginemanager_log");
QFile f(path);
if (!f.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
kDebug() << "faild to open" << path;
return;
}
QTextStream out(&f);
QHashIterator<QString, DataEngine*> it(d->engines);
out << "================================== " << KGlobal::locale()->formatDateTime(QDateTime::currentDateTime()) << endl;
while (it.hasNext()) {
it.next();
DataEngine *engine = it.value();
out << "DataEngine: " << it.key() << ' ' << engine << endl;
out << " Claimed # of sources: " << engine->sources().count() << endl;
out << " Actual # of sources: " << engine->containerDict().count() << endl;
out << endl << " Source Details" << endl;
foreach (DataContainer *dc, engine->containerDict()) {
out << " * " << dc->objectName() << endl;
out << " Data count: " << dc->d->data.count() << endl;
out << " Stored: " << dc->isStorageEnabled() << ' ' << endl;
const int directs = dc->receivers(SIGNAL(dataUpdated(QString, Plasma::DataEngine::Data)));
if (directs > 0) {
out << " Direction Connections: " << directs << ' ' << endl;
}
const int relays = dc->d->relays.count();
if (relays > 0) {
out << " Relays: " << dc->d->relays.count() << endl;
QString times;
foreach (SignalRelay *relay, dc->d->relays) {
times.append(' ').append(QString::number(relay->m_interval));
}
out << " Relay Timeouts: " << times << ' ' << endl;
}
}
out << endl << "-----" << endl;
}
out << endl << endl;
#endif
// killTimer(event->timerId());
}
} // namespace Plasma
+
+#include "moc_dataenginemanager.cpp"
diff --git a/plasma/delegate.cpp b/plasma/delegate.cpp
index bdf8c5a7f3..96ce661af5 100644
--- a/plasma/delegate.cpp
+++ b/plasma/delegate.cpp
@@ -1,492 +1,494 @@
/*
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.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kglobalsettings.h>
#include <kcolorscheme.h>
// plasma
#include <plasma/paintutils.h>
#include <plasma/framesvg.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;
bool m_showToolTip;
FrameSvg *svg;
};
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)
{
d->svg = new FrameSvg(this);
d->svg->setImagePath("widgets/viewitem");
d->svg->setElementPrefix("hover");
}
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>();
//kDebug() << subTitleText;
QRect titleRect = d->titleRect(option, index);
titleRect.moveTopLeft(titleRect.topLeft()-option.rect.topLeft());
QRect subTitleRect = d->subTitleRect(option, index);
subTitleRect.moveTopLeft(subTitleRect.topLeft()-option.rect.topLeft());
if (subTitleText == titleText) {
subTitleText.clear();
}
QFont titleFont(option.font);
// 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);
}
QPixmap buffer(option.rect.size());
buffer.fill(Qt::transparent);
QPainter p(&buffer);
// draw title
p.setFont(titleFont);
if (option.palette.color(QPalette::Base).alpha() > 0) {
p.setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::NormalText), 1));
} else {
p.setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
}
p.drawText(titleRect, Qt::AlignLeft|Qt::AlignVCenter, titleText);
// draw sub-title, BUT only if:
// * SubTitleMandatoryRole is defined and model returns 'true'
// * SubTitleMandatoryRole is not defined and the adjasent model indexes
// have the same contents of the Qt::DisplayRole
// * when model doesn't provide a valid data for SubTitleMandatory role
// we also show title on mouse hover
//
// the rationale 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.
bool drawSubTitle = !subTitleText.isEmpty();
if (drawSubTitle && !hover) {
// If the model wants to have exact control for subtitles showing
// it is expected to return a valid data for SubTitleMandatoryRole.
// If it doesn't return a valid data for this role
// then by default we well be showing a subtitles for
// adjasent items with the same content (see comments below too)
QVariant mandatoryRoleData = index.data(d->roles[SubTitleMandatoryRole]);
if (mandatoryRoleData.isValid()) {
drawSubTitle = mandatoryRoleData.value<bool>();
} else {
bool uniqueTitle = true;
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;
}
}
drawSubTitle = !uniqueTitle;
}
}
if (drawSubTitle) {
if (option.palette.color(QPalette::Base).alpha() > 0) {
p.setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText), 1));
} else {
QColor textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
textColor.setAlphaF(0.6);
p.setPen(textColor);
}
const QFont subTitleFont = d->fontForSubTitle(option.font);
p.setFont(subTitleFont);
p.drawText(subTitleRect, Qt::AlignLeft|Qt::AlignVCenter, subTitleText);
}
p.end();
d->m_showToolTip = false;
const QColor gradientColor = KColorScheme(QPalette::Active).background(KColorScheme::NormalBackground).color();
if (option.direction == Qt::LeftToRight) {
if (((titleRect.width() + decorationRect.width() + 10) > option.rect.width() ||
(subTitleRect.width() + decorationRect.width() + 15) > option.rect.width()) &&
(titleRect.width() > 120 || subTitleRect.width() > 120)) {
QPainter p(&buffer);
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
p.setPen(Qt::NoPen);
QLinearGradient gr;
QRect gradientRect(option.rect.width() - 60, titleRect.y(),
80, titleRect.height() + subTitleRect.height());
// draw it on the right side
gr.setStart(gradientRect.topLeft());
gr.setFinalStop(gradientRect.topRight());
gr.setColorAt(0.0, Qt::transparent);
gr.setColorAt(0.7, gradientColor);
p.setBrush(QBrush(gr));
p.drawRect(gradientRect);
d->m_showToolTip = true;
p.end();
}
} else {
if (((titleRect.width() + decorationRect.width() + 10) > option.rect.width() ||
(subTitleRect.width() + decorationRect.width() + 15 )> option.rect.width()) &&
(titleRect.width() > 120 || subTitleRect.width() > 120)) {
buffer.fill(Qt::transparent);
QPainter p(&buffer);
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
p.setPen(Qt::NoPen);
QLinearGradient gr;
QRect gradientRect(option.rect.x() - 55, titleRect.y(),
60, titleRect.height() + subTitleRect.height());
gr.setStart(gradientRect.topRight());
gr.setFinalStop(gradientRect.topLeft());
gr.setColorAt(0.0, Qt::transparent);
gr.setColorAt(0.6, gradientColor);
p.setBrush(QBrush(gr));
p.drawRect(gradientRect);
d->m_showToolTip = true;
p.end();
}
}
painter->drawPixmap(option.rect, buffer, buffer.rect());
if (hover) {
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
const int column = index.column();
const int columns = index.model()->columnCount();
int roundedRadius = 5;
const bool useSvg = option.palette.color(QPalette::Base).alpha() == 0;
// 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);
backgroundColor2.setAlphaF(0.5);
QRect highlightRect = option.rect;
if (!useSvg) {
highlightRect.adjust(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 (useSvg) {
roundedRadius = d->svg->marginSize(Plasma::RightMargin);
}
painter->setClipRect(option.rect);
highlightRect.adjust(0, 0, roundedRadius, 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 (useSvg) {
roundedRadius = d->svg->marginSize(Plasma::LeftMargin);
}
painter->setClipRect(option.rect);
highlightRect.adjust(-roundedRadius, 0, 0, 0);
//column < columns-1; clip both ways
} else {
if (useSvg) {
roundedRadius = d->svg->marginSize(Plasma::LeftMargin);
}
painter->setClipRect(option.rect);
highlightRect.adjust(-roundedRadius, 0, +roundedRadius, 0);
}
//if the view is transparent paint as plasma, otherwise paint with kde colors
if (useSvg) {
d->svg->resizeFrame(highlightRect.size());
d->svg->paintFrame(painter, highlightRect.topLeft());
} else {
painter->setPen(outlinePen);
painter->drawPath(PaintUtils::roundedRectangle(highlightRect, roundedRadius));
}
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());
const bool useSvg = option.palette.color(QPalette::Base).alpha() == 0;
if (useSvg) {
qreal left, top, right, bottom;
d->svg->getMargins(left, top, right, bottom);
size += QSize(left+right, top+bottom);
} else {
size *= 1.1;
}
return size;
}
bool Delegate::showToolTip() const
{
return d->m_showToolTip;
}
}
+
+#include "moc_delegate.cpp"
diff --git a/plasma/dialog.cpp b/plasma/dialog.cpp
index 59e1a84619..5e45a54a6e 100644
--- a/plasma/dialog.cpp
+++ b/plasma/dialog.cpp
@@ -1,870 +1,872 @@
/*
* 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 "private/dialog_p.h"
#include <QPainter>
#include <QSvgRenderer>
#include <QResizeEvent>
#include <QMouseEvent>
#ifdef Q_WS_X11
#include <QX11Info>
#endif
#include <QBitmap>
#include <QTimer>
#include <QVBoxLayout>
#include <QGraphicsSceneEvent>
#include <QGraphicsView>
#include <QGraphicsWidget>
#include <QApplication>
#include <QDesktopWidget>
#include <QVarLengthArray>
#include <QGraphicsLayout>
#include <kdebug.h>
#include <kwindowsystem.h>
#include <netwm.h>
#include "plasma/applet.h"
#include "plasma/animator.h"
#include "plasma/containment.h"
#include "plasma/corona.h"
#include "plasma/framesvg.h"
#include "plasma/theme.h"
#include "plasma/widgets/scrollwidget.h"
#include "plasma/windoweffects.h"
#include "plasma/private/windowshadows_p.h"
#ifdef Q_WS_X11
#include <X11/Xlib.h>
#endif
namespace Plasma
{
void DialogPrivate::scheduleBorderCheck(bool triggeredByResize)
{
//kDebug();
if (triggeredByResize) {
resizeChecksWithBorderCheck = true;
// to keep the UI as fluid as possible, we call checkBorders
// immediately when there is a resize, and therefore stop any
// move-triggered scheduled calls to it. this keeps things
// looking reasonable during resize while avoiding as many
// calls to checkBorders as possible
if (moveTimer) {
moveTimer->stop();
}
checkBorders();
return;
}
if (!moveTimer) {
moveTimer = new QTimer(q);
moveTimer->setSingleShot(true);
QObject::connect(moveTimer, SIGNAL(timeout()), q, SLOT(checkBorders()));
}
moveTimer->start(0);
}
void DialogPrivate::themeChanged()
{
checkBorders(false);
if (background->hasElement("shadow-top")) {
WindowShadows::self()->addWindow(q);
} else {
WindowShadows::self()->removeWindow(q);
}
const bool translucency = Plasma::Theme::defaultTheme()->windowTranslucencyEnabled();
// WA_NoSystemBackground is going to fail combined with sliding popups, but is needed
// when we aren't compositing
q->setAttribute(Qt::WA_NoSystemBackground, !translucency);
updateMask();
q->update();
}
void DialogPrivate::updateMask()
{
const bool translucency = Plasma::Theme::defaultTheme()->windowTranslucencyEnabled();
WindowEffects::enableBlurBehind(q->winId(), translucency,
translucency ? background->mask() : QRegion());
if (translucency) {
q->clearMask();
} else {
q->setMask(background->mask());
}
}
void DialogPrivate::checkBorders()
{
checkBorders(true);
}
void DialogPrivate::delayedAdjustSize()
{
q->syncToGraphicsWidget();
}
void DialogPrivate::checkBorders(bool updateMaskIfNeeded)
{
if (resizeChecksWithBorderCheck) {
background->resizeFrame(q->size());
}
QGraphicsWidget *graphicsWidget = graphicsWidgetPtr.data();
const FrameSvg::EnabledBorders currentBorders = background->enabledBorders();
FrameSvg::EnabledBorders borders = FrameSvg::AllBorders;
Plasma::Applet *applet = appletPtr.data();
//used to remove borders at the edge of the desktop
QRect avail;
QRect screenGeom;
QDesktopWidget *desktop = QApplication::desktop();
Plasma::Corona *c = 0;
if (applet) {
c = qobject_cast<Plasma::Corona *>(applet->scene());
} else if (graphicsWidget) {
c = qobject_cast<Plasma::Corona *>(graphicsWidget->scene());
}
if (c) {
QRegion r = c->availableScreenRegion(desktop->screenNumber(q));
QRect maxRect;
foreach (QRect rect, r.rects()) {
if (rect.width() > maxRect.width() && rect.height() > maxRect.height()) {
maxRect = rect;
}
}
avail = maxRect;
screenGeom = c->screenGeometry(desktop->screenNumber(q));
} else {
avail = desktop->availableGeometry(desktop->screenNumber(q));
screenGeom = desktop->screenGeometry(desktop->screenNumber(q));
}
QRect dialogGeom = q->geometry();
qreal topHeight(0);
qreal leftWidth(0);
qreal rightWidth(0);
qreal bottomHeight(0);
//decide about disabling the border attached to the panel
if (applet) {
background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight);
switch (applet->location()) {
case BottomEdge:
if (applet->containment() &&
dialogGeom.bottom() + 2 >= screenGeom.bottom() - applet->containment()->size().height() &&
dialogGeom.width() <= applet->containment()->size().width()) {
borders &= ~FrameSvg::BottomBorder;
leftWidth = 0;
rightWidth = 0;
bottomHeight = 0;
}
break;
case TopEdge:
if (applet->containment() &&
dialogGeom.top() <= screenGeom.top() + applet->containment()->size().height() &&
dialogGeom.width() <= applet->containment()->size().width()) {
borders &= ~FrameSvg::TopBorder;
topHeight = 0;
leftWidth = 0;
rightWidth = 0;
}
break;
case LeftEdge:
if (applet->containment() &&
dialogGeom.left() <= screenGeom.left() + applet->containment()->size().width() &&
dialogGeom.height() <= applet->containment()->size().height()) {
borders &= ~FrameSvg::LeftBorder;
leftWidth = 0;
rightWidth = 0;
}
break;
case RightEdge:
if (applet->containment() &&
dialogGeom.right() + 2 >= screenGeom.right() - applet->containment()->size().width() &&
dialogGeom.height() <= applet->containment()->size().height()) {
borders &= ~FrameSvg::RightBorder;
leftWidth = 0;
rightWidth = 0;
}
break;
default:
break;
}
}
//decide if to disable the other borders
if (q->isVisible()) {
if (dialogGeom.left() <= avail.left()) {
borders &= ~FrameSvg::LeftBorder;
}
if (dialogGeom.top() <= avail.top()) {
borders &= ~FrameSvg::TopBorder;
}
//FIXME: that 2 pixels offset has probably something to do with kwin
if (dialogGeom.right() + 2 > avail.right()) {
borders &= ~FrameSvg::RightBorder;
}
if (dialogGeom.bottom() + 2 > avail.bottom()) {
borders &= ~FrameSvg::BottomBorder;
}
}
background->setEnabledBorders(borders);
background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight);
//kDebug() << leftWidth << topHeight << rightWidth << bottomHeight;
q->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
if (resizeChecksWithBorderCheck) {
updateResizeCorners();
updateMask();
q->update();
} else if (currentBorders != borders) {
if (updateMaskIfNeeded) {
updateMask();
}
q->update();
}
resizeChecksWithBorderCheck = false;
}
void Dialog::syncToGraphicsWidget()
{
d->adjustViewTimer->stop();
QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data();
if (d->view && graphicsWidget && d->resizeStartCorner != -1) {
const int prevStartCorner = d->resizeStartCorner;
d->resizeStartCorner = -1;
QSize prevSize = size();
/*
#ifndef NDEBUG
kDebug() << "Widget size:" << graphicsWidget->size()
#endif
<< "| Widget size hint:" << graphicsWidget->effectiveSizeHint(Qt::PreferredSize)
<< "| Widget minsize hint:" << graphicsWidget->minimumSize()
<< "| Widget maxsize hint:" << graphicsWidget->maximumSize()
<< "| Widget bounding rect:" << graphicsWidget->sceneBoundingRect();
*/
//set the sizehints correctly:
int left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QDesktopWidget *desktop = QApplication::desktop();
QSize maxSize = desktop->availableGeometry(desktop->screenNumber(this)).size();
graphicsWidget->setMaximumSize(maxSize - QSize(left + right, top + bottom).boundedTo(graphicsWidget->effectiveSizeHint(Qt::MaximumSize).toSize()));
setMinimumSize(0, 0);
setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
QSize newSize(qMin(int(graphicsWidget->size().width()) + left + right, maxSize.width()),
qMin(int(graphicsWidget->size().height()) + top + bottom, maxSize.height()));
const QSizeF minimum = graphicsWidget->effectiveSizeHint(Qt::MinimumSize);
QSize newMinimumSize(qMin(int(minimum.width()) + left + right, maxSize.width()),
qMin(int(minimum.height()) + top + bottom, maxSize.height()));
QSize newMaximumSize(qMin(int(graphicsWidget->maximumSize().width()) + left + right, maxSize.width()),
qMin(int(graphicsWidget->maximumSize().height()) + top + bottom, maxSize.height()));
Plasma::Applet *applet = d->appletPtr.data();
if (applet) {
QRect currentGeometry(geometry());
currentGeometry.setSize(newSize);
if (applet->location() == Plasma::TopEdge ||
applet->location() == Plasma::LeftEdge) {
currentGeometry.setSize(newSize);
} else if (applet->location() == Plasma::RightEdge) {
currentGeometry.moveTopRight(geometry().topRight());
//BottomEdge and floating
} else {
currentGeometry.moveBottomLeft(geometry().bottomLeft());
}
setGeometry(currentGeometry);
} else {
resize(newSize);
}
setMinimumSize(newMinimumSize);
setMaximumSize(newMaximumSize);
updateGeometry();
//reposition and resize the view.
//force a valid rect, otherwise it will take up the whole scene
QRectF sceneRect(graphicsWidget->sceneBoundingRect());
sceneRect.setWidth(qMax(qreal(1), sceneRect.width()));
sceneRect.setHeight(qMax(qreal(1), sceneRect.height()));
d->view->setSceneRect(sceneRect);
//d->view->resize(graphicsWidget->size().toSize());
d->view->centerOn(graphicsWidget);
if (size() != prevSize) {
//the size of the dialog has changed, emit the signal:
emit dialogResized();
}
d->resizeStartCorner = prevStartCorner;
}
}
int DialogPrivate::calculateWidthForHeightAndRatio(int height, qreal ratio)
{
switch (aspectRatioMode) {
case KeepAspectRatio:
return qRound(height * ratio);
break;
case Square:
return height;
break;
case ConstrainedSquare:
return height;
break;
default:
return -1;
}
}
Dialog::Dialog(QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f | Qt::FramelessWindowHint),
d(new DialogPrivate(this))
{
setMouseTracking(true);
setAttribute(Qt::WA_TranslucentBackground);
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(themeChanged()));
QPalette pal = palette();
pal.setColor(backgroundRole(), Qt::transparent);
setPalette(pal);
WindowEffects::overrideShadow(winId(), true);
d->adjustViewTimer = new QTimer(this);
d->adjustViewTimer->setSingleShot(true);
connect(d->adjustViewTimer, SIGNAL(timeout()), this, SLOT(syncToGraphicsWidget()));
d->adjustSizeTimer = new QTimer(this);
d->adjustSizeTimer->setSingleShot(true);
connect(d->adjustSizeTimer, SIGNAL(timeout()), this, SLOT(delayedAdjustSize()));
d->themeChanged();
}
Dialog::~Dialog()
{
delete d;
}
void Dialog::paintEvent(QPaintEvent *e)
{
QPainter p(this);
p.setCompositionMode(QPainter::CompositionMode_Source);
d->background->paintFrame(&p, e->rect(), e->rect());
}
void Dialog::mouseMoveEvent(QMouseEvent *event)
{
if (event->modifiers() == Qt::AltModifier) {
unsetCursor();
} else if (d->resizeAreas[Dialog::NorthEast].contains(event->pos())) {
setCursor(Qt::SizeBDiagCursor);
} else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos())) {
setCursor(Qt::SizeFDiagCursor);
} else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos())) {
setCursor(Qt::SizeFDiagCursor);
} else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos())) {
setCursor(Qt::SizeBDiagCursor);
} else if (!(event->buttons() & Qt::LeftButton)) {
unsetCursor();
}
// here we take care of resize..
if (d->resizeStartCorner != Dialog::NoCorner) {
int newWidth;
int newHeight;
QPoint position;
qreal aspectRatio = (qreal)width() / (qreal)height();
switch(d->resizeStartCorner) {
case Dialog::NorthEast:
newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height() - event->y()));
newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
if (newWidth == -1) {
newWidth = qMin(maximumWidth(), qMax(minimumWidth(), event->x()));
}
position = QPoint(x(), y() + height() - newHeight);
break;
case Dialog::NorthWest:
newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height() - event->y()));
newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
if (newWidth == -1) {
newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width() - event->x()));
}
position = QPoint(x() + width() - newWidth, y() + height() - newHeight);
break;
case Dialog::SouthWest:
newHeight = qMin(maximumHeight(), qMax(minimumHeight(), event->y()));
newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
if (newWidth == -1) {
newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width() - event->x()));
}
position = QPoint(x() + width() - newWidth, y());
break;
case Dialog::SouthEast:
newHeight = qMin(maximumHeight(), qMax(minimumHeight(), event->y()));
newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
if (newWidth == -1) {
newWidth = qMin(maximumWidth(), qMax(minimumWidth(), event->x()));
}
position = QPoint(x(), y());
break;
default:
newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height()));
newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
if (newWidth == -1) {
newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width()));
}
position = QPoint(x(), y());
break;
}
QRect newGeom(position, QSize(newWidth, newHeight));
// now sanity check the resize results again min constraints, if any
if (d->leftResizeMin > -1 && newGeom.left() > d->leftResizeMin) {
newGeom.setLeft(d->leftResizeMin);
}
if (d->topResizeMin > -1 && newGeom.top() > d->topResizeMin) {
newGeom.setTop(d->topResizeMin);
}
if (d->rightResizeMin > -1 && newGeom.right() < d->rightResizeMin) {
newGeom.setRight(d->rightResizeMin);
}
if (d->bottomResizeMin > -1 && newGeom.bottom() < d->bottomResizeMin) {
newGeom.setBottom(d->bottomResizeMin);
}
if ((newGeom.width() >= minimumSize().width()) && (newGeom.height() >= minimumSize().height())) {
setGeometry(newGeom);
}
}
QWidget::mouseMoveEvent(event);
}
void Dialog::mousePressEvent(QMouseEvent *event)
{
if (d->resizeAreas[Dialog::NorthEast].contains(event->pos())) {
d->resizeStartCorner = Dialog::NorthEast;
} else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos())) {
d->resizeStartCorner = Dialog::NorthWest;
} else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos())) {
d->resizeStartCorner = Dialog::SouthEast;
} else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos())) {
d->resizeStartCorner = Dialog::SouthWest;
} else {
d->resizeStartCorner = Dialog::NoCorner;
}
QWidget::mousePressEvent(event);
}
void Dialog::mouseReleaseEvent(QMouseEvent *event)
{
if (d->resizeStartCorner != Dialog::NoCorner) {
emit dialogResized();
d->resizeStartCorner = Dialog::NoCorner;
unsetCursor();
}
QWidget::mouseReleaseEvent(event);
}
void Dialog::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape) {
hide();
}
}
bool Dialog::event(QEvent *event)
{
return QWidget::event(event);
}
void Dialog::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event)
//kDebug();
d->scheduleBorderCheck(true);
if (d->resizeStartCorner != -1 && d->view && d->graphicsWidgetPtr) {
QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data();
graphicsWidget->resize(d->view->size());
QRectF sceneRect(graphicsWidget->sceneBoundingRect());
sceneRect.setWidth(qMax(qreal(1), sceneRect.width()));
sceneRect.setHeight(qMax(qreal(1), sceneRect.height()));
d->view->setSceneRect(sceneRect);
d->view->centerOn(graphicsWidget);
}
}
void DialogPrivate::updateResizeCorners()
{
const int resizeAreaMargin = 20;
const QRect r = q->rect();
const FrameSvg::EnabledBorders borders = background->enabledBorders();
// IMPLEMENTATION NOTE: we set resize corners for the corners set, but also
// for the complimentary corners if we've cut out an edge of our SVG background
// which implies we are up against an immovable edge (e.g. a screen edge)
resizeAreas.clear();
if (resizeCorners & Dialog::NorthEast ||
(resizeCorners & Dialog::NorthWest && !(borders & FrameSvg::LeftBorder)) ||
(resizeCorners & Dialog::SouthEast && !(borders & FrameSvg::BottomBorder))) {
resizeAreas[Dialog::NorthEast] = QRect(r.right() - resizeAreaMargin, 0,
resizeAreaMargin, resizeAreaMargin);
}
if (resizeCorners & Dialog::NorthWest ||
(resizeCorners & Dialog::NorthEast && !(borders & FrameSvg::RightBorder)) ||
(resizeCorners & Dialog::SouthWest && !(borders & FrameSvg::BottomBorder))) {
resizeAreas[Dialog::NorthWest] = QRect(0, 0, resizeAreaMargin, resizeAreaMargin);
}
if (resizeCorners & Dialog::SouthEast ||
(resizeCorners & Dialog::SouthWest && !(borders & FrameSvg::LeftBorder)) ||
(resizeCorners & Dialog::NorthEast && !(borders & FrameSvg::TopBorder))) {
resizeAreas[Dialog::SouthEast] = QRect(r.right() - resizeAreaMargin,
r.bottom() - resizeAreaMargin,
resizeAreaMargin, resizeAreaMargin);
}
if (resizeCorners & Dialog::SouthWest ||
(resizeCorners & Dialog::SouthEast && !(borders & FrameSvg::RightBorder)) ||
(resizeCorners & Dialog::NorthWest && !(borders & FrameSvg::TopBorder))) {
resizeAreas[Dialog::SouthWest] = QRect(0, r.bottom() - resizeAreaMargin,
resizeAreaMargin, resizeAreaMargin);
}
}
void Dialog::setGraphicsWidget(QGraphicsWidget *widget)
{
if (d->graphicsWidgetPtr) {
d->graphicsWidgetPtr.data()->removeEventFilter(this);
}
d->graphicsWidgetPtr = widget;
if (widget) {
Plasma::Corona *c = qobject_cast<Plasma::Corona *>(widget->scene());
if (c) {
c->addOffscreenWidget(widget);
}
if (!layout()) {
QVBoxLayout *lay = new QVBoxLayout(this);
lay->setMargin(0);
lay->setSpacing(0);
}
d->checkBorders();
if (!d->view) {
d->view = new QGraphicsView(this);
d->view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
d->view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
d->view->setFrameShape(QFrame::NoFrame);
d->view->viewport()->setAutoFillBackground(false);
layout()->addWidget(d->view);
}
d->view->setScene(widget->scene());
//try to have the proper size -before- showing the dialog
d->view->centerOn(widget);
if (widget->layout()) {
widget->layout()->activate();
}
static_cast<QGraphicsLayoutItem *>(widget)->updateGeometry();
widget->resize(widget->size().expandedTo(widget->effectiveSizeHint(Qt::MinimumSize)));
syncToGraphicsWidget();
//d->adjustSizeTimer->start(150);
widget->installEventFilter(this);
d->view->installEventFilter(this);
} else {
delete d->view;
d->view = 0;
}
}
QGraphicsWidget *Dialog::graphicsWidget() const
{
return d->graphicsWidgetPtr.data();
}
bool Dialog::eventFilter(QObject *watched, QEvent *event)
{
if (d->resizeStartCorner == Dialog::NoCorner && watched == d->graphicsWidgetPtr.data() &&
(event->type() == QEvent::GraphicsSceneResize || event->type() == QEvent::GraphicsSceneMove)) {
d->adjustViewTimer->start(150);
}
// when moving the cursor with a 45ー angle from the outside
// to the inside passing over a resize angle the cursor changes its
// shape to a resize cursor. As a side effect this is the only case
// when the cursor immediately enters the view without giving
// the dialog the chance to restore the original cursor shape.
if (event->type() == QEvent::Enter && watched == d->view) {
unsetCursor();
}
return QWidget::eventFilter(watched, event);
}
void Dialog::hideEvent(QHideEvent * event)
{
Q_UNUSED(event);
emit dialogVisible(false);
}
void Dialog::showEvent(QShowEvent * event)
{
Q_UNUSED(event);
//check if the widget size is still synced with the view
d->checkBorders();
d->updateResizeCorners();
QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data();
if (graphicsWidget &&
((d->view && graphicsWidget->size().toSize() != d->view->size()) ||
d->oldGraphicsWidgetMinimumSize != graphicsWidget->minimumSize() ||
d->oldGraphicsWidgetMaximumSize != graphicsWidget->maximumSize())) {
//here have to be done immediately, ideally should have to be done -before- shwing, but is not possible to catch show() so early
syncToGraphicsWidget();
d->oldGraphicsWidgetMinimumSize = graphicsWidget->minimumSize().toSize();
d->oldGraphicsWidgetMaximumSize = graphicsWidget->maximumSize().toSize();
}
if (d->view) {
d->view->setFocus();
}
if (graphicsWidget) {
graphicsWidget->setFocus();
}
emit dialogVisible(true);
WindowEffects::overrideShadow(winId(), true);
}
void Dialog::focusInEvent(QFocusEvent *event)
{
Q_UNUSED(event)
if (d->view) {
d->view->setFocus();
}
QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data();
if (graphicsWidget) {
graphicsWidget->setFocus();
}
}
void Dialog::moveEvent(QMoveEvent *event)
{
Q_UNUSED(event)
//kDebug();
d->scheduleBorderCheck();
}
void Dialog::setResizeHandleCorners(ResizeCorners corners)
{
if ((d->resizeCorners != corners) && (aspectRatioMode() != FixedSize)) {
d->resizeCorners = corners;
d->updateResizeCorners();
}
}
Dialog::ResizeCorners Dialog::resizeCorners() const
{
return d->resizeCorners;
}
bool Dialog::isUserResizing() const
{
return d->resizeStartCorner > NoCorner;
}
void Dialog::setMinimumResizeLimits(int left, int top, int right, int bottom)
{
d->leftResizeMin = left;
d->topResizeMin = top;
d->rightResizeMin = right;
d->bottomResizeMin = bottom;
}
void Dialog::getMinimumResizeLimits(int *left, int *top, int *right, int *bottom)
{
if (left) {
*left = d->leftResizeMin;
}
if (top) {
*top = d->topResizeMin;
}
if (right) {
*right = d->rightResizeMin;
}
if (bottom) {
*bottom = d->bottomResizeMin;
}
}
void Dialog::animatedHide(Plasma::Direction direction)
{
if (!isVisible()) {
return;
}
if (!Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
hide();
return;
}
Location location = Desktop;
switch (direction) {
case Down:
location = BottomEdge;
break;
case Right:
location = RightEdge;
break;
case Left:
location = LeftEdge;
break;
case Up:
location = TopEdge;
break;
default:
break;
}
Plasma::WindowEffects::slideWindow(this, location);
hide();
}
void Dialog::animatedShow(Plasma::Direction direction)
{
if (!Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
show();
return;
}
//copied to not add new api
Location location = Desktop;
switch (direction) {
case Up:
location = BottomEdge;
break;
case Left:
location = RightEdge;
break;
case Right:
location = LeftEdge;
break;
case Down:
location = TopEdge;
break;
default:
break;
}
if (Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
Plasma::WindowEffects::slideWindow(this, location);
}
show();
}
bool Dialog::inControlArea(const QPoint &point)
{
foreach (const QRect &r, d->resizeAreas) {
if (r.contains(point)) {
return true;
}
}
return false;
}
Plasma::AspectRatioMode Dialog::aspectRatioMode() const
{
return d->aspectRatioMode;
}
void Dialog::setAspectRatioMode(Plasma::AspectRatioMode mode)
{
if (mode == FixedSize) {
setResizeHandleCorners(NoCorner);
}
d->aspectRatioMode = mode;
}
}
+
+#include "moc_dialog.cpp"
diff --git a/plasma/framesvg.cpp b/plasma/framesvg.cpp
index 0fd13de921..07155c1a60 100644
--- a/plasma/framesvg.cpp
+++ b/plasma/framesvg.cpp
@@ -1,1095 +1,1097 @@
/*
* Copyright 2008-2010 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008-2010 Marco Martin <notmart@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "framesvg.h"
#include "private/framesvg_p.h"
#include <QAtomicInt>
#include <QBitmap>
#include <QCryptographicHash>
#include <QPainter>
#include <QRegion>
#include <QSize>
#include <QStringBuilder>
#include <QTimer>
#include <kdebug.h>
#include <applet.h>
#include <theme.h>
#include <private/svg_p.h>
namespace Plasma
{
QHash<QString, FrameData *> FrameSvgPrivate::s_sharedFrames;
// Any attempt to generate a frame whose width or height is larger than this
// will be rejected
static const int MAX_FRAME_SIZE = 100000;
FrameSvg::FrameSvg(QObject *parent)
: Svg(parent),
d(new FrameSvgPrivate(this))
{
connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateNeeded()));
d->frames.insert(QString(), new FrameData(this));
}
FrameSvg::~FrameSvg()
{
delete d;
}
void FrameSvg::setImagePath(const QString &path)
{
if (path == imagePath()) {
return;
}
bool updateNeeded = true;
clearCache();
FrameData *fd = d->frames[d->prefix];
if (fd->refcount() == 1) {
// we're the only user of it, let's remove it from the shared keys
// we don't want to deref it, however, as we'll still be using it
const QString oldKey = d->cacheId(fd, d->prefix);
FrameSvgPrivate::s_sharedFrames.remove(oldKey);
} else {
// others are using this frame, so deref it for ourselves
fd->deref(this);
fd = 0;
}
Svg::d->setImagePath(path);
if (!fd) {
// we need to replace our frame, start by looking in the frame cache
FrameData *oldFd = d->frames[d->prefix];
const QString key = d->cacheId(oldFd, d->prefix);
fd = FrameSvgPrivate::s_sharedFrames.value(key);
if (fd) {
// we found one, so ref it and use it; we also don't need to (or want to!)
// trigger a full update of the frame since it is already the one we want
// and likely already rendered just fine
fd->ref(this);
updateNeeded = false;
} else {
// nothing exists for us in the cache, so create a new FrameData based
// on the old one
fd = new FrameData(*oldFd, this);
}
d->frames.insert(d->prefix, fd);
}
setContainsMultipleImages(true);
if (updateNeeded) {
// ensure our frame is in the cache
const QString key = d->cacheId(fd, d->prefix);
FrameSvgPrivate::s_sharedFrames.insert(key, fd);
// this will emit repaintNeeded() as well when it is done
d->updateAndSignalSizes();
} else {
emit repaintNeeded();
}
}
void FrameSvg::setEnabledBorders(const EnabledBorders borders)
{
if (borders == d->frames[d->prefix]->enabledBorders) {
return;
}
FrameData *fd = d->frames[d->prefix];
const QString oldKey = d->cacheId(fd, d->prefix);
const EnabledBorders oldBorders = fd->enabledBorders;
fd->enabledBorders = borders;
const QString newKey = d->cacheId(fd, d->prefix);
fd->enabledBorders = oldBorders;
//kDebug() << "looking for" << newKey;
FrameData *newFd = FrameSvgPrivate::s_sharedFrames.value(newKey);
if (newFd) {
//kDebug() << "FOUND IT!" << newFd->refcount;
// we've found a math, so insert that new one and ref it ..
newFd->ref(this);
d->frames.insert(d->prefix, newFd);
//.. then deref the old one and if it's no longer used, get rid of it
if (fd->deref(this)) {
//const QString oldKey = d->cacheId(fd, d->prefix);
//kDebug() << "1. Removing it" << oldKey << fd->refcount;
FrameSvgPrivate::s_sharedFrames.remove(oldKey);
delete fd;
}
return;
}
if (fd->refcount() == 1) {
// we're the only user of it, let's remove it from the shared keys
// we don't want to deref it, however, as we'll still be using it
FrameSvgPrivate::s_sharedFrames.remove(oldKey);
} else {
// others are using it, but we wish to change its size. so deref it,
// then create a copy of it (we're automatically ref'd via the ctor),
// then insert it into our frames.
fd->deref(this);
fd = new FrameData(*fd, this);
d->frames.insert(d->prefix, fd);
}
fd->enabledBorders = borders;
d->updateAndSignalSizes();
}
FrameSvg::EnabledBorders FrameSvg::enabledBorders() const
{
if (d->frames.isEmpty()) {
return NoBorder;
}
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 += '-';
}
}
FrameData *oldFrameData = d->frames.value(oldPrefix);
if (oldPrefix == d->prefix && oldFrameData) {
return;
}
if (!d->frames.contains(d->prefix)) {
if (oldFrameData) {
FrameData *newFd = 0;
if (!oldFrameData->frameSize.isEmpty()) {
const QString key = d->cacheId(oldFrameData, d->prefix);
newFd = FrameSvgPrivate::s_sharedFrames.value(key);
}
// we need to put this in the cache if we didn't find it in the shared frames
// and we have a size; if we don't have a size, we'll catch it later
const bool cache = !newFd && !oldFrameData->frameSize.isEmpty();
if (newFd) {
newFd->ref(this);
} else {
newFd = new FrameData(*oldFrameData, this);
}
d->frames.insert(d->prefix, newFd);
if (cache) {
// we have to cache after inserting the frame since the cacheId requires the
// frame to be in the frames collection already
const QString key = d->cacheId(oldFrameData, d->prefix);
//kDebug() << this << " 1. inserting as" << key;
FrameSvgPrivate::s_sharedFrames.insert(key, newFd);
}
} else {
// couldn't find anything useful, so we just create something here
// we don't have a size for it yet, so don't bother trying to share it just yet
FrameData *newFd = new FrameData(this);
d->frames.insert(d->prefix, newFd);
}
d->updateSizes();
}
if (!d->cacheAll) {
d->frames.remove(oldPrefix);
if (oldFrameData) {
if (oldFrameData->deref(this)) {
const QString oldKey = d->cacheId(oldFrameData, oldPrefix);
FrameSvgPrivate::s_sharedFrames.remove(oldKey);
delete oldFrameData;
}
}
}
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 (imagePath().isEmpty()) {
return;
}
if (size.isEmpty()) {
#ifndef NDEBUG
kDebug() << "Invalid size" << size;
#endif
return;
}
FrameData *fd = d->frames[d->prefix];
if (size == fd->frameSize) {
return;
}
const QString oldKey = d->cacheId(fd, d->prefix);
const QSize currentSize = fd->frameSize;
fd->frameSize = size.toSize();
const QString newKey = d->cacheId(fd, d->prefix);
fd->frameSize = currentSize;
//kDebug() << "looking for" << newKey;
FrameData *newFd = FrameSvgPrivate::s_sharedFrames.value(newKey);
if (newFd) {
//kDebug() << "FOUND IT!" << newFd->refcount;
// we've found a math, so insert that new one and ref it ..
newFd->ref(this);
d->frames.insert(d->prefix, newFd);
//.. then deref the old one and if it's no longer used, get rid of it
if (fd->deref(this)) {
//const QString oldKey = d->cacheId(fd, d->prefix);
//kDebug() << "1. Removing it" << oldKey << fd->refcount;
FrameSvgPrivate::s_sharedFrames.remove(oldKey);
delete fd;
}
return;
}
if (fd->refcount() == 1) {
// we're the only user of it, let's remove it from the shared keys
// we don't want to deref it, however, as we'll still be using it
FrameSvgPrivate::s_sharedFrames.remove(oldKey);
} else {
// others are using it, but we wish to change its size. so deref it,
// then create a copy of it (we're automatically ref'd via the ctor),
// then insert it into our frames.
fd->deref(this);
fd = new FrameData(*fd, this);
d->frames.insert(d->prefix, fd);
}
d->updateSizes();
fd->frameSize = size.toSize();
// we know it isn't in s_sharedFrames due to the check above, so insert it now
FrameSvgPrivate::s_sharedFrames.insert(newKey, fd);
}
QSizeF FrameSvg::frameSize() const
{
QHash<QString, FrameData*>::const_iterator it = d->frames.constFind(d->prefix);
if (it == d->frames.constEnd()) {
return QSize(-1, -1);
} else {
return d->frameSize(it.value());
}
}
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->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();
}
}
QPixmap FrameSvg::alphaMask() const
{
//FIXME: the distinction between overlay and
return d->alphaMask();
}
QRegion FrameSvg::mask() const
{
FrameData *frame = d->frames[d->prefix];
QString id = d->cacheId(frame, QString());
if (!frame->cachedMasks.contains(id)) {
//TODO: Implement a better way to cap the number of cached masks
if (frame->cachedMasks.count() > frame->MAX_CACHED_MASKS) {
frame->cachedMasks.clear();
}
frame->cachedMasks.insert(id, QRegion(QBitmap(d->alphaMask().alphaChannel().createMaskFromColor(Qt::black))));
}
return frame->cachedMasks[id];
}
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) {
//TODO: should we clear from the Theme pixmap cache as well?
if (p->deref(this)) {
const QString key = d->cacheId(p, it.key());
FrameSvgPrivate::s_sharedFrames.remove(key);
p->cachedBackground = QPixmap();
}
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);
}
//#define DEBUG_FRAMESVG_CACHE
FrameSvgPrivate::~FrameSvgPrivate()
{
#ifdef DEBUG_FRAMESVG_CACHE
#ifndef NDEBUG
kDebug() << "*************" << q << q->imagePath() << "****************";
#endif
#endif
QHashIterator<QString, FrameData *> it(frames);
while (it.hasNext()) {
it.next();
if (it.value()) {
// we remove all references from this widget to the frame, and delete it if we're the
// last user
if (it.value()->removeRefs(q)) {
const QString key = cacheId(it.value(), it.key());
#ifdef DEBUG_FRAMESVG_CACHE
#ifndef NDEBUG
kDebug() << "2. Removing it" << key << it.value() << it.value()->refcount() << s_sharedFrames.contains(key);
#endif
#endif
s_sharedFrames.remove(key);
delete it.value();
}
#ifdef DEBUG_FRAMESVG_CACHE
else {
#ifndef NDEBUG
kDebug() << "still shared:" << cacheId(it.value(), it.key()) << it.value() << it.value()->refcount() << it.value()->isUsed();
#endif
}
} else {
#ifndef NDEBUG
kDebug() << "lost our value for" << it.key();
#endif
#endif
}
}
#ifdef DEBUG_FRAMESVG_CACHE
QHashIterator<QString, FrameData *> it2(s_sharedFrames);
int shares = 0;
while (it2.hasNext()) {
it2.next();
const int rc = it2.value()->refcount();
if (rc == 0) {
#ifndef NDEBUG
kDebug() << " LOST!" << it2.key() << rc << it2.value();// << it2.value()->references;
#endif
} else {
#ifndef NDEBUG
kDebug() << " " << it2.key() << rc << it2.value();
#endif
foreach (FrameSvg *data, it2.value()->references.keys()) {
#ifndef NDEBUG
kDebug( )<< " " << (void*)data << it2.value()->references[data];
#endif
}
shares += rc - 1;
}
}
#ifndef NDEBUG
kDebug() << "#####################################" << s_sharedFrames.count() << ", pixmaps saved:" << shares;
#endif
#endif
frames.clear();
}
QPixmap FrameSvgPrivate::alphaMask()
{
FrameData *frame = frames[prefix];
QString maskPrefix;
if (q->hasElement("mask-" % prefix % "center")) {
maskPrefix = "mask-";
}
if (maskPrefix.isNull()) {
if (frame->cachedBackground.isNull()) {
generateBackground(frame);
if (frame->cachedBackground.isNull()) {
return QPixmap();
}
}
return frame->cachedBackground;
} else {
QString oldPrefix = prefix;
// We are setting the prefix only temporary to generate
// the needed mask image
prefix = maskPrefix % oldPrefix;
if (!frames.contains(prefix)) {
const QString key = cacheId(frame, prefix);
// see if we can find a suitable candidate in the shared frames
// if successful, ref and insert, otherwise create a new one
// and insert that into both the shared frames and our frames.
FrameData *maskFrame = s_sharedFrames.value(key);
if (maskFrame) {
maskFrame->ref(q);
} else {
maskFrame = new FrameData(*frame, q);
s_sharedFrames.insert(key, maskFrame);
}
frames.insert(prefix, maskFrame);
updateSizes();
}
FrameData *maskFrame = frames[prefix];
if (maskFrame->cachedBackground.isNull() || maskFrame->frameSize != frameSize(frame)) {
const QString oldKey = cacheId(maskFrame, prefix);
maskFrame->frameSize = frameSize(frame).toSize();
const QString newKey = cacheId(maskFrame, prefix);
if (s_sharedFrames.contains(oldKey)) {
s_sharedFrames.remove(oldKey);
s_sharedFrames.insert(newKey, maskFrame);
}
maskFrame->cachedBackground = QPixmap();
generateBackground(maskFrame);
if (maskFrame->cachedBackground.isNull()) {
return QPixmap();
}
}
prefix = oldPrefix;
return maskFrame->cachedBackground;
}
}
void FrameSvgPrivate::generateBackground(FrameData *frame)
{
if (!frame->cachedBackground.isNull() || !q->hasElementPrefix(q->prefix())) {
return;
}
const QString id = cacheId(frame, prefix);
Theme *theme = Theme::defaultTheme();
bool frameCached = !frame->cachedBackground.isNull();
bool overlayCached = false;
const bool overlayAvailable = !prefix.startsWith("mask-") && q->hasElement(prefix % "overlay");
QPixmap overlay;
if (q->isUsingRenderingCache()) {
frameCached = theme->findInCache(id, frame->cachedBackground) && !frame->cachedBackground.isNull();
if (overlayAvailable) {
overlayCached = theme->findInCache("overlay_" % id, overlay) && !overlay.isNull();
}
}
if (!frameCached) {
generateFrameBackground(frame);
}
//Overlays
QSize overlaySize;
QPoint actualOverlayPos = QPoint(0, 0);
if (overlayAvailable && !overlayCached) {
QPoint pos = QPoint(0, 0);
overlaySize = q->elementSize(prefix % "overlay");
//Random pos, stretched and tiled are mutually exclusive
if (q->hasElement(prefix % "hint-overlay-random-pos")) {
actualOverlayPos = overlayPos;
} else if (q->hasElement(prefix % "hint-overlay-pos-right")) {
actualOverlayPos.setX(frame->frameSize.width() - overlaySize.width());
} else if (q->hasElement(prefix % "hint-overlay-pos-bottom")) {
actualOverlayPos.setY(frame->frameSize.height() - overlaySize.height());
//Stretched or Tiled?
} else if (q->hasElement(prefix % "hint-overlay-stretch")) {
overlaySize = frameSize(frame).toSize();
} else {
if (q->hasElement(prefix % "hint-overlay-tile-horizontal")) {
overlaySize.setWidth(frameSize(frame).width());
}
if (q->hasElement(prefix % "hint-overlay-tile-vertical")) {
overlaySize.setHeight(frameSize(frame).height());
}
}
overlay = alphaMask();
QPainter overlayPainter(&overlay);
overlayPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
//Tiling?
if (q->hasElement(prefix % "hint-overlay-tile-horizontal") ||
q->hasElement(prefix % "hint-overlay-tile-vertical")) {
QSize s = q->size();
q->resize(q->elementSize(prefix % "overlay"));
overlayPainter.drawTiledPixmap(QRect(QPoint(0,0), overlaySize), q->pixmap(prefix % "overlay"));
q->resize(s);
} else {
q->paint(&overlayPainter, QRect(actualOverlayPos, overlaySize), prefix % "overlay");
}
overlayPainter.end();
}
if (!frameCached) {
cacheFrame(prefix, frame->cachedBackground, overlayCached ? overlay : QPixmap());
}
if (!overlay.isNull()) {
QPainter p(&frame->cachedBackground);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.drawPixmap(actualOverlayPos, overlay, QRect(actualOverlayPos, overlaySize));
}
}
void FrameSvgPrivate::generateFrameBackground(FrameData *frame)
{
//kDebug() << "generating background";
const QSizeF size = frameSize(frame);
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 (!size.isValid()) {
#ifndef NDEBUG
kDebug() << "Invalid frame size" << size;
#endif
return;
}
if (size.width() >= MAX_FRAME_SIZE || size.height() >= MAX_FRAME_SIZE) {
kWarning() << "Not generating frame background for a size whose width or height is more than" << MAX_FRAME_SIZE << size;
return;
}
const int contentWidth = size.width() - frame->leftWidth - frame->rightWidth;
const int contentHeight = size.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);
//CENTER
if (frame->tileCenter) {
if (contentHeight > 0 && contentWidth > 0) {
const int centerTileHeight = q->elementSize(prefix % "center").height();
const int centerTileWidth = q->elementSize(prefix % "center").width();
QPixmap center(centerTileWidth, centerTileHeight);
center.fill(Qt::transparent);
{
QPainter centerPainter(&center);
centerPainter.setCompositionMode(QPainter::CompositionMode_Source);
q->paint(&centerPainter, QRect(QPoint(0, 0), q->elementSize(prefix % "center")), prefix % "center");
}
if (frame->composeOverBorder) {
p.drawTiledPixmap(QRect(QPoint(0, 0), size.toSize()), center);
} else {
p.drawTiledPixmap(QRect(frame->leftWidth, frame->topHeight,
contentWidth, contentHeight), center);
}
}
} else {
if (contentHeight > 0 && contentWidth > 0) {
if (frame->composeOverBorder) {
q->paint(&p, QRect(QPoint(0, 0), size.toSize()),
prefix % "center");
} else {
q->paint(&p, QRect(frame->leftWidth, frame->topHeight,
contentWidth, contentHeight),
prefix % "center");
}
}
}
if (frame->composeOverBorder) {
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawPixmap(QRect(QPoint(0, 0), size.toSize()), alphaMask());
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
}
if (frame->enabledBorders & FrameSvg::LeftBorder && q->hasElement(prefix % "left")) {
rightOffset += frame->leftWidth;
}
// Corners
if (frame->enabledBorders & FrameSvg::TopBorder && q->hasElement(prefix % "top")) {
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;
}
if (q->hasElement(prefix % "topright") && frame->enabledBorders & FrameSvg::RightBorder) {
q->paint(&p, QRect(rightOffset, topOffset, frame->rightWidth, frame->topHeight), prefix % "topright");
}
}
if (frame->enabledBorders & FrameSvg::BottomBorder && q->hasElement(prefix % "bottom")) {
if (q->hasElement(prefix % "bottomleft") && frame->enabledBorders & FrameSvg::LeftBorder) {
q->paint(&p, QRect(leftOffset, bottomOffset, frame->leftWidth, frame->bottomHeight), prefix % "bottomleft");
contentLeft = frame->leftWidth;
}
if (frame->enabledBorders & FrameSvg::RightBorder && q->hasElement(prefix % "bottomright")) {
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 (frame->enabledBorders & FrameSvg::TopBorder && q->hasElement(prefix % "top")) {
q->paint(&p, QRect(contentLeft, topOffset, contentWidth, frame->topHeight), prefix % "top");
}
if (frame->enabledBorders & FrameSvg::BottomBorder && q->hasElement(prefix % "bottom")) {
q->paint(&p, QRect(contentLeft, bottomOffset, contentWidth, frame->bottomHeight), prefix % "bottom");
}
}
} else {
if (frame->enabledBorders & FrameSvg::LeftBorder && q->hasElement(prefix % "left")
&& leftHeight > 0 && frame->leftWidth > 0) {
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 (frame->enabledBorders & FrameSvg::RightBorder && q->hasElement(prefix % "right") &&
leftHeight > 0 && frame->rightWidth > 0) {
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 (frame->enabledBorders & FrameSvg::TopBorder && q->hasElement(prefix % "top")
&& topWidth > 0 && frame->topHeight > 0) {
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 (frame->enabledBorders & FrameSvg::BottomBorder && q->hasElement(prefix % "bottom")
&& topWidth > 0 && frame->bottomHeight > 0) {
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);
}
}
}
QString FrameSvgPrivate::cacheId(FrameData *frame, const QString &prefixToSave) const
{
const QSize size = frameSize(frame).toSize();
const QLatin1Char s('_');
return QString::number(frame->enabledBorders) % s % QString::number(size.width()) % s % QString::number(size.height()) % s % prefixToSave % s % q->imagePath();
}
void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay)
{
if (!q->isUsingRenderingCache()) {
return;
}
//insert background
FrameData *frame = frames.value(prefixToSave);
if (!frame) {
return;
}
const QString id = cacheId(frame, prefixToSave);
//kDebug()<<"Saving to cache frame"<<id;
Theme::defaultTheme()->insertIntoCache(id, background, QString::number((qint64)q, 16) % prefixToSave);
if (!overlay.isNull()) {
//insert overlay
Theme::defaultTheme()->insertIntoCache("overlay_" % id, overlay, QString::number((qint64)q, 16) % prefixToSave % "overlay");
}
}
void FrameSvgPrivate::updateSizes() const
{
//kDebug() << "!!!!!!!!!!!!!!!!!!!!!! updating sizes" << prefix;
FrameData *frame = frames[prefix];
Q_ASSERT(frame);
QSize s = q->size();
q->resize();
frame->cachedBackground = 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").width();
} 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").width();
} 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;
}
frame->composeOverBorder = (q->hasElement(prefix % "hint-compose-over-border") &&
q->hasElement("mask-" % prefix % "center"));
//since it's rectangular, topWidth and bottomWidth must be the same
//the ones that don't have a prefix is for retrocompatibility
frame->tileCenter = (q->hasElement("hint-tile-center") || q->hasElement(prefix % "hint-tile-center"));
frame->noBorderPadding = (q->hasElement("hint-no-border-padding") || q->hasElement(prefix % "hint-no-border-padding"));
frame->stretchBorders = (q->hasElement("hint-stretch-borders") || q->hasElement(prefix % "hint-stretch-borders"));
q->resize(s);
}
void FrameSvgPrivate::updateNeeded()
{
q->clearCache();
updateSizes();
}
void FrameSvgPrivate::updateAndSignalSizes()
{
updateSizes();
emit q->repaintNeeded();
}
QSizeF FrameSvgPrivate::frameSize(FrameData *frame) const
{
if (!frame->frameSize.isValid()) {
updateSizes();
frame->frameSize = q->size();
}
return frame->frameSize;
}
void FrameData::ref(FrameSvg *svg)
{
references[svg] = references[svg] + 1;
//kDebug() << this << svg << references[svg];
}
bool FrameData::deref(FrameSvg *svg)
{
references[svg] = references[svg] - 1;
//kDebug() << this << svg << references[svg];
if (references[svg] < 1) {
references.remove(svg);
}
return references.isEmpty();
}
bool FrameData::removeRefs(FrameSvg *svg)
{
references.remove(svg);
return references.isEmpty();
}
bool FrameData::isUsed() const
{
return !references.isEmpty();
}
int FrameData::refcount() const
{
return references.count();
}
} // Plasma namespace
+
+#include "moc_framesvg.cpp"
diff --git a/plasma/packagestructure.cpp b/plasma/packagestructure.cpp
index 4159e8afc2..789d107307 100644
--- a/plasma/packagestructure.cpp
+++ b/plasma/packagestructure.cpp
@@ -1,60 +1,62 @@
/******************************************************************************
* Copyright 2011 by Aaron Seigo <aseigo@kde.org> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public License *
* along with this library; see the file COPYING.LIB. If not, write to *
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301, USA. *
*******************************************************************************/
#include "packagestructure.h"
#include "private/package_p.h"
namespace Plasma
{
PackageStructure::PackageStructure(QObject *parent, const QVariantList &args)
: QObject(parent),
d(0)
{
Q_UNUSED(args)
}
PackageStructure::~PackageStructure()
{
}
void PackageStructure::initPackage(Package *package)
{
Q_UNUSED(package)
}
void PackageStructure::pathChanged(Package *package)
{
Q_UNUSED(package)
}
bool PackageStructure::installPackage(Package *package, const QString &archivePath, const QString &packageRoot)
{
return PackagePrivate::installPackage(archivePath, packageRoot, package->servicePrefix());
}
bool PackageStructure::uninstallPackage(Package *package, const QString &packageName, const QString &packageRoot)
{
return PackagePrivate::uninstallPackage(packageName, packageRoot, package->servicePrefix());
}
}
+
+#include "moc_packagestructure.cpp"
diff --git a/plasma/popupapplet.cpp b/plasma/popupapplet.cpp
index 54d22baa2b..26fe294da3 100644
--- a/plasma/popupapplet.cpp
+++ b/plasma/popupapplet.cpp
@@ -1,898 +1,900 @@
/*
* Copyright 2008 by Montel Laurent <montel@kde.org>
* Copyright 2008 by Marco Martin <notmart@gmail.com>
*
* 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 "popupapplet.h"
#include "private/popupapplet_p.h"
#include "private/dialog_p.h"
#include <QApplication>
#include <QGraphicsProxyWidget>
#include <QGraphicsLinearLayout>
#include <QTimer>
#include <QVBoxLayout>
#ifdef Q_WS_X11
#include <QX11Info>
#endif
#include <kicon.h>
#include <kiconloader.h>
#include <kwindowsystem.h>
#include <kglobalsettings.h>
#include <netwm.h>
#include "plasma/private/applet_p.h"
#include "plasma/corona.h"
#include "plasma/containment.h"
#include "plasma/private/containment_p.h"
#include "plasma/dialog.h"
#include "plasma/package.h"
#include "plasma/theme.h"
#include "plasma/scripting/appletscript.h"
#include "plasma/tooltipmanager.h"
#include "plasma/widgets/iconwidget.h"
namespace Plasma
{
PopupApplet::PopupApplet(QObject *parent, const QVariantList &args)
: Applet(parent, args),
d(new PopupAppletPrivate(this))
{
}
PopupApplet::PopupApplet(const QString &packagePath, uint appletId, const QVariantList &args)
: Applet(packagePath, appletId, args),
d(new PopupAppletPrivate(this))
{
}
PopupApplet::~PopupApplet()
{
delete widget();
delete d;
}
void PopupApplet::setPopupIcon(const QIcon &icon)
{
if (icon.isNull()) {
if (d->icon) {
delete d->icon;
d->icon = 0;
setLayout(0);
setAspectRatioMode(d->savedAspectRatio);
}
return;
}
d->createIconWidget();
d->icon->setIcon(icon);
}
void PopupApplet::setPopupIcon(const QString &iconName)
{
// Attempt 1: is it in the plasmoid package?
if (package().isValid()) {
const QString file = package().filePath("images", iconName);
if (!file.isEmpty()) {
setPopupIcon(KIcon(file));
return;
}
}
// Attempt 2: is it a svg in the icons directory?
QString name = QString("icons/") + iconName.split("-").first();
if (!Plasma::Theme::defaultTheme()->imagePath(name).isEmpty()) {
d->createIconWidget();
d->icon->setSvg(name, iconName);
if (d->icon->svg().isEmpty()) {
setPopupIcon(KIcon(iconName));
}
return;
}
// Final Attempt: use KIcon
setPopupIcon(KIcon(iconName));
}
QIcon PopupApplet::popupIcon() const
{
return d->icon ? d->icon->icon() : QIcon();
}
QWidget *PopupApplet::widget()
{
return d->widget;
}
void PopupApplet::setWidget(QWidget *widget)
{
if (d->widget) {
Plasma::Dialog *dialog = d->dialogPtr.data();
if (dialog) {
dialog->setGraphicsWidget(0);
QVBoxLayout *lay = 0;
QLayout *existingLayout = dialog->layout();
if (existingLayout) {
lay = dynamic_cast<QVBoxLayout *>(existingLayout);
if (!lay) {
delete existingLayout;
}
}
if (!lay) {
lay = new QVBoxLayout;
dialog->setLayout(lay);
}
lay->removeWidget(d->widget);
lay->addWidget(widget);
} else if (d->proxy) {
d->proxy.data()->setWidget(widget);
}
}
d->widget = widget;
}
QGraphicsWidget *PopupApplet::graphicsWidget()
{
return d->graphicsWidget.data();
}
void PopupApplet::setGraphicsWidget(QGraphicsWidget *graphicsWidget)
{
if (d->graphicsWidget) {
if (d->dialogPtr) {
d->dialogPtr.data()->setGraphicsWidget(graphicsWidget);
} else if (layout()) {
QGraphicsLinearLayout *lay = static_cast<QGraphicsLinearLayout *>(layout());
lay->removeAt(0);
if (graphicsWidget) {
lay->addItem(graphicsWidget);
}
}
}
d->graphicsWidget = graphicsWidget;
}
void PopupAppletPrivate::popupConstraintsEvent(Plasma::Constraints constraints)
{
Plasma::FormFactor f = q->formFactor();
if (constraints & Plasma::FormFactorConstraint ||
constraints & Plasma::StartupCompletedConstraint ||
(constraints & Plasma::SizeConstraint &&
(f == Plasma::Vertical || f == Plasma::Horizontal))) {
QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout *>(q->layout());
if (icon && lay && lay->count() > 0) {
lay->removeAt(0);
}
QSizeF minimum;
QSizeF parentSize;
QGraphicsWidget *gWidget = q->graphicsWidget();
//kDebug() << "graphics widget is" << (QObject*)gWidget;
QWidget *qWidget = q->widget();
if (gWidget) {
minimum = gWidget->minimumSize();
// our layout may have been replaced on us in the call to graphicsWidget!
lay = dynamic_cast<QGraphicsLinearLayout *>(q->layout());
} else if (qWidget) {
minimum = qWidget->minimumSizeHint();
}
//99% of the times q->parentWidget() is the containment, but using it we can also manage the applet-in-applet case (i.e. systray)
//there are also cases where the parentlayoutitem is bigger than the containment (e.g. newspaper)
if (q->parentLayoutItem()) {
parentSize = q->parentLayoutItem()->geometry().size();
} else if (q->parentWidget()) {
parentSize = q->parentWidget()->size();
}
//check if someone did the nasty trick of applets in applets, in this case we always want to be collapsed
QGraphicsWidget *candidateParentApplet = q;
Plasma::Applet *parentApplet = 0;
//this loop should be executed normally a single time, at most 2-3 times for quite complex containments
while (candidateParentApplet) {
candidateParentApplet = candidateParentApplet->parentWidget();
parentApplet = qobject_cast<Plasma::Applet *>(candidateParentApplet);
if (parentApplet) {
break;
}
}
//Applet on desktop
if ((!parentApplet || parentApplet->isContainment() ) && icon && (!icon->svg().isEmpty() || !icon->icon().isNull()) && ((f != Plasma::Vertical && f != Plasma::Horizontal) ||
((f == Plasma::Vertical && parentSize.width() >= minimum.width()) ||
(f == Plasma::Horizontal && parentSize.height() >= minimum.height())))) {
//kDebug() << "we are expanding the popupapplet";
// we only switch to expanded if we aren't horiz/vert constrained and
// this applet has an icon.
// otherwise, we leave it up to the applet itself to figure it out
if (icon) {
icon->hide();
}
if (savedAspectRatio != Plasma::InvalidAspectRatioMode) {
q->setAspectRatioMode(savedAspectRatio);
}
Dialog *dialog = dialogPtr.data();
if (dialog) {
if (dialog->layout() && qWidget) {
//we don't want to delete Widget inside the dialog layout
dialog->layout()->removeWidget(qWidget);
}
if (qWidget) {
qWidget->setParent(0);
}
delete dialog;
}
if (!lay) {
lay = new QGraphicsLinearLayout();
lay->setContentsMargins(0, 0, 0, 0);
lay->setSpacing(0);
lay->setOrientation(Qt::Horizontal);
q->setLayout(lay);
}
QSize prefSize;
if (gWidget) {
if (proxy) {
proxy.data()->setWidget(0);
delete proxy.data();
}
Corona *corona = qobject_cast<Corona *>(gWidget->scene());
if (corona) {
corona->removeOffscreenWidget(gWidget);
}
lay->addItem(gWidget);
prefSize = gWidget->preferredSize().toSize();
} else if (qWidget) {
if (!proxy) {
proxy = new QGraphicsProxyWidget(q);
proxy.data()->setWidget(qWidget);
proxy.data()->show();
}
lay->addItem(proxy.data());
prefSize = qWidget->sizeHint();
}
//we could be on a big panel, but in that case we will be able to resize
//more than the natural minimum size, because we'll transform into an icon
if (f == Plasma::Horizontal) {
minimum.setHeight(0);
} else if (f == Plasma::Vertical) {
minimum.setWidth(0);
}
qreal left, top, right, bottom;
q->getContentsMargins(&left, &top, &right, &bottom);
QSizeF oldSize(q->size());
//size not saved/invalid size saved
if (oldSize.width() < q->minimumSize().width() || oldSize.height() < q->minimumSize().height()) {
q->resize(prefSize);
emit q->appletTransformedItself();
}
} else {
//Applet on popup
if (icon && lay) {
lay->addItem(icon);
}
//kDebug() << "about to switch to a popup";
if (!qWidget && !gWidget) {
delete dialogPtr.data();
return;
}
//there was already a dialog? don't make the switch again
if (dialogPtr) {
return;
}
if (proxy) {
proxy.data()->setWidget(0); // prevent it from deleting our widget!
delete proxy.data();
}
//save the aspect ratio mode in case we drag'n drop in the Desktop later
savedAspectRatio = q->aspectRatioMode();
if (icon) {
icon->show();
q->setAspectRatioMode(Plasma::ConstrainedSquare);
}
Dialog *dialog = new Dialog();
dialog->d->appletPtr = q;
dialogPtr = dialog;
if (icon) {
dialog->setAspectRatioMode(savedAspectRatio);
}
//no longer use Qt::Popup since that seems to cause a lot of problem when you drag
//stuff out of your Dialog (extenders). Monitor WindowDeactivate events so we can
//emulate the same kind of behavior as Qt::Popup (close when you click somewhere
//else.
if (gWidget) {
Corona *corona = qobject_cast<Corona *>(gWidget->scene());
if (!corona) {
corona = qobject_cast<Corona *>(q->scene());
}
if (corona) {
corona->addOffscreenWidget(gWidget);
}
gWidget->show();
dialog->setGraphicsWidget(gWidget);
dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (gWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
} else if (qWidget) {
QVBoxLayout *l_layout = new QVBoxLayout(dialog);
l_layout->setSpacing(0);
l_layout->setMargin(0);
l_layout->addWidget(qWidget);
dialog->adjustSize();
dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (qWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
} else {
dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
}
restoreDialogSize();
KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
dialog->installEventFilter(q);
QObject::connect(dialog, SIGNAL(dialogResized()), q, SLOT(dialogSizeChanged()));
QObject::connect(dialog, SIGNAL(dialogVisible(bool)), q, SLOT(dialogStatusChanged(bool)));
}
}
if (constraints & Plasma::PopupConstraint) {
updateDialogPosition();
}
if (icon) {
// emit the size hint changing stuff for our applet as we are handling
// the size changings
emit q->sizeHintChanged(Qt::PreferredSize);
}
}
void PopupAppletPrivate::appletActivated()
{
internalTogglePopup(true);
}
QSizeF PopupApplet::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
if (!d->dialogPtr || which != Qt::PreferredSize) {
return Applet::sizeHint(which, constraint);
}
switch (formFactor()) {
case Vertical:
case Horizontal: {
const int size = IconSize(KIconLoader::Panel);
return QSizeF(size, size);
}
default:
break;
}
const int size = IconSize(KIconLoader::Desktop);
return QSizeF(size, size);
}
void PopupApplet::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (!d->icon && !d->popupLostFocus && event->buttons() == Qt::LeftButton) {
d->clicked = scenePos().toPoint();
event->setAccepted(true);
return;
} else {
d->popupLostFocus = false;
Applet::mousePressEvent(event);
}
}
void PopupApplet::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (!d->icon &&
(d->clicked - scenePos().toPoint()).manhattanLength() < KGlobalSettings::dndEventDelay()) {
d->internalTogglePopup();
} else {
Applet::mouseReleaseEvent(event);
}
}
bool PopupApplet::eventFilter(QObject *watched, QEvent *event)
{
if (!d->passive && watched == d->dialogPtr.data() && (event->type() == QEvent::WindowDeactivate)) {
d->popupLostFocus = true;
QTimer::singleShot(100, this, SLOT(clearPopupLostFocus()));
}
if (watched == d->dialogPtr.data() && event->type() == QEvent::ContextMenu) {
//pass it up to the applet
//well, actually we have to pass it to the *containment*
//because all the code for showing an applet's contextmenu is actually in Containment.
Containment *c = containment();
if (c) {
Applet *applet = this;
Dialog *dialog = d->dialogPtr.data();
if (dialog && dialog->graphicsWidget()) {
int left, top, right, bottom;
dialog->getContentsMargins(&left, &top, &right, &bottom);
const QPoint eventPos = static_cast<QContextMenuEvent*>(event)->pos() - QPoint(left, top);
QPointF pos = dialog->graphicsWidget()->mapToScene(eventPos);
if (Applet *actual = c->d->appletAt(pos)) {
applet = actual;
}
}
KMenu desktopMenu;
c->d->addAppletActions(desktopMenu, applet, event);
if (!desktopMenu.isEmpty()) {
desktopMenu.exec(static_cast<QContextMenuEvent*>(event)->globalPos());
return true;
}
return false;
}
}
return Applet::eventFilter(watched, event);
}
void PopupApplet::showPopup(uint popupDuration)
{
// use autohideTimer to store when the next show should be
if (popupDuration > 0 || d->autohideTimer) {
if (!d->autohideTimer) {
d->autohideTimer = new QTimer(this);
d->autohideTimer->setSingleShot(true);
connect(d->autohideTimer, SIGNAL(timeout()), this, SLOT(hideTimedPopup()));
}
d->autohideTimer->stop();
d->autohideTimer->setInterval(popupDuration);
}
//kDebug() << "starting delayed show, duration for popup is" << popupDuration;
d->delayedShowTimer.start(0, this);
}
void PopupApplet::timerEvent(QTimerEvent *event)
{
if (event->timerId() == d->delayedShowTimer.timerId()) {
d->delayedShowTimer.stop();
Dialog *dialog = d->dialogPtr.data();
if (dialog) {
// move the popup before its fist show, even if the show isn't triggered by
// a click, this should fix the first random position seen in some widgets
if (!dialog->isVisible()) {
d->internalTogglePopup();
}
const int popupDuration = d->autohideTimer ? d->autohideTimer->interval() : 0;
//kDebug() << "popupDuration is:" << (d->autohideTimer ? d->autohideTimer->interval() : 0);
if (popupDuration > 0) {
d->autohideTimer->start();
} else if (d->autohideTimer) {
d->autohideTimer->stop();
}
}
} else if (event->timerId() == d->showDialogTimer.timerId()) {
d->showDialogTimer.stop();
d->showDialog();
} else {
Applet::timerEvent(event);
}
}
void PopupApplet::hidePopup()
{
d->showDialogTimer.stop();
d->delayedShowTimer.stop();
Dialog *dialog = d->dialogPtr.data();
if (dialog && dialog->isVisible()) {
if (location() != Floating) {
dialog->animatedHide(locationToInverseDirection(location()));
} else {
dialog->hide();
}
}
}
void PopupApplet::togglePopup()
{
d->internalTogglePopup();
}
Plasma::PopupPlacement PopupApplet::popupPlacement() const
{
return d->popupPlacement;
}
void PopupApplet::setPopupAlignment(Qt::AlignmentFlag alignment)
{
d->popupAlignment = alignment;
}
Qt::AlignmentFlag PopupApplet::popupAlignment() const
{
return d->popupAlignment;
}
void PopupApplet::popupEvent(bool popped)
{
if (Applet::d->script) {
emit Applet::d->script->popupEvent(popped);
}
}
void PopupApplet::setPassivePopup(bool passive)
{
d->passive = passive;
}
bool PopupApplet::isPassivePopup() const
{
return d->passive;
}
bool PopupApplet::isPopupShowing() const
{
return d->dialogPtr && d->dialogPtr.data()->isVisible();
}
bool PopupApplet::isIconified() const
{
return d->dialogPtr;
}
PopupAppletPrivate::PopupAppletPrivate(PopupApplet *applet)
: q(applet),
icon(0),
widget(0),
popupPlacement(Plasma::FloatingPopup),
popupAlignment(Qt::AlignLeft),
savedAspectRatio(Plasma::InvalidAspectRatioMode),
autohideTimer(0),
preShowStatus(UnknownStatus),
popupLostFocus(false),
passive(false)
{
int iconSize = IconSize(KIconLoader::Desktop);
q->resize(iconSize, iconSize);
q->setAcceptDrops(true);
QObject::disconnect(q, SIGNAL(activate()), static_cast<Applet*>(q), SLOT(setFocus()));
QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconSizeChanged(int)));
}
PopupAppletPrivate::~PopupAppletPrivate()
{
if (proxy) {
proxy.data()->setWidget(0);
}
delete dialogPtr.data();
delete icon;
}
void PopupAppletPrivate::iconSizeChanged(int group)
{
if (icon && (group == KIconLoader::Desktop || group == KIconLoader::Panel)) {
q->updateGeometry();
}
}
void PopupAppletPrivate::internalTogglePopup(bool fromActivatedSignal)
{
if (autohideTimer) {
autohideTimer->stop();
}
delayedShowTimer.stop();
Plasma::Dialog *dialog = dialogPtr.data();
if (!dialog) {
q->setFocus(Qt::ShortcutFocusReason);
if (!fromActivatedSignal) {
QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
emit q->activate();
QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
}
return;
}
if (!q->view()) {
return;
}
if (dialog->isVisible()) {
if (q->location() != Floating) {
dialog->animatedHide(locationToInverseDirection(q->location()));
} else {
dialog->hide();
}
dialog->clearFocus();
} else {
if (!graphicsWidget) {
// we have nothing to show, so let's not.
if (!fromActivatedSignal) {
QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
emit q->activate();
QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
}
return;
}
ToolTipManager::self()->hide(q);
showDialogTimer.start(0, q);
}
}
void PopupAppletPrivate::showDialog()
{
Plasma::Dialog *dialog = dialogPtr.data();
if (!dialog) {
return;
}
updateDialogPosition();
KWindowSystem::setOnAllDesktops(dialog->winId(), true);
KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
if (icon) {
dialog->setAspectRatioMode(savedAspectRatio);
}
if (q->location() != Floating) {
dialog->animatedShow(locationToDirection(q->location()));
} else {
dialog->show();
}
if (!(dialog->windowFlags() & Qt::X11BypassWindowManagerHint)) {
KWindowSystem::activateWindow(dialog->winId());
}
}
void PopupAppletPrivate::hideTimedPopup()
{
autohideTimer->stop();
q->hidePopup();
}
void PopupAppletPrivate::clearPopupLostFocus()
{
if (!icon || !icon->isDown()) {
q->hidePopup();
}
popupLostFocus = false;
}
KConfigGroup PopupAppletPrivate::popupConfigGroup()
{
KConfigGroup *mainGroup = static_cast<Applet*>(q)->d->mainConfigGroup();
return KConfigGroup(mainGroup, "PopupApplet");
}
void PopupAppletPrivate::dialogSizeChanged()
{
//Reposition the dialog
Plasma::Dialog *dialog = dialogPtr.data();
if (dialog) {
KConfigGroup sizeGroup = popupConfigGroup();
sizeGroup.writeEntry("DialogHeight", dialog->height());
sizeGroup.writeEntry("DialogWidth", dialog->width());
updateDialogPosition(!dialog->isUserResizing());
emit q->configNeedsSaving();
emit q->appletTransformedByUser();
}
}
void PopupAppletPrivate::dialogStatusChanged(bool shown)
{
if (shown) {
preShowStatus = q->status();
q->setStatus(NeedsAttentionStatus);
QObject::connect(q, SIGNAL(newStatus(Plasma::ItemStatus)),
q, SLOT(statusChangeWhileShown(Plasma::ItemStatus)),
Qt::UniqueConnection);
} else {
QObject::disconnect(q, SIGNAL(newStatus(Plasma::ItemStatus)),
q, SLOT(statusChangeWhileShown(Plasma::ItemStatus)));
q->setStatus(preShowStatus);
}
q->popupEvent(shown);
}
void PopupAppletPrivate::statusChangeWhileShown(Plasma::ItemStatus status)
{
preShowStatus = status;
}
void PopupAppletPrivate::createIconWidget()
{
if (icon) {
return;
}
icon = new Plasma::IconWidget(q);
QObject::connect(icon, SIGNAL(clicked()), q, SLOT(internalTogglePopup()));
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout();
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->setOrientation(Qt::Horizontal);
layout->addItem(icon);
layout->setAlignment(icon, Qt::AlignCenter);
q->setLayout(layout);
}
void PopupAppletPrivate::restoreDialogSize()
{
Plasma::Dialog *dialog = dialogPtr.data();
if (!dialog) {
return;
}
Corona *corona = qobject_cast<Corona *>(q->scene());
if (!corona) {
return;
}
KConfigGroup sizeGroup = popupConfigGroup();
int preferredWidth = 0;
int preferredHeight = 0;
QGraphicsWidget *gWidget = dialog->graphicsWidget();
if (gWidget) {
preferredWidth = gWidget->preferredSize().width();
preferredHeight = gWidget->preferredSize().height();
}
const int width = qMin(sizeGroup.readEntry("DialogWidth", preferredWidth),
corona->screenGeometry(-1).width() - 50);
const int height = qMin(sizeGroup.readEntry("DialogHeight", preferredHeight),
corona->screenGeometry(-1).height() - 50);
QSize saved(width, height);
if (saved.isNull()) {
saved = dialog->sizeHint();
} else {
saved = saved.expandedTo(dialog->minimumSizeHint());
}
if (saved.width() != dialog->width() || saved.height() != dialog->height()) {
dialog->resize(saved);
/*if (gWidget) {
gWidget->resize(saved);
}*/
}
}
void PopupAppletPrivate::updateDialogPosition(bool move)
{
Plasma::Dialog *dialog = dialogPtr.data();
if (!dialog) {
return;
}
Corona *corona = qobject_cast<Corona *>(q->scene());
if (!corona) {
return;
}
QGraphicsView *view = q->view();
if (!view) {
return;
}
const QPoint appletPos = view->mapToGlobal(view->mapFromScene(q->scenePos()));
QPoint dialogPos = dialog->pos();
if (move) {
if (!q->containment() || view == q->containment()->view()) {
dialogPos = corona->popupPosition(q, dialog->size(), popupAlignment);
} else {
dialogPos = corona->popupPosition(q->parentItem(), dialog->size(), popupAlignment);
}
}
bool reverse = false;
if (q->formFactor() == Plasma::Vertical) {
reverse = (appletPos.y() + (q->size().height() / 2)) < (dialogPos.y() + (dialog->size().height() / 2));
dialog->setMinimumResizeLimits(-1, appletPos.y(), -1, appletPos.y() + q->size().height());
} else {
reverse = (appletPos.x() + (q->size().width() / 2)) < (dialogPos.x() + (dialog->size().width() / 2));
dialog->setMinimumResizeLimits(appletPos.x(), -1, appletPos.x() + q->size().width(), -1);
}
Dialog::ResizeCorners resizeCorners = Dialog::NoCorner;
switch (q->location()) {
case BottomEdge:
resizeCorners = Dialog::NorthEast | Dialog::NorthWest;
popupPlacement = reverse ? TopPosedLeftAlignedPopup : TopPosedRightAlignedPopup;
break;
case TopEdge:
resizeCorners = Dialog::SouthEast | Dialog::SouthWest;
popupPlacement = reverse ? Plasma::BottomPosedLeftAlignedPopup : Plasma::BottomPosedRightAlignedPopup;
break;
case LeftEdge:
resizeCorners = Dialog::SouthEast | Dialog::NorthEast;
popupPlacement = reverse ? RightPosedTopAlignedPopup : RightPosedBottomAlignedPopup;
break;
case RightEdge:
resizeCorners = Dialog::SouthWest | Dialog::NorthWest;
popupPlacement = reverse ? LeftPosedTopAlignedPopup : LeftPosedBottomAlignedPopup;
break;
default:
popupPlacement = FloatingPopup;
resizeCorners = Dialog::All;
break;
}
dialog->setResizeHandleCorners(resizeCorners);
if (move) {
dialog->move(dialogPos);
}
}
} // Plasma namespace
+
+#include "moc_popupapplet.cpp"
diff --git a/plasma/private/datacontainer_p.cpp b/plasma/private/datacontainer_p.cpp
index 908ebe7036..71ca7b2e7d 100644
--- a/plasma/private/datacontainer_p.cpp
+++ b/plasma/private/datacontainer_p.cpp
@@ -1,169 +1,171 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "datacontainer.h" //krazy:exclude=includes
#include "datacontainer_p.h" //krazy:exclude=includes
namespace Plasma
{
SignalRelay *DataContainerPrivate::signalRelay(const DataContainer *dc, QObject *visualization,
uint pollingInterval,
Plasma::IntervalAlignment align,
bool immediateUpdate)
{
QMap<uint, SignalRelay *>::const_iterator relayIt = relays.constFind(pollingInterval);
SignalRelay *relay = 0;
//FIXME what if we have two applets with the same interval and different alignment?
if (relayIt == relays.constEnd()) {
relay = new SignalRelay(const_cast<DataContainer*>(dc), this,
pollingInterval, align, immediateUpdate);
relays[pollingInterval] = relay;
} else {
relay = relayIt.value();
}
relayObjects[visualization] = relay;
return relay;
}
bool DataContainerPrivate::hasUpdates()
{
if (cached) {
// SignalRelay needs us to pretend we did an update
cached = false;
return true;
}
return dirty;
}
SignalRelay::SignalRelay(DataContainer *parent, DataContainerPrivate *data, uint ival,
Plasma::IntervalAlignment align, bool immediateUpdate)
: QObject(parent),
dc(parent),
d(data),
m_interval(ival),
m_align(align),
m_resetTimer(true),
m_queued(true)
{
//kDebug() << "signal relay with time of" << m_timerId << "being set up";
m_timerId = startTimer(immediateUpdate ? 0 : m_interval);
if (m_align != Plasma::NoAlignment) {
checkAlignment();
}
}
int SignalRelay::receiverCount() const
{
return receivers(SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)));
}
bool SignalRelay::isUnused() const
{
return receivers(SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data))) < 1;
}
void SignalRelay::checkAlignment()
{
int newTime = 0;
QTime t = QTime::currentTime();
if (m_align == Plasma::AlignToMinute) {
int seconds = t.second();
if (seconds > 2) {
newTime = ((60 - seconds) * 1000) + 500;
}
} else if (m_align == Plasma::AlignToHour) {
int minutes = t.minute();
int seconds = t.second();
if (minutes > 1 || seconds > 10) {
newTime = ((60 - minutes) * 1000 * 60) +
((60 - seconds) * 1000) + 500;
}
}
if (newTime) {
killTimer(m_timerId);
m_timerId = startTimer(newTime);
m_resetTimer = true;
}
}
void SignalRelay::checkQueueing()
{
//kDebug() << m_queued;
if (m_queued) {
emit dataUpdated(dc->objectName(), d->data);
m_queued = false;
//TODO: should we re-align our timer at this point, to avoid
// constant queueing due to more-or-less constant time
// async update time? this might make sense for
// staggered accesses to the same source by multiple
// visualizations causing a minimumPollingInterval violation.
// it may not make sense for purely async-and-takes-a-while
// type operations (e.g. network fetching).
// we need more real world data before making such a change
// change
//
// killTimer(m_timerId);
// m_timerId = startTime(m_interval);
}
}
void SignalRelay::forceImmediateUpdate()
{
emit dataUpdated(dc->objectName(), d->data);
}
void SignalRelay::timerEvent(QTimerEvent *event)
{
if (event->timerId() != m_timerId) {
QObject::timerEvent(event);
return;
}
if (m_resetTimer) {
killTimer(m_timerId);
m_timerId = startTimer(m_interval);
m_resetTimer = false;
}
if (m_align != Plasma::NoAlignment) {
checkAlignment();
}
emit dc->updateRequested(dc);
if (d->hasUpdates()) {
//kDebug() << "emitting data updated directly" << d->data;
emit dataUpdated(dc->objectName(), d->data);
m_queued = false;
} else {
// the source wasn't actually updated; so let's put ourselves in the queue
// so we get a dataUpdated() call when the data does arrive
//kDebug() << "queued";
m_queued = true;
}
}
} // Plasma namespace
+
+#include "moc_datacontainer_p.cpp"
diff --git a/plasma/private/focusindicator.cpp b/plasma/private/focusindicator.cpp
index 1d0744fdd2..05f678d8a5 100644
--- a/plasma/private/focusindicator.cpp
+++ b/plasma/private/focusindicator.cpp
@@ -1,322 +1,322 @@
/*
* Copyright 2009 Marco Martin <notmart@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "focusindicator_p.h"
#include <QGraphicsSceneResizeEvent>
#include <QPainter>
#include <QStringBuilder>
#include <QStyleOptionGraphicsItem>
#include <plasma/theme.h>
#include <plasma/framesvg.h>
#include <plasma/animator.h>
namespace Plasma
{
FocusIndicator::FocusIndicator(QGraphicsWidget *parent, const QString &widget)
: QGraphicsWidget(parent),
m_parent(parent),
m_background(new Plasma::FrameSvg(this)),
m_isUnderMouse(false)
{
m_background->setImagePath(widget);
init(parent);
}
FocusIndicator::FocusIndicator(QGraphicsWidget *parent, FrameSvg *svg)
: QGraphicsWidget(parent),
m_parent(parent),
m_background(svg),
m_isUnderMouse(false)
{
init(parent);
}
void FocusIndicator::init(QGraphicsWidget *parent)
{
setVisible(!Theme::defaultTheme()->useNativeWidgetStyle());
setFlag(QGraphicsItem::ItemStacksBehindParent);
setAcceptsHoverEvents(true);
m_background->setCacheAllRenderedFrames(true);
m_fade = Animator::create(Animator::FadeAnimation, this);
m_fade->setTargetWidget(this);
m_fade->setProperty("startOpacity", 0.0);
m_fade->setProperty("targetOpacity", 1.0);
m_hoverAnimation = Animator::create(Animator::PixmapTransitionAnimation);
m_hoverAnimation->setProperty("duration", 250);
m_hoverAnimation->setTargetWidget(this);
m_testPrefix = "hover";
if (m_background->hasElementPrefix("shadow") ||
m_background->hasElement("shadow")) {
m_prefix = "shadow";
}
parent->installEventFilter(this);
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(syncGeometry()));
}
FocusIndicator::~FocusIndicator()
{
m_parent->removeEventFilter(this);
delete m_fade;
}
void FocusIndicator::setCustomGeometry(const QRectF &geometry)
{
if (m_customGeometry == geometry) {
return;
}
m_customGeometry = geometry;
syncGeometry();
}
void FocusIndicator::setCustomPrefix(const QString &prefix)
{
QString was = m_prefix;
if (!m_prefix.isEmpty() && !m_customPrefix.isEmpty()) {
m_prefix.remove(m_customPrefix);
}
m_customPrefix = prefix;
if (!m_prefix.isEmpty()) {
m_prefix.prepend(m_customPrefix);
}
m_testPrefix = m_customPrefix % "hover";
if (m_prefix.isEmpty()) {
m_prefix = m_customPrefix % "shadow";
}
if (m_prefix == was) {
return;
}
syncGeometry();
resizeEvent(0);
}
bool FocusIndicator::eventFilter(QObject *watched, QEvent *event)
{
if (Theme::defaultTheme()->useNativeWidgetStyle() ||
static_cast<QGraphicsWidget *>(watched) != m_parent || !m_parent ) {
return false;
}
if (event->type() == QEvent::GraphicsSceneHoverEnter) {
m_isUnderMouse = true;
} else if (event->type() == QEvent::GraphicsSceneHoverLeave) {
m_isUnderMouse = false;
}
switch (event->type()) {
case QEvent::GraphicsSceneHoverEnter:
if (!m_parent->hasFocus()) {
m_prefix = m_customPrefix % "hover";
syncGeometry();
m_hoverAnimation->stop();
if (m_background->hasElementPrefix(m_testPrefix)) {
m_background->setElementPrefix(m_customPrefix % "shadow");
m_hoverAnimation->setProperty("startPixmap", m_background->framePixmap());
m_background->setElementPrefix(m_customPrefix % "hover");
m_hoverAnimation->setProperty("targetPixmap", m_background->framePixmap());
} else if (m_background->hasElement(m_testPrefix)) {
m_hoverAnimation->setProperty("startPixmap", m_background->pixmap(m_customPrefix % "shadow"));
m_hoverAnimation->setProperty("targetPixmap", m_background->pixmap(m_customPrefix % "hover"));
}
m_hoverAnimation->start();
}
break;
case QEvent::GraphicsSceneHoverLeave:
if (!m_parent->hasFocus()) {
m_prefix = m_customPrefix % "shadow";
syncGeometry();
m_hoverAnimation->stop();
if (m_background->hasElementPrefix(m_testPrefix)) {
m_background->setElementPrefix(m_customPrefix % "hover");
m_hoverAnimation->setProperty("startPixmap", m_background->framePixmap());
m_background->setElementPrefix(m_customPrefix % "shadow");
m_hoverAnimation->setProperty("targetPixmap", m_background->framePixmap());
} else if (m_background->hasElement(m_testPrefix)) {
m_hoverAnimation->setProperty("startPixmap", m_background->pixmap(m_customPrefix % "hover"));
m_hoverAnimation->setProperty("targetPixmap", m_background->pixmap(m_customPrefix % "shadow"));
}
m_hoverAnimation->start();
}
break;
case QEvent::GraphicsSceneResize:
syncGeometry();
break;
case QEvent::FocusIn:
m_prefix = m_customPrefix % "focus";
syncGeometry();
m_hoverAnimation->stop();
if (m_background->hasElementPrefix(m_customPrefix % "focus")) {
//m_background->setElementPrefix(m_customPrefix % "shadow");
m_hoverAnimation->setProperty("startPixmap", m_background->framePixmap());
m_background->setElementPrefix(m_customPrefix % "focus");
m_hoverAnimation->setProperty("targetPixmap", m_background->framePixmap());
} else if (m_background->hasElement(m_customPrefix % "focus")) {
//m_hoverAnimation->setProperty("startPixmap", m_background->pixmap(m_customPrefix % "shadow"));
m_hoverAnimation->setProperty("targetPixmap", m_background->pixmap(m_customPrefix % "focus"));
}
m_hoverAnimation->start();
break;
case QEvent::FocusOut:
if (!m_isUnderMouse) {
m_prefix = m_customPrefix % "shadow";
syncGeometry();
m_hoverAnimation->stop();
if (m_background->hasElementPrefix(m_customPrefix % "focus")) {
m_background->setElementPrefix("focus");
m_hoverAnimation->setProperty("startPixmap", m_background->framePixmap());
m_background->setElementPrefix("shadow");
m_hoverAnimation->setProperty("targetPixmap", m_background->framePixmap());
} else if (m_background->hasElement(m_customPrefix % "focus")) {
m_hoverAnimation->setProperty("startPixmap", m_background->pixmap(m_customPrefix % "focus"));
m_hoverAnimation->setProperty("targetPixmap", m_background->pixmap(m_customPrefix % "shadow"));
}
m_hoverAnimation->start();
}
break;
default:
break;
};
return false;
}
void FocusIndicator::resizeEvent(QGraphicsSceneResizeEvent *)
{
if (m_background->hasElementPrefix(m_customPrefix % "shadow")) {
m_background->setElementPrefix(m_customPrefix % "shadow");
m_background->resizeFrame(size());
}
if (m_background->hasElementPrefix(m_customPrefix % "hover")) {
m_background->setElementPrefix(m_customPrefix % "hover");
m_background->resizeFrame(size());
}
if (m_background->hasElementPrefix(m_customPrefix % "focus")) {
m_background->setElementPrefix(m_customPrefix % "focus");
m_background->resizeFrame(size());
}
if (m_hoverAnimation->state() == QAbstractAnimation::Running) {
m_hoverAnimation->stop();
}
if (m_background->hasElementPrefix(m_testPrefix)) {
m_background->setElementPrefix(m_prefix);
m_hoverAnimation->setProperty("startPixmap", m_background->framePixmap());
m_hoverAnimation->setProperty("targetPixmap", m_background->framePixmap());
} else if (m_background->hasElement(m_testPrefix)) {
m_hoverAnimation->setProperty("startPixmap", m_background->pixmap(m_prefix));
m_hoverAnimation->setProperty("targetPixmap", m_background->pixmap(m_prefix));
}
}
void FocusIndicator::animateVisibility(const bool visible)
{
m_fade->setProperty("startOpacity", opacity());
if (visible) {
m_fade->setProperty("targetOpacity", 1.0);
} else {
m_fade->setProperty("targetOpacity", 0);
}
m_fade->start();
}
void FocusIndicator::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
painter->drawPixmap(
option->rect,
m_hoverAnimation->property("currentPixmap").value<QPixmap>());
}
void FocusIndicator::syncGeometry()
{
if (Theme::defaultTheme()->useNativeWidgetStyle()) {
hide();
return;
} else if (!isVisible()) {
show();
}
QRectF geom;
if (!m_customGeometry.isEmpty()) {
geom = m_customGeometry;
} else {
geom = m_parent->boundingRect();
}
if (m_background->hasElementPrefix(m_testPrefix)) {
//always take borders from hover to make it stable
m_background->setElementPrefix(m_testPrefix);
qreal left, top, right, bottom;
m_background->getMargins(left, top, right, bottom);
m_background->setElementPrefix(m_prefix);
setGeometry(QRectF(geom.topLeft() + QPointF(-left, -top), geom.size() + QSize(left+right, top+bottom)));
} else if (m_background->hasElement(m_testPrefix)) {
QRectF elementRect = m_background->elementRect(m_testPrefix);
elementRect.moveCenter(geom.center());
setGeometry(elementRect);
}
}
void FocusIndicator::setFrameSvg(FrameSvg *frameSvg)
{
if (m_background != frameSvg) {
m_background = frameSvg;
}
}
FrameSvg *FocusIndicator::frameSvg() const
{
return m_background;
}
}
-#include <focusindicator_p.moc>
+#include "moc_focusindicator_p.cpp"
diff --git a/plasma/private/qtjolie-branch/qtjolie/abstractadaptor.cpp b/plasma/private/qtjolie-branch/qtjolie/abstractadaptor.cpp
index 5352ba0fe3..f16c13a729 100644
--- a/plasma/private/qtjolie-branch/qtjolie/abstractadaptor.cpp
+++ b/plasma/private/qtjolie-branch/qtjolie/abstractadaptor.cpp
@@ -1,41 +1,43 @@
/**
* This file is part of the KDE project
* Copyright (C) 2009 Kevin Ottens <ervin@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "abstractadaptor.h"
namespace Jolie
{
class AbstractAdaptorPrivate
{
};
}
using namespace Jolie;
AbstractAdaptor::AbstractAdaptor(QObject *parent)
: QObject(parent), d(new AbstractAdaptorPrivate)
{
}
AbstractAdaptor::~AbstractAdaptor()
{
delete d;
}
+
+#include "moc_abstractadaptor.cpp"
diff --git a/plasma/private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp b/plasma/private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp
index 250eb5c316..1d669e9f0e 100644
--- a/plasma/private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp
+++ b/plasma/private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp
@@ -1,48 +1,50 @@
/**
* This file is part of the KDE project
* Copyright (C) 2009 Kevin Ottens <ervin@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "pendingcallwatcher.h"
#include "pendingcall_p.h"
using namespace Jolie;
PendingCallWatcher::PendingCallWatcher(const PendingCall &other, QObject *parent)
: QObject(parent), PendingCall(other.d)
{
d->watchers << this;
}
PendingCallWatcher::~PendingCallWatcher()
{
d->watchers.removeAll(this);
}
bool PendingCallWatcher::isFinished() const
{
return d->isFinished;
}
void PendingCallWatcher::waitForFinished()
{
PendingCallWaiter waiter;
waiter.waitForFinished(d.data());
}
+
+#include "moc_pendingcallwatcher.cpp"
diff --git a/plasma/remote/accessappletjob.cpp b/plasma/remote/accessappletjob.cpp
index 785b08775d..033b109e29 100644
--- a/plasma/remote/accessappletjob.cpp
+++ b/plasma/remote/accessappletjob.cpp
@@ -1,208 +1,210 @@
/*
* Copyright 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License 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 "accessappletjob.h"
#include <qtimer.h>
#include <qtemporarydir.h>
#include <kdebug.h>
#include <kdesktopfile.h>
#include <kmessagebox.h>
#include <kzip.h>
#include "config-plasma.h"
#include "applet.h"
#include "package.h"
#include "pluginloader.h"
#include "private/applet_p.h"
#include "service.h"
#include "servicejob.h"
namespace Plasma
{
class AccessAppletJobPrivate
{
public:
AccessAppletJobPrivate(const KUrl &location, AccessAppletJob *owner)
: q(owner),
location(location),
applet(0)
{
}
void slotStart()
{
q->start();
}
void slotServiceReady(Plasma::Service *service)
{
KConfigGroup op = service->operationDescription("GetPackage");
service->startOperationCall(op);
q->connect(service, SIGNAL(finished(Plasma::ServiceJob*)),
q, SLOT(slotPackageDownloaded(Plasma::ServiceJob*)));
}
void slotPackageDownloaded(Plasma::ServiceJob *job)
{
if (job->error()) {
#ifndef NDEBUG
kDebug() << "Plasmoid Access Job triggers an error.";
#endif
q->setError(job->error());
q->setErrorText(job->errorText());
}
//TODO: there's some duplication with installPackage, but we don't want to actually install
//the fetched package. Just extract the archive somewhere in a temp directory.
if (job->result().type() == QVariant::String) {
QString pluginName = job->result().toString();
#ifndef NDEBUG
kDebug() << "Server responded with a pluginname, trying to load: " << pluginName;
#endif
applet = PluginLoader::self()->loadApplet(pluginName);
if (applet) {
applet->d->remoteLocation = location;
} else {
q->setError(-1);
q->setErrorText(i18n("The \"%1\" widget is not installed.", pluginName));
}
q->emitResult();
} else {
#ifndef NDEBUG
kDebug() << "Server responded with a plasmoid package";
#endif
//read, and extract the plasmoid package to a temporary directory
QByteArray package = job->result().toByteArray();
QDataStream stream(&package, QIODevice::ReadOnly);
KZip archive(stream.device());
if (!archive.open(QIODevice::ReadOnly)) {
kWarning() << "Could not open package file";
q->setError(-1);
q->setErrorText(i18n("Server sent an invalid plasmoid package."));
q->emitResult();
return;
}
const KArchiveDirectory *source = archive.directory();
QTemporaryDir tempDir;
tempDir.setAutoRemove(false);
QString path = tempDir.path() + '/';
source->copyTo(path);
KDesktopFile metadata(path + "/metadata.desktop");
KConfigGroup group = metadata.desktopGroup();
QString iconName = group.readEntry("Icon");
QString message = i18n("You are about to open a remote widget on your system.<br>");
message+= i18n("<table width=\"100%\">");
message+= i18n("<tr><td align=\"right\"><b>Name:</b></td><td>&nbsp; %1</td></tr>", group.readEntry("Name"));
message+= i18n("<tr><td align=\"right\"><b>Description:</b></td><td>&nbsp; %1</td></tr>", group.readEntry("Comment"));
message+= i18n("<tr><td align=\"right\"><b>Author:</b></td><td>&nbsp; %1 &lt;%2&gt;</td></tr>",
group.readEntry("X-KDE-PluginInfo-Author"),
group.readEntry("X-KDE-PluginInfo-Email"));
message+= i18n("<tr><td align=\"right\"><b>Server:</b></td><td>&nbsp; %1</td></tr>", location.host());
message+= i18n("</table>");
message+= i18n("<br><br>Are you sure you want to open this widget on your system?");
KDialog *dialog = new KDialog;
dialog->setWindowTitle(i18n("Remote Widget"));
dialog->setButtons(KDialog::Yes|KDialog::No);
dialog->setButtonText(KDialog::Yes, i18n("Open Widget"));
dialog->setButtonText(KDialog::No, i18n("Reject Widget"));
int answer = KMessageBox::createKMessageBox(dialog, KIcon(iconName), message,
QStringList(), QString(), 0,
KMessageBox::Dangerous);
if (answer!=KDialog::Yes) {
q->setError(-1);
q->setErrorText(i18nc("A remote widget was rejected by the user.", "User rejected"));
q->emitResult();
return;
}
applet = Applet::loadPlasmoid(path);
if (applet) {
applet->d->remoteLocation = location;
} else {
q->setError(-1);
}
q->emitResult();
}
}
void slotTimeout()
{
kWarning() << "Plasmoid access job timed out";
q->setError(-1);
q->setErrorText(i18n("Timeout"));
q->emitResult();
}
AccessAppletJob *q;
KUrl location;
Applet *applet;
};
AccessAppletJob::AccessAppletJob(const KUrl &location, QObject *parent)
: KJob(parent),
d(new AccessAppletJobPrivate(location, this))
{
QTimer::singleShot(30000, this, SLOT(slotTimeout()));
}
AccessAppletJob::~AccessAppletJob()
{
delete d;
}
Applet *AccessAppletJob::applet() const
{
return d->applet;
}
void AccessAppletJob::start()
{
#ifdef ENABLE_REMOTE_WIDGETS
#ifndef NDEBUG
kDebug() << "fetching a plasmoid from location = " << d->location.prettyUrl();
#endif
Service *service = Service::access(d->location);
connect(service, SIGNAL(serviceReady(Plasma::Service*)),
this, SLOT(slotServiceReady(Plasma::Service*)));
#else
kWarning() << "libplasma was compiled without support for remote services. Accessing remote applet failed because of that.";
setError(-1);
setErrorText(i18n("Your system does not provide support for the 'remote widgets' feature. Access Failed."));
emitResult();
#endif
}
} // namespace Plasma
+
+#include "moc_accessappletjob.cpp"
diff --git a/plasma/remote/accessmanager.cpp b/plasma/remote/accessmanager.cpp
index 2920a59b18..1ca3c195dc 100644
--- a/plasma/remote/accessmanager.cpp
+++ b/plasma/remote/accessmanager.cpp
@@ -1,273 +1,275 @@
/*
* Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "accessmanager.h"
#include "private/accessmanager_p.h"
#include "authorizationmanager.h"
#include "authorizationmanager_p.h"
#include "service.h"
#include "serviceaccessjob.h"
#include "config-plasma.h"
#include <QtCore/QMap>
#include <QtCore/QTimer>
#include <dnssd/remoteservice.h>
#include <dnssd/servicebrowser.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kurl.h>
#include <QtJolie/Message>
namespace Plasma
{
class RemoteObjectDescription::Private
{
public:
QString name;
QString description;
QString icon;
KUrl url;
};
RemoteObjectDescription::RemoteObjectDescription()
: d(new Private)
{
}
RemoteObjectDescription::RemoteObjectDescription(const RemoteObjectDescription &other)
: d(new Private(*other.d))
{
}
RemoteObjectDescription &RemoteObjectDescription::operator=(const RemoteObjectDescription &other)
{
*d = *other.d;
return *this;
}
void RemoteObjectDescription::setName(const QString &name)
{
d->name = name;
}
QString RemoteObjectDescription::name() const
{
return d->name;
}
void RemoteObjectDescription::setUrl(const KUrl &url)
{
d->url = url;
}
KUrl RemoteObjectDescription::url() const
{
return d->url;
}
void RemoteObjectDescription::setDescription(const QString &description)
{
d->description = description;
}
QString RemoteObjectDescription::description() const
{
return d->description;
}
void RemoteObjectDescription::setIcon(const QString &icon)
{
d->icon = icon;
}
QString RemoteObjectDescription::icon() const
{
return d->icon;
}
class AccessManagerSingleton
{
public:
AccessManager self;
};
K_GLOBAL_STATIC(AccessManagerSingleton, privateAccessManagerSelf)
AccessManager *AccessManager::self()
{
return &privateAccessManagerSelf->self;
}
AccessManager::AccessManager()
: QObject(),
d(new AccessManagerPrivate(this))
{
KGlobal::dirs()->addResourceType("trustedkeys", "config", "trustedkeys/");
}
AccessManager::~AccessManager()
{
delete d;
}
AccessAppletJob *AccessManager::accessRemoteApplet(const KUrl &location) const
{
AuthorizationManager::self()->d->prepareForServiceAccess();
KUrl resolvedLocation;
if (location.scheme() == "plasma+zeroconf") {
if (d->zeroconfServices.contains(location.host())) {
resolvedLocation = d->services[location.host()].url();
} else {
#ifndef NDEBUG
kDebug() << "There's no zeroconf service with this name.";
#endif
}
} else {
resolvedLocation = location;
}
AccessAppletJob *job = new AccessAppletJob(resolvedLocation);
connect(job, SIGNAL(finished(KJob*)), this, SLOT(slotJobFinished(KJob*)));
QTimer::singleShot(0, job, SLOT(slotStart()));
return job;
}
QList<RemoteObjectDescription> AccessManager::remoteApplets() const
{
return d->services.values();
}
QStringList AccessManager::supportedProtocols()
{
QStringList list;
list << "plasma" << "plasma+zeroconf";
return list;
}
AccessManagerPrivate::AccessManagerPrivate(AccessManager *manager)
: q(manager),
browser(new DNSSD::ServiceBrowser("_plasma._tcp"))
{
#ifdef ENABLE_REMOTE_WIDGETS
q->connect(browser, SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)),
q, SLOT(slotAddService(DNSSD::RemoteService::Ptr)));
q->connect(browser, SIGNAL(serviceRemoved(DNSSD::RemoteService::Ptr)),
q, SLOT(slotRemoveService(DNSSD::RemoteService::Ptr)));
browser->startBrowse();
#else
kWarning() << "libplasma is compiled without support for remote widgets. not monitoring remote widgets on the network";
#endif
}
AccessManagerPrivate::~AccessManagerPrivate()
{
delete browser;
}
void AccessManagerPrivate::slotJobFinished(KJob *job)
{
emit q->finished(static_cast<AccessAppletJob*>(job));
}
void AccessManagerPrivate::slotAddService(DNSSD::RemoteService::Ptr service)
{
#ifndef NDEBUG
kDebug();
#endif
if (!service->resolve()) {
#ifndef NDEBUG
kDebug() << "Zeroconf service can't be resolved";
#endif
return;
}
if (!services.contains(service->serviceName())) {
RemoteObjectDescription metadata;
#ifndef NDEBUG
kDebug() << "textdata = " << service->textData();
#endif
#ifndef NDEBUG
kDebug() << "hostname: " << service->hostName();
#endif
QHostAddress address = DNSSD::ServiceBrowser::resolveHostName(service->hostName());
QString ip = address.toString();
#ifndef NDEBUG
kDebug() << "result for resolve = " << ip;
#endif
KUrl url(QString("plasma://%1:%2/%3").arg(ip)
.arg(service->port())
.arg(service->serviceName()));
if (service->textData().isEmpty()) {
#ifndef NDEBUG
kDebug() << "no textdata?";
#endif
metadata.setName(service->serviceName());
metadata.setUrl(url);
} else {
#ifndef NDEBUG
kDebug() << "service has got textdata";
#endif
QMap<QString, QByteArray> textData = service->textData();
metadata.setName(textData["name"]);
metadata.setDescription(textData["description"]);
metadata.setIcon(textData["icon"]);
metadata.setUrl(url);
}
#ifndef NDEBUG
kDebug() << "location = " << metadata.url();
#endif
#ifndef NDEBUG
kDebug() << "name = " << metadata.name();
#endif
#ifndef NDEBUG
kDebug() << "description = " << metadata.name();
#endif
services[service->serviceName()] = metadata;
zeroconfServices[service->serviceName()] = service;
emit q->remoteAppletAnnounced(metadata);
}
}
void AccessManagerPrivate::slotRemoveService(DNSSD::RemoteService::Ptr service)
{
#ifndef NDEBUG
kDebug();
#endif
emit q->remoteAppletUnannounced(services[service->serviceName()]);
services.remove(service->serviceName());
zeroconfServices.remove(service->serviceName());
}
} // Plasma namespace
+
+#include "moc_accessmanager.cpp"
diff --git a/plasma/remote/authorizationmanager.cpp b/plasma/remote/authorizationmanager.cpp
index 17b72b4301..e2c898b4bf 100644
--- a/plasma/remote/authorizationmanager.cpp
+++ b/plasma/remote/authorizationmanager.cpp
@@ -1,316 +1,318 @@
/*
* Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "authorizationmanager.h"
#include "authorizationmanager_p.h"
#include "authorizationinterface.h"
#include "authorizationrule.h"
#include "authorizationrule_p.h"
#include "denyallauthorization_p.h"
#include "credentials.h"
#include "pinpairingauthorization_p.h"
#include "service.h"
#include "servicejob.h"
#include "trustedonlyauthorization_p.h"
#include "private/joliemessagehelper_p.h"
#include <QtCore/QBuffer>
#include <QtCore/QMap>
#include <QtCore/QMetaType>
#include <QtCore/QTimer>
#include <qtemporaryfile.h>
#include <QtNetwork/QHostInfo>
#include <QtJolie/Message>
#include <QtJolie/Server>
#include <kauthaction.h>
#include <kconfiggroup.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <kurl.h>
#include <kwallet.h>
namespace Plasma
{
class AuthorizationManagerSingleton
{
public:
AuthorizationManager self;
};
K_GLOBAL_STATIC(AuthorizationManagerSingleton, privateAuthorizationManagerSelf)
AuthorizationManager *AuthorizationManager::self()
{
return &privateAuthorizationManagerSelf->self;
}
AuthorizationManager::AuthorizationManager()
: QObject(),
d(new AuthorizationManagerPrivate(this))
{
qRegisterMetaTypeStreamOperators<Plasma::Credentials>("Plasma::Credentials");
}
AuthorizationManager::~AuthorizationManager()
{
delete d;
}
void AuthorizationManager::setAuthorizationPolicy(AuthorizationPolicy policy)
{
if (d->locked) {
#ifndef NDEBUG
kDebug() << "Can't change AuthorizationPolicy: interface locked.";
#endif
return;
}
if (policy == d->authorizationPolicy) {
return;
}
d->authorizationPolicy = policy;
if (d->authorizationInterface != d->customAuthorizationInterface) {
delete d->authorizationInterface;
}
switch (policy) {
case DenyAll:
d->authorizationInterface = new DenyAllAuthorization();
break;
case PinPairing:
d->authorizationInterface = new PinPairingAuthorization();
break;
case TrustedOnly:
d->authorizationInterface = new TrustedOnlyAuthorization();
break;
case Custom:
d->authorizationInterface = d->customAuthorizationInterface;
break;
}
d->locked = true;
}
void AuthorizationManager::setAuthorizationInterface(AuthorizationInterface *interface)
{
if (d->authorizationInterface) {
#ifndef NDEBUG
kDebug() << "Can't change AuthorizationInterface: interface locked.";
#endif
return;
}
delete d->customAuthorizationInterface;
d->customAuthorizationInterface = interface;
if (d->authorizationPolicy == Custom) {
d->authorizationInterface = interface;
}
}
AuthorizationManagerPrivate::AuthorizationManagerPrivate(AuthorizationManager *manager)
: q(manager),
server(0),
authorizationPolicy(AuthorizationManager::DenyAll),
authorizationInterface(new DenyAllAuthorization()),
customAuthorizationInterface(0),
rulesConfig(KSharedConfig::openConfig("/etc/plasma-remotewidgets.conf")->group("Rules")),
locked(false)
{
}
AuthorizationManagerPrivate::~AuthorizationManagerPrivate()
{
delete authorizationInterface;
delete customAuthorizationInterface;
delete server;
}
void AuthorizationManagerPrivate::prepareForServiceAccess()
{
if (myCredentials.isValid()) {
return;
}
wallet = KWallet::Wallet::openWallet("kdewallet", 0, KWallet::Wallet::Asynchronous);
q->connect(wallet, SIGNAL(walletOpened(bool)), q, SLOT(slotWalletOpened()));
QTimer::singleShot(0, q, SLOT(slotLoadRules()));
}
void AuthorizationManagerPrivate::prepareForServicePublication()
{
if (!server) {
server = new Jolie::Server(4000);
}
}
void AuthorizationManagerPrivate::saveRules()
{
#ifndef NDEBUG
kDebug() << "SAVE RULES";
#endif
QTemporaryFile tempFile;
tempFile.open();
tempFile.setAutoRemove(false);
KConfigGroup rulesGroup = KSharedConfig::openConfig(tempFile.fileName())->group("Rules");
int i = 0;
foreach (AuthorizationRule *rule, rules) {
if (rule->persistence() == AuthorizationRule::Persistent) {
#ifndef NDEBUG
kDebug() << "adding rule " << i;
#endif
rulesGroup.group(QString::number(i)).writeEntry("CredentialsID", rule->credentials().id());
rulesGroup.group(QString::number(i)).writeEntry("serviceName", rule->serviceName());
rulesGroup.group(QString::number(i)).writeEntry("Policy", (uint)rule->policy());
rulesGroup.group(QString::number(i)).writeEntry("Targets", (uint)rule->targets());
rulesGroup.group(QString::number(i)).writeEntry("Persistence", (uint)rule->persistence());
i++;
}
}
rulesGroup.sync();
tempFile.close();
#ifndef NDEBUG
kDebug() << "tempfile = " << tempFile.fileName();
#endif
KAuth::Action action("org.kde.kcontrol.kcmremotewidgets.save");
action.addArgument("source", tempFile.fileName());
action.addArgument("filename", "/etc/plasma-remotewidgets.conf");
KAuth::ActionReply reply = action.execute();
if (reply.failed()) {
#ifndef NDEBUG
kDebug() << "KAuth failed.... YOU SUCK!";
#endif
}
}
void AuthorizationManagerPrivate::slotWalletOpened()
{
QByteArray identity;
if (!wallet->readEntry("Credentials", identity)) {
#ifndef NDEBUG
kDebug() << "Existing identity found";
#endif
QDataStream stream(&identity, QIODevice::ReadOnly);
stream >> myCredentials;
}
if (!myCredentials.isValid()) {
#ifndef NDEBUG
kDebug() << "Creating a new identity";
#endif
myCredentials = Credentials::createCredentials(QHostInfo::localHostName());
QDataStream stream(&identity, QIODevice::WriteOnly);
stream << myCredentials;
wallet->writeEntry("Credentials", identity);
}
emit q->readyForRemoteAccess();
}
void AuthorizationManagerPrivate::slotLoadRules()
{
foreach (const QString &groupName, rulesConfig.groupList()) {
QString identityID = rulesConfig.group(groupName).readEntry("CredentialsID", "");
QString serviceName = rulesConfig.group(groupName).readEntry("serviceName", "");
uint policy = rulesConfig.group(groupName).readEntry("Policy", 0);
uint targets = rulesConfig.group(groupName).readEntry("Targets", 0);
uint persistence = rulesConfig.group(groupName).readEntry("Persistence", 0);
//Credentials storedCredentials = identities[identityID];
if (serviceName.isEmpty()) {
#ifndef NDEBUG
kDebug() << "Invalid rule";
#endif
} else {
AuthorizationRule *rule = new AuthorizationRule(serviceName, identityID);
rule->setPolicy(static_cast<AuthorizationRule::Policy>(policy));
rule->setTargets(static_cast<AuthorizationRule::Targets>(targets));
rule->setPersistence(static_cast<AuthorizationRule::Persistence>(persistence));
rules.append(rule);
}
}
}
AuthorizationRule *AuthorizationManagerPrivate::matchingRule(const QString &serviceName,
const Credentials &identity) const
{
AuthorizationRule *matchingRule = 0;
foreach (AuthorizationRule *rule, rules) {
if (rule->d->matches(serviceName, identity.id())) {
//a message can have multiple matching rules, consider priorities: the more specific the
//rule is, the higher it's priority
if (!matchingRule) {
matchingRule = rule;
} else {
if (!matchingRule->targets().testFlag(AuthorizationRule::AllServices) &&
!matchingRule->targets().testFlag(AuthorizationRule::AllUsers)) {
matchingRule = rule;
}
}
}
}
if (!matchingRule) {
#ifndef NDEBUG
kDebug() << "no matching rule";
#endif
} else {
#ifndef NDEBUG
kDebug() << "matching rule found: " << matchingRule->description();
#endif
}
return matchingRule;
}
Credentials AuthorizationManagerPrivate::getCredentials(const QString &id)
{
if (identities.contains(id)) {
return identities[id];
} else {
return Credentials();
}
}
void AuthorizationManagerPrivate::addCredentials(const Credentials &identity)
{
if (identities.contains(identity.id())) {
return;
} else if (identity.isValid()) {
#ifndef NDEBUG
kDebug() << "Adding a new identity for " << identity.id();
#endif
identities[identity.id()] = identity;
}
}
} // Plasma namespace
+
+#include "moc_authorizationmanager.cpp"
diff --git a/plasma/remote/authorizationrule.cpp b/plasma/remote/authorizationrule.cpp
index bac6a292bd..9f40dead1d 100644
--- a/plasma/remote/authorizationrule.cpp
+++ b/plasma/remote/authorizationrule.cpp
@@ -1,170 +1,172 @@
/*
* Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "authorizationrule.h"
#include "authorizationmanager.h"
#include "authorizationmanager_p.h"
#include "authorizationrule_p.h"
#include "credentials.h"
#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <kurl.h>
#include <klocalizedstring.h>
namespace Plasma
{
AuthorizationRulePrivate::AuthorizationRulePrivate(const QString &serviceName, const QString &credentialID,
AuthorizationRule *rule)
: q(rule),
serviceName(serviceName),
credentialID(credentialID),
policy(AuthorizationRule::Deny),
targets(AuthorizationRule::Default),
persistence(AuthorizationRule::Transient)
{
}
AuthorizationRulePrivate::~AuthorizationRulePrivate()
{
}
bool AuthorizationRulePrivate::matches(const QString &name, const QString &id) const
{
if (serviceName == name && (credentialID == id)) {
return true;
}
if (targets.testFlag(AuthorizationRule::AllUsers) && (serviceName == name)) {
return true;
}
if (targets.testFlag(AuthorizationRule::AllServices) && (credentialID == id)) {
return true;
}
return false;
}
void AuthorizationRulePrivate::scheduleChangedSignal()
{
QTimer::singleShot(0, q, SLOT(fireChangedSignal()));
}
void AuthorizationRulePrivate::fireChangedSignal()
{
if ((persistence == AuthorizationRule::Persistent) &&
(policy != AuthorizationRule::PinRequired)) {
AuthorizationManager::self()->d->saveRules();
}
emit q->changed(q);
}
AuthorizationRule::AuthorizationRule(const QString &serviceName, const QString &credentialID)
: QObject(AuthorizationManager::self()),
d(new AuthorizationRulePrivate(serviceName, credentialID, this))
{
}
AuthorizationRule::~AuthorizationRule()
{
delete d;
}
QString AuthorizationRule::description() const
{
//i18n megafest :p
if (d->targets.testFlag(AllUsers) && d->policy == Allow) {
return i18n("Allow everybody access to %1.", d->serviceName);
} else if (d->targets.testFlag(AllUsers) && d->policy == Deny) {
return i18n("Deny everybody access to %1", d->serviceName);
} else if (d->targets.testFlag(AllServices) && d->policy == Allow) {
return i18n("Allow %1 access to all services.", credentials().name());
} else if (d->targets.testFlag(AllServices) && d->policy == Deny) {
return i18n("Deny %1 access to all services.", credentials().name());
} else if (d->policy == Allow) {
return i18n("Allow access to %1, by %2.", d->serviceName, credentials().name());
} else if (d->policy == Deny) {
return i18n("Deny access to %1, by %2.", d->serviceName, credentials().name());
} else {
return i18n("Allow access to %1, by %2?", d->serviceName, credentials().name());
}
}
void AuthorizationRule::setPolicy(Policy policy)
{
d->policy = policy;
d->scheduleChangedSignal();
}
AuthorizationRule::Policy AuthorizationRule::policy()
{
return d->policy;
}
void AuthorizationRule::setTargets(Targets targets)
{
d->targets = targets;
d->scheduleChangedSignal();
}
AuthorizationRule::Targets AuthorizationRule::targets()
{
return d->targets;
}
void AuthorizationRule::setPersistence(Persistence persistence)
{
d->persistence = persistence;
d->scheduleChangedSignal();
}
AuthorizationRule::Persistence AuthorizationRule::persistence()
{
return d->persistence;
}
void AuthorizationRule::setPin(const QString &pin)
{
d->pin = pin;
d->scheduleChangedSignal();
}
QString AuthorizationRule::pin() const
{
return d->pin;
}
Credentials AuthorizationRule::credentials() const
{
return AuthorizationManager::self()->d->getCredentials(d->credentialID);
}
QString AuthorizationRule::serviceName() const
{
return d->serviceName;
}
} // Plasma namespace
+
+#include "moc_authorizationrule.cpp"
diff --git a/plasma/remote/clientpinrequest.cpp b/plasma/remote/clientpinrequest.cpp
index 568650522c..62391c5f99 100644
--- a/plasma/remote/clientpinrequest.cpp
+++ b/plasma/remote/clientpinrequest.cpp
@@ -1,77 +1,79 @@
/*
* Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "clientpinrequest.h"
#include "service.h"
#include "private/remoteservice_p.h"
#include <kdebug.h>
#include <klocalizedstring.h>
namespace Plasma
{
class ClientPinRequestPrivate {
public:
ClientPinRequestPrivate(RemoteService *service)
: service(service)
{
}
~ClientPinRequestPrivate() {}
RemoteService *service;
QString pin;
};
ClientPinRequest::ClientPinRequest(RemoteService *service)
: QObject(service),
d(new ClientPinRequestPrivate(service))
{
}
ClientPinRequest::~ClientPinRequest()
{
delete d;
}
QString ClientPinRequest::description() const
{
return i18n("You have requested access to the %1 hosted at %2.", d->service->name(),
d->service->location());
}
void ClientPinRequest::setPin(const QString &pin)
{
#ifndef NDEBUG
kDebug() << "pin = " << pin;
#endif
d->pin = pin;
emit changed(this);
}
QString ClientPinRequest::pin() const
{
return d->pin;
}
} // Plasma namespace
+
+#include "moc_clientpinrequest.cpp"
diff --git a/plasma/remote/serviceaccessjob.cpp b/plasma/remote/serviceaccessjob.cpp
index 4ff0ffc306..18c25ea740 100644
--- a/plasma/remote/serviceaccessjob.cpp
+++ b/plasma/remote/serviceaccessjob.cpp
@@ -1,75 +1,77 @@
/*
* Copyright 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License 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 "serviceaccessjob.h"
#include "private/remoteservice_p.h"
namespace Plasma
{
class ServiceAccessJobPrivate
{
public:
ServiceAccessJobPrivate(ServiceAccessJob *owner, KUrl location)
: q(owner),
service(0),
location(location)
{
}
void slotStart()
{
q->start();
}
void slotServiceReady()
{
q->emitResult();
}
ServiceAccessJob *q;
Service *service;
KUrl location;
};
ServiceAccessJob::ServiceAccessJob(KUrl location, QObject *parent)
: KJob(parent),
d(new ServiceAccessJobPrivate(this, location))
{
}
ServiceAccessJob::~ServiceAccessJob()
{
delete d;
}
Service *ServiceAccessJob::service() const
{
return d->service;
}
void ServiceAccessJob::start()
{
d->service = new RemoteService(parent(), d->location);
connect(d->service, SIGNAL(ready()), this, SLOT(slotServiceReady()));
}
} // namespace Plasma
+
+#include "moc_serviceaccessjob.cpp"
diff --git a/plasma/runnercontext.cpp b/plasma/runnercontext.cpp
index 5c4147e667..a419861623 100644
--- a/plasma/runnercontext.cpp
+++ b/plasma/runnercontext.cpp
@@ -1,549 +1,551 @@
/*
* 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 "runnercontext.h"
#include <cmath>
#include <QReadWriteLock>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSharedData>
#include <kcompletion.h>
#include <kconfiggroup.h>
#include <kdebug.h>
#include <kmimetype.h>
#include <kshell.h>
#include <kstandarddirs.h>
#include <kurl.h>
#include <kprotocolinfo.h>
#include "abstractrunner.h"
#include "querymatch.h"
//#define LOCK_FOR_READ(d) if (d->policy == Shared) { d->lock.lockForRead(); }
//#define LOCK_FOR_WRITE(d) if (d->policy == Shared) { d->lock.lockForWrite(); }
//#define UNLOCK(d) if (d->policy == Shared) { d->lock.unlock(); }
#define LOCK_FOR_READ(d) d->lock.lockForRead();
#define LOCK_FOR_WRITE(d) d->lock.lockForWrite();
#define UNLOCK(d) d->lock.unlock();
namespace Plasma
{
/*
Corrects the case of the last component in a path (e.g. /usr/liB -> /usr/lib)
path: The path to be processed.
correctCasePath: The corrected-case path
mustBeDir: Tells whether the last component is a folder or doesn't matter
Returns true on success and false on error, in case of error, correctCasePath is not modified
*/
bool correctLastComponentCase(const QString &path, QString &correctCasePath, const bool mustBeDir)
{
//kDebug() << "Correcting " << path;
// If the file already exists then no need to search for it.
if (QFile::exists(path)) {
correctCasePath = path;
//kDebug() << "Correct path is" << correctCasePath;
return true;
}
const QFileInfo pathInfo(path);
const QDir fileDir = pathInfo.dir();
//kDebug() << "Directory is" << fileDir;
const QString filename = pathInfo.fileName();
//kDebug() << "Filename is" << filename;
//kDebug() << "searching for a" << (mustBeDir ? "directory" : "directory/file");
const QStringList matchingFilenames = fileDir.entryList(QStringList(filename),
mustBeDir ? QDir::Dirs : QDir::NoFilter);
if (matchingFilenames.empty()) {
//kDebug() << "No matches found!!\n";
return false;
} else {
/*if (matchingFilenames.size() > 1) {
#ifndef NDEBUG
kDebug() << "Found multiple matches!!\n";
#endif
}*/
if (fileDir.path().endsWith(QDir::separator())) {
correctCasePath = fileDir.path() + matchingFilenames[0];
} else {
correctCasePath = fileDir.path() + QDir::separator() + matchingFilenames[0];
}
//kDebug() << "Correct path is" << correctCasePath;
return true;
}
}
/*
Corrects the case of a path (e.g. /uSr/loCAL/bIN -> /usr/local/bin)
path: The path to be processed.
corrected: The corrected-case path
Returns true on success and false on error, in case of error, corrected is not modified
*/
bool correctPathCase(const QString& path, QString &corrected)
{
// early exit check
if (QFile::exists(path)) {
corrected = path;
return true;
}
// path components
QStringList components = QString(path).split(QDir::separator());
if (components.size() < 1) {
return false;
}
const bool mustBeDir = components.back().isEmpty();
//kDebug() << "Components are" << components;
if (mustBeDir) {
components.pop_back();
}
if (components.isEmpty()) {
return true;
}
QString correctPath;
const unsigned initialComponents = components.size();
for (unsigned i = 0; i < initialComponents - 1; i ++) {
const QString tmp = components[0] + QDir::separator() + components[1];
if (!correctLastComponentCase(tmp, correctPath, components.size() > 2 || mustBeDir)) {
//kDebug() << "search was not successful";
return false;
}
components.removeFirst();
components[0] = correctPath;
}
corrected = correctPath;
return true;
}
class RunnerContextPrivate : public QSharedData
{
public:
RunnerContextPrivate(RunnerContext *context)
: QSharedData(),
type(RunnerContext::UnknownType),
q(context),
singleRunnerQueryMode(false)
{
}
RunnerContextPrivate(const RunnerContextPrivate &p)
: QSharedData(),
launchCounts(p.launchCounts),
type(RunnerContext::None),
q(p.q),
singleRunnerQueryMode(false)
{
//kDebug() << "ツソツソツソツソツソツソツソツソツソツソツソツソツソツソツソツソツソboo yeah" << type;
}
~RunnerContextPrivate()
{
}
/**
* Determines type of query
&&
*/
void determineType()
{
// NOTE! this method must NEVER be called from
// code that may be running in multiple threads
// with the same data.
type = RunnerContext::UnknownType;
QString path = QDir::cleanPath(KShell::tildeExpand(term));
int space = path.indexOf(' ');
if (!KStandardDirs::findExe(path.left(space)).isEmpty()) {
// it's a shell command if there's a space because that implies
// that it has arguments!
type = (space > 0) ? RunnerContext::ShellCommand :
RunnerContext::Executable;
} else {
KUrl url(term);
// check for a normal URL first
//kDebug() << url << KProtocolInfo::protocolClass(url.scheme()) << url.hasHost() <<
// url.host() << url.isLocalFile() << path << path.indexOf('/');
const bool hasProtocol = !url.scheme().isEmpty();
const bool isLocalProtocol = KProtocolInfo::protocolClass(url.scheme()) == ":local";
if (hasProtocol &&
((!isLocalProtocol && url.hasHost()) ||
(isLocalProtocol && url.scheme() != "file"))) {
// we either have a network protocol with a host, so we can show matches for it
// or we have a non-file url that may be local so a host isn't required
type = RunnerContext::NetworkLocation;
} else if (isLocalProtocol) {
// at this point in the game, we assume we have a path,
// but if a path doesn't have any slashes
// it's too ambiguous to be sure we're in a filesystem context
path = QDir::cleanPath(url.toLocalFile());
//kDebug( )<< "slash check" << path;
if (hasProtocol || ((path.indexOf('/') != -1 || path.indexOf('\\') != -1))) {
QString correctCasePath;
if (correctPathCase(path, correctCasePath)) {
path = correctCasePath;
QFileInfo info(path);
//kDebug( )<< "correct cas epath is" << correctCasePath << info.isSymLink() <<
// info.isDir() << info.isFile();
if (info.isSymLink()) {
path = info.canonicalFilePath();
info = QFileInfo(path);
}
if (info.isDir()) {
type = RunnerContext::Directory;
mimeType = "inode/folder";
} else if (info.isFile()) {
type = RunnerContext::File;
KMimeType::Ptr mimeTypePtr = KMimeType::findByPath(path);
if (mimeTypePtr) {
mimeType = mimeTypePtr->name();
}
}
}
}
}
}
//kDebug() << "term2type" << term << type;
}
void invalidate()
{
q = &s_dummyContext;
}
QReadWriteLock lock;
QList<QueryMatch> matches;
QMap<QString, const QueryMatch*> matchesById;
QHash<QString, int> launchCounts;
QString term;
QString mimeType;
RunnerContext::Type type;
RunnerContext * q;
static RunnerContext s_dummyContext;
bool singleRunnerQueryMode;
};
RunnerContext RunnerContextPrivate::s_dummyContext;
RunnerContext::RunnerContext(QObject *parent)
: QObject(parent),
d(new RunnerContextPrivate(this))
{
}
//copy ctor
RunnerContext::RunnerContext(RunnerContext &other, QObject *parent)
: QObject(parent)
{
LOCK_FOR_READ(other.d)
d = other.d;
UNLOCK(other.d)
}
RunnerContext::~RunnerContext()
{
}
RunnerContext &RunnerContext::operator=(const RunnerContext &other)
{
if (this->d == other.d) {
return *this;
}
QExplicitlySharedDataPointer<Plasma::RunnerContextPrivate> oldD = d;
LOCK_FOR_WRITE(d)
LOCK_FOR_READ(other.d)
d = other.d;
UNLOCK(other.d)
UNLOCK(oldD)
return *this;
}
void RunnerContext::reset()
{
// We will detach if we are a copy of someone. But we will reset
// if we are the 'main' context others copied from. Resetting
// one RunnerContext makes all the copies obsolete.
// We need to mark the q pointer of the detached RunnerContextPrivate
// as dirty on detach to avoid receiving results for old queries
d->invalidate();
d.detach();
// Now that we detached the d pointer we need to reset its q pointer
d->q = this;
// we still have to remove all the matches, since if the
// ref count was 1 (e.g. only the RunnerContext is using
// the dptr) then we won't get a copy made
if (!d->matches.isEmpty()) {
d->matchesById.clear();
d->matches.clear();
emit matchesChanged();
}
d->term.clear();
d->mimeType.clear();
d->type = UnknownType;
d->singleRunnerQueryMode = false;
//kDebug() << "match count" << d->matches.count();
}
void RunnerContext::setQuery(const QString &term)
{
reset();
if (term.isEmpty()) {
return;
}
d->term = term;
d->determineType();
}
QString RunnerContext::query() const
{
// the query term should never be set after
// a search starts. in fact, reset() ensures this
// and setQuery(QString) calls reset()
return d->term;
}
RunnerContext::Type RunnerContext::type() const
{
return d->type;
}
QString RunnerContext::mimeType() const
{
return d->mimeType;
}
bool RunnerContext::isValid() const
{
// if our qptr is dirty, we aren't useful anymore
return (d->q != &(d->s_dummyContext));
}
bool RunnerContext::addMatches(const QList<QueryMatch> &matches)
{
if (matches.isEmpty() || !isValid()) {
//Bail out if the query is empty or the qptr is dirty
return false;
}
LOCK_FOR_WRITE(d)
foreach (QueryMatch match, matches) {
// Give previously launched matches a slight boost in relevance
// The boost smoothly saturates to 0.5;
if (int count = d->launchCounts.value(match.id())) {
match.setRelevance(match.relevance() + 0.5 * (1-exp(-count*0.3)));
}
d->matches.append(match);
#ifndef NDEBUG
if (d->matchesById.contains(match.id())) {
kDebug() << "Duplicate match id " << match.id() << "from" << match.runner()->name();
}
#endif
d->matchesById.insert(match.id(), &d->matches.at(d->matches.size() - 1));
}
UNLOCK(d);
//kDebug()<< "add matches";
// A copied searchContext may share the d pointer,
// we always want to sent the signal of the object that created
// the d pointer
emit d->q->matchesChanged();
return true;
}
bool RunnerContext::addMatch(const QueryMatch &match)
{
if (!isValid()) {
// Bail out if the qptr is dirty
return false;
}
QueryMatch m(match); // match must be non-const to modify relevance
LOCK_FOR_WRITE(d)
if (int count = d->launchCounts.value(m.id())) {
m.setRelevance(m.relevance() + 0.05 * count);
}
d->matches.append(m);
d->matchesById.insert(m.id(), &d->matches.at(d->matches.size() - 1));
UNLOCK(d);
//kDebug()<< "added match" << match->text();
emit d->q->matchesChanged();
return true;
}
bool RunnerContext::removeMatches(const QStringList matchIdList)
{
if (!isValid()) {
return false;
}
QStringList presentMatchIdList;
QList<const QueryMatch*> presentMatchList;
LOCK_FOR_READ(d)
foreach(const QString &matchId, matchIdList) {
const QueryMatch* match = d->matchesById.value(matchId, 0);
if (match) {
presentMatchList << match;
presentMatchIdList << matchId;
}
}
UNLOCK(d)
if (presentMatchIdList.isEmpty()) {
return false;
}
LOCK_FOR_WRITE(d)
foreach(const QueryMatch *match, presentMatchList) {
d->matches.removeAll(*match);
}
foreach(const QString &matchId, presentMatchIdList) {
d->matchesById.remove(matchId);
}
UNLOCK(d)
emit d->q->matchesChanged();
return true;
}
bool RunnerContext::removeMatch(const QString matchId)
{
if (!isValid()) {
return false;
}
LOCK_FOR_READ(d)
const QueryMatch* match = d->matchesById.value(matchId, 0);
UNLOCK(d)
if (!match) {
return false;
}
LOCK_FOR_WRITE(d)
d->matches.removeAll(*match);
d->matchesById.remove(matchId);
UNLOCK(d)
emit d->q->matchesChanged();
return true;
}
QList<QueryMatch> RunnerContext::matches() const
{
LOCK_FOR_READ(d)
QList<QueryMatch> matches = d->matches;
UNLOCK(d);
return matches;
}
QueryMatch RunnerContext::match(const QString &id) const
{
LOCK_FOR_READ(d)
const QueryMatch *match = d->matchesById.value(id, 0);
UNLOCK(d)
if (match) {
return *match;
}
return QueryMatch(0);
}
void RunnerContext::setSingleRunnerQueryMode(bool enabled)
{
d->singleRunnerQueryMode = enabled;
}
bool RunnerContext::singleRunnerQueryMode() const
{
return d->singleRunnerQueryMode;
}
void RunnerContext::restore(const KConfigGroup &config)
{
const QStringList cfgList = config.readEntry("LaunchCounts", QStringList());
const QRegExp r("(\\d*) (.*)");
foreach (const QString& entry, cfgList) {
r.indexIn(entry);
int count = r.cap(1).toInt();
QString id = r.cap(2);
d->launchCounts[id] = count;
}
}
void RunnerContext::save(KConfigGroup &config)
{
QStringList countList;
typedef QHash<QString, int>::const_iterator Iterator;
Iterator end = d->launchCounts.constEnd();
for (Iterator i = d->launchCounts.constBegin(); i != end; ++i) {
countList << QString("%2 %1").arg(i.key()).arg(i.value());
}
config.writeEntry("LaunchCounts", countList);
config.sync();
}
void RunnerContext::run(const QueryMatch &match)
{
++d->launchCounts[match.id()];
match.run(*this);
}
} // Plasma namespace
+
+#include "moc_runnercontext.cpp"
diff --git a/plasma/runnermanager.cpp b/plasma/runnermanager.cpp
index c008df8a34..a7e537f544 100644
--- a/plasma/runnermanager.cpp
+++ b/plasma/runnermanager.cpp
@@ -1,837 +1,839 @@
/*
* Copyright (C) 2006 Aaron Seigo <aseigo@kde.org>
* Copyright (C) 2007, 2009 Ryan P. Bitanga <ryan.bitanga@gmail.com>
* Copyright (C) 2008 Jordi Polo <mumismo@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 "runnermanager.h"
#include "config-plasma.h"
#include <QMutex>
#include <QTimer>
#include <QCoreApplication>
#include <kdebug.h>
#include <kplugininfo.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#ifndef PLASMA_NO_SOLID
#include <solid/device.h>
#include <solid/deviceinterface.h>
#endif
#include <Weaver/DebuggingAids.h>
#include <Weaver/State.h>
#include <Weaver/Thread.h>
#include <Weaver/ThreadWeaver.h>
#include "private/runnerjobs_p.h"
#include "pluginloader.h"
#include "querymatch.h"
using ThreadWeaver::Weaver;
using ThreadWeaver::Job;
//#define MEASURE_PREPTIME
namespace Plasma
{
/*****************************************************
* RunnerManager::Private class
*
*****************************************************/
class RunnerManagerPrivate
{
public:
RunnerManagerPrivate(RunnerManager *parent)
: q(parent),
deferredRun(0),
currentSingleRunner(0),
prepped(false),
allRunnersPrepped(false),
singleRunnerPrepped(false),
teardownRequested(false),
singleMode(false),
singleRunnerWasLoaded(false)
{
matchChangeTimer.setSingleShot(true);
delayTimer.setSingleShot(true);
QObject::connect(&matchChangeTimer, SIGNAL(timeout()), q, SLOT(matchesChanged()));
QObject::connect(&context, SIGNAL(matchesChanged()), q, SLOT(scheduleMatchesChanged()));
QObject::connect(&delayTimer, SIGNAL(timeout()), q, SLOT(unblockJobs()));
}
~RunnerManagerPrivate()
{
KConfigGroup config = configGroup();
context.save(config);
}
void scheduleMatchesChanged()
{
matchChangeTimer.start(100);
}
void matchesChanged()
{
emit q->matchesChanged(context.matches());
}
void loadConfiguration()
{
KConfigGroup config = configGroup();
//The number of threads used scales with the number of processors.
#ifndef PLASMA_NO_SOLID
const int numProcs =
qMax(Solid::Device::listFromType(Solid::DeviceInterface::Processor).count(), 1);
#else
const int numProcs = 1;
#endif
//This entry allows to define a hard upper limit independent of the number of processors.
const int maxThreads = config.readEntry("maxThreads", 16);
const int numThreads = qMin(maxThreads, 2 + ((numProcs - 1) * 2));
//kDebug() << "setting up" << numThreads << "threads for" << numProcs << "processors";
if (numThreads > Weaver::instance()->maximumNumberOfThreads()) {
Weaver::instance()->setMaximumNumberOfThreads(numThreads);
}
// Limit the number of instances of a single normal speed runner and all of the slow runners
// to half the number of threads
const int cap = qMax(2, numThreads/2);
DefaultRunnerPolicy::instance().setCap(cap);
context.restore(config);
}
KConfigGroup configGroup()
{
return conf.isValid() ? conf : KConfigGroup(KGlobal::config(), "PlasmaRunnerManager");
}
void clearSingleRunner()
{
if (singleRunnerWasLoaded) {
delete currentSingleRunner;
}
currentSingleRunner = 0;
}
void loadSingleRunner()
{
if (!singleMode || singleModeRunnerId.isEmpty()) {
clearSingleRunner();
return;
}
if (currentSingleRunner) {
if (currentSingleRunner->id() == singleModeRunnerId) {
return;
}
clearSingleRunner();
}
AbstractRunner *loadedRunner = q->runner(singleModeRunnerId);
if (loadedRunner) {
singleRunnerWasLoaded = false;
currentSingleRunner = loadedRunner;
return;
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner", QString("[X-KDE-PluginInfo-Name] == '%1'").arg(singleModeRunnerId));
if (!offers.isEmpty()) {
const KService::Ptr &service = offers[0];
currentSingleRunner = loadInstalledRunner(service);
if (currentSingleRunner) {
emit currentSingleRunner->prepare();
singleRunnerWasLoaded = true;
}
}
}
void loadRunners()
{
KConfigGroup config = configGroup();
KPluginInfo::List offers = RunnerManager::listRunnerInfo();
const bool loadAll = config.readEntry("loadAll", false);
const QStringList whiteList = config.readEntry("pluginWhiteList", QStringList());
const bool noWhiteList = whiteList.isEmpty();
KConfigGroup pluginConf;
if (conf.isValid()) {
pluginConf = KConfigGroup(&conf, "Plugins");
} else {
pluginConf = KConfigGroup(KGlobal::config(), "Plugins");
}
advertiseSingleRunnerIds.clear();
QSet<AbstractRunner *> deadRunners;
QMutableListIterator<KPluginInfo> it(offers);
while (it.hasNext()) {
KPluginInfo &description = it.next();
//kDebug() << "Loading runner: " << service->name() << service->storageId();
QString tryExec = description.property("TryExec").toString();
//kDebug() << "TryExec is" << tryExec;
if (!tryExec.isEmpty() && KStandardDirs::findExe(tryExec).isEmpty()) {
// we don't actually have this application!
continue;
}
const QString runnerName = description.pluginName();
description.load(pluginConf);
const bool loaded = runners.contains(runnerName);
const bool selected = loadAll || (description.isPluginEnabled() && (noWhiteList || whiteList.contains(runnerName)));
const bool singleQueryModeEnabled = description.property("X-Plasma-AdvertiseSingleRunnerQueryMode").toBool();
if (singleQueryModeEnabled) {
advertiseSingleRunnerIds.insert(runnerName, description.name());
}
//kDebug() << loadAll << description.isPluginEnabled() << noWhiteList << whiteList.contains(runnerName);
if (selected) {
if (!loaded) {
AbstractRunner *runner = loadInstalledRunner(description.service());
if (runner) {
runners.insert(runnerName, runner);
}
}
} else if (loaded) {
//Remove runner
deadRunners.insert(runners.take(runnerName));
#ifndef NDEBUG
kDebug() << "Removing runner: " << runnerName;
#endif
}
}
if (!deadRunners.isEmpty()) {
QSet<FindMatchesJob *> deadJobs;
foreach (FindMatchesJob *job, searchJobs) {
if (deadRunners.contains(job->runner())) {
QObject::disconnect(job, SIGNAL(done(ThreadWeaver::Job*)), q, SLOT(jobDone(ThreadWeaver::Job*)));
searchJobs.remove(job);
deadJobs.insert(job);
}
}
foreach (FindMatchesJob *job, oldSearchJobs) {
if (deadRunners.contains(job->runner())) {
oldSearchJobs.remove(job);
deadJobs.insert(job);
}
}
if (deadJobs.isEmpty()) {
qDeleteAll(deadRunners);
} else {
new DelayedJobCleaner(deadJobs, deadRunners);
}
}
#ifndef NDEBUG
kDebug() << "All runners loaded, total:" << runners.count();
#endif
}
AbstractRunner *loadInstalledRunner(const KService::Ptr service)
{
if (!service) {
return 0;
}
AbstractRunner *runner = PluginLoader::self()->loadRunner(service->property("X-KDE-PluginInfo-Name", QVariant::String).toString());
if (runner) {
runner->setParent(q);
} else {
const QString api = service->property("X-Plasma-API").toString();
if (api.isEmpty()) {
QVariantList args;
args << service->storageId();
if (Plasma::isPluginVersionCompatible(KPluginLoader(*service).pluginVersion())) {
QString error;
runner = service->createInstance<AbstractRunner>(q, args, &error);
if (!runner) {
#ifndef NDEBUG
kDebug() << "Failed to load runner:" << service->name() << ". error reported:" << error;
#endif
}
}
} else {
//kDebug() << "got a script runner known as" << api;
runner = new AbstractRunner(service, q);
}
}
if (runner) {
#ifndef NDEBUG
kDebug() << "================= loading runner:" << service->name() << "=================";
#endif
QObject::connect(runner, SIGNAL(matchingSuspended(bool)), q, SLOT(runnerMatchingSuspended(bool)));
runner->init();
}
return runner;
}
void jobDone(ThreadWeaver::Job *job)
{
FindMatchesJob *runJob = dynamic_cast<FindMatchesJob *>(job);
if (!runJob) {
return;
}
if (deferredRun.isEnabled() && runJob->runner() == deferredRun.runner()) {
//kDebug() << "job actually done, running now **************";
QueryMatch tmpRun = deferredRun;
deferredRun = QueryMatch(0);
tmpRun.run(context);
}
searchJobs.remove(runJob);
oldSearchJobs.remove(runJob);
runJob->deleteLater();
if (searchJobs.isEmpty() && context.matches().isEmpty()) {
// we finished our run, and there are no valid matches, and so no
// signal will have been sent out. so we need to emit the signal
// ourselves here
emit q->matchesChanged(context.matches());
}
checkTearDown();
}
void checkTearDown()
{
//kDebug() << prepped << teardownRequested << searchJobs.count() << oldSearchJobs.count();
if (!prepped || !teardownRequested) {
return;
}
if (Weaver::instance()->isIdle()) {
qDeleteAll(searchJobs);
searchJobs.clear();
qDeleteAll(oldSearchJobs);
oldSearchJobs.clear();
}
if (searchJobs.isEmpty() && oldSearchJobs.isEmpty()) {
if (allRunnersPrepped) {
foreach (AbstractRunner *runner, runners) {
emit runner->teardown();
}
allRunnersPrepped = false;
}
if (singleRunnerPrepped) {
if (currentSingleRunner) {
emit currentSingleRunner->teardown();
}
singleRunnerPrepped = false;
}
emit q->queryFinished();
prepped = false;
teardownRequested = false;
}
}
void unblockJobs()
{
// WORKAROUND: Queue an empty job to force ThreadWeaver to awaken threads
if (searchJobs.isEmpty() && Weaver::instance()->isIdle()) {
qDeleteAll(oldSearchJobs);
oldSearchJobs.clear();
checkTearDown();
return;
}
DummyJob *dummy = new DummyJob(q);
Weaver::instance()->enqueue(dummy);
QObject::connect(dummy, SIGNAL(done(ThreadWeaver::Job*)), dummy, SLOT(deleteLater()));
}
void runnerMatchingSuspended(bool suspended)
{
if (suspended || !prepped || teardownRequested) {
return;
}
AbstractRunner *runner = qobject_cast<AbstractRunner *>(q->sender());
if (runner) {
startJob(runner);
}
}
void startJob(AbstractRunner *runner)
{
if ((runner->ignoredTypes() & context.type()) == 0) {
FindMatchesJob *job = new FindMatchesJob(runner, &context, Weaver::instance());
QObject::connect(job, SIGNAL(done(ThreadWeaver::Job*)), q, SLOT(jobDone(ThreadWeaver::Job*)));
if (runner->speed() == AbstractRunner::SlowSpeed) {
job->setDelayTimer(&delayTimer);
}
Weaver::instance()->enqueue(job);
searchJobs.insert(job);
}
}
// Delay in ms before slow runners are allowed to run
static const int slowRunDelay = 400;
RunnerManager *q;
QueryMatch deferredRun;
RunnerContext context;
QTimer matchChangeTimer;
QTimer delayTimer; // Timer to control when to run slow runners
QHash<QString, AbstractRunner*> runners;
QHash<QString, QString> advertiseSingleRunnerIds;
AbstractRunner* currentSingleRunner;
QSet<FindMatchesJob*> searchJobs;
QSet<FindMatchesJob*> oldSearchJobs;
KConfigGroup conf;
QString singleModeRunnerId;
bool loadAll : 1;
bool prepped : 1;
bool allRunnersPrepped : 1;
bool singleRunnerPrepped : 1;
bool teardownRequested : 1;
bool singleMode : 1;
bool singleRunnerWasLoaded : 1;
};
/*****************************************************
* RunnerManager::Public class
*
*****************************************************/
RunnerManager::RunnerManager(QObject *parent)
: QObject(parent),
d(new RunnerManagerPrivate(this))
{
d->loadConfiguration();
//ThreadWeaver::setDebugLevel(true, 4);
}
RunnerManager::RunnerManager(KConfigGroup &c, QObject *parent)
: QObject(parent),
d(new RunnerManagerPrivate(this))
{
// Should this be really needed? Maybe d->loadConfiguration(c) would make
// more sense.
d->conf = KConfigGroup(&c, "PlasmaRunnerManager");
d->loadConfiguration();
//ThreadWeaver::setDebugLevel(true, 4);
}
RunnerManager::~RunnerManager()
{
if (!qApp->closingDown() && (!d->searchJobs.isEmpty() || !d->oldSearchJobs.isEmpty())) {
new DelayedJobCleaner(d->searchJobs + d->oldSearchJobs);
}
delete d;
}
void RunnerManager::reloadConfiguration()
{
d->loadConfiguration();
d->loadRunners();
}
void RunnerManager::setAllowedRunners(const QStringList &runners)
{
KConfigGroup config = d->configGroup();
config.writeEntry("pluginWhiteList", runners);
if (!d->runners.isEmpty()) {
// this has been called with runners already created. so let's do an instant reload
d->loadRunners();
}
}
QStringList RunnerManager::allowedRunners() const
{
KConfigGroup config = d->configGroup();
return config.readEntry("pluginWhiteList", QStringList());
}
void RunnerManager::loadRunner(const KService::Ptr service)
{
KPluginInfo description(service);
const QString runnerName = description.pluginName();
if (!runnerName.isEmpty() && !d->runners.contains(runnerName)) {
AbstractRunner *runner = d->loadInstalledRunner(service);
if (runner) {
d->runners.insert(runnerName, runner);
}
}
}
void RunnerManager::loadRunner(const QString &path)
{
if (!d->runners.contains(path)) {
AbstractRunner *runner = new AbstractRunner(this, path);
connect(runner, SIGNAL(matchingSuspended(bool)), this, SLOT(runnerMatchingSuspended(bool)));
d->runners.insert(path, runner);
}
}
AbstractRunner* RunnerManager::runner(const QString &name) const
{
if (d->runners.isEmpty()) {
d->loadRunners();
}
return d->runners.value(name, 0);
}
AbstractRunner *RunnerManager::singleModeRunner() const
{
return d->currentSingleRunner;
}
void RunnerManager::setSingleModeRunnerId(const QString &id)
{
d->singleModeRunnerId = id;
d->loadSingleRunner();
}
QString RunnerManager::singleModeRunnerId() const
{
return d->singleModeRunnerId;
}
bool RunnerManager::singleMode() const
{
return d->singleMode;
}
void RunnerManager::setSingleMode(bool singleMode)
{
if (d->singleMode == singleMode) {
return;
}
Plasma::AbstractRunner *prevSingleRunner = d->currentSingleRunner;
d->singleMode = singleMode;
d->loadSingleRunner();
d->singleMode = d->currentSingleRunner;
if (prevSingleRunner != d->currentSingleRunner) {
if (d->prepped) {
matchSessionComplete();
if (d->singleMode) {
setupMatchSession();
}
}
}
}
QList<AbstractRunner *> RunnerManager::runners() const
{
return d->runners.values();
}
QStringList RunnerManager::singleModeAdvertisedRunnerIds() const
{
return d->advertiseSingleRunnerIds.keys();
}
QString RunnerManager::runnerName(const QString &id) const
{
if (runner(id)) {
return runner(id)->name();
} else {
return d->advertiseSingleRunnerIds.value(id, QString());
}
}
RunnerContext* RunnerManager::searchContext() const
{
return &d->context;
}
//Reordering is here so data is not reordered till strictly needed
QList<QueryMatch> RunnerManager::matches() const
{
return d->context.matches();
}
void RunnerManager::run(const QString &id)
{
run(d->context.match(id));
}
void RunnerManager::run(const QueryMatch &match)
{
if (!match.isEnabled()) {
return;
}
//TODO: this function is not const as it may be used for learning
AbstractRunner *runner = match.runner();
foreach (FindMatchesJob *job, d->searchJobs) {
if (job->runner() == runner && !job->isFinished()) {
#ifndef NDEBUG
kDebug() << "deferred run";
#endif
d->deferredRun = match;
return;
}
}
if (d->deferredRun.isValid()) {
d->deferredRun = QueryMatch(0);
}
d->context.run(match);
}
QList<QAction*> RunnerManager::actionsForMatch(const QueryMatch &match)
{
AbstractRunner *runner = match.runner();
if (runner) {
return runner->actionsForMatch(match);
}
return QList<QAction*>();
}
QMimeData * RunnerManager::mimeDataForMatch(const QString &id) const
{
return mimeDataForMatch(d->context.match(id));
}
QMimeData * RunnerManager::mimeDataForMatch(const QueryMatch &match) const
{
AbstractRunner *runner = match.runner();
if (runner) {
return runner->mimeDataForMatch(match);
}
return 0;
}
KPluginInfo::List RunnerManager::listRunnerInfo(const QString &parentApp)
{
return PluginLoader::self()->listRunnerInfo(parentApp);
}
void RunnerManager::setupMatchSession()
{
d->teardownRequested = false;
if (d->prepped) {
return;
}
d->prepped = true;
if (d->singleMode) {
if (d->currentSingleRunner) {
emit d->currentSingleRunner->prepare();
d->singleRunnerPrepped = true;
}
} else {
foreach (AbstractRunner *runner, d->runners) {
#ifdef MEASURE_PREPTIME
QTime t;
t.start();
#endif
emit runner->prepare();
#ifdef MEASURE_PREPTIME
#ifndef NDEBUG
kDebug() << t.elapsed() << runner->name();
#endif
#endif
}
d->allRunnersPrepped = true;
}
}
void RunnerManager::matchSessionComplete()
{
if (!d->prepped) {
return;
}
d->teardownRequested = true;
d->checkTearDown();
}
void RunnerManager::launchQuery(const QString &term)
{
launchQuery(term, QString());
}
void RunnerManager::launchQuery(const QString &untrimmedTerm, const QString &runnerName)
{
setupMatchSession();
QString term = untrimmedTerm.trimmed();
setSingleModeRunnerId(runnerName);
setSingleMode(!runnerName.isEmpty());
if (term.isEmpty()) {
if (d->singleMode && d->currentSingleRunner && d->currentSingleRunner->defaultSyntax()) {
term = d->currentSingleRunner->defaultSyntax()->exampleQueries().first().remove(QRegExp(":q:"));
} else {
reset();
return;
}
}
if (d->context.query() == term) {
// we already are searching for this!
return;
}
if (d->singleMode && !d->currentSingleRunner) {
reset();
return;
}
if (d->runners.isEmpty()) {
d->loadRunners();
}
reset();
// kDebug() << "runners searching for" << term << "on" << runnerName;
d->context.setQuery(term);
QHash<QString, AbstractRunner*> runable;
//if the name is not empty we will launch only the specified runner
if (d->singleMode && d->currentSingleRunner) {
runable.insert(QString(), d->currentSingleRunner);
d->context.setSingleRunnerQueryMode(true);
} else {
runable = d->runners;
}
foreach (Plasma::AbstractRunner *r, runable) {
if (r->isMatchingSuspended()) {
continue;
}
d->startJob(r);
}
// Start timer to unblock slow runners
d->delayTimer.start(RunnerManagerPrivate::slowRunDelay);
}
bool RunnerManager::execQuery(const QString &term)
{
return execQuery(term, QString());
}
bool RunnerManager::execQuery(const QString &untrimmedTerm, const QString &runnerName)
{
QString term = untrimmedTerm.trimmed();
if (term.isEmpty()) {
reset();
return false;
}
if (d->runners.isEmpty()) {
d->loadRunners();
}
if (d->context.query() == term) {
// we already are searching for this!
emit matchesChanged(d->context.matches());
return false;
}
reset();
//kDebug() << "executing query about " << term << "on" << runnerName;
d->context.setQuery(term);
AbstractRunner *r = runner(runnerName);
if (!r) {
//kDebug() << "failed to find the runner";
return false;
}
if ((r->ignoredTypes() & d->context.type()) != 0) {
//kDebug() << "ignored!";
return false;
}
r->performMatch(d->context);
//kDebug() << "succeeded with" << d->context.matches().count() << "results";
emit matchesChanged(d->context.matches());
return true;
}
QString RunnerManager::query() const
{
return d->context.query();
}
void RunnerManager::reset()
{
// If ThreadWeaver is idle, it is safe to clear previous jobs
if (Weaver::instance()->isIdle()) {
qDeleteAll(d->searchJobs);
qDeleteAll(d->oldSearchJobs);
d->oldSearchJobs.clear();
} else {
Weaver::instance()->dequeue();
d->oldSearchJobs += d->searchJobs;
}
d->searchJobs.clear();
if (d->deferredRun.isEnabled()) {
//kDebug() << "job actually done, running now **************";
QueryMatch tmpRun = d->deferredRun;
d->deferredRun = QueryMatch(0);
tmpRun.run(d->context);
}
d->context.reset();
}
} // Plasma namespace
+
+#include "moc_runnermanager.cpp"
diff --git a/plasma/scripting/appletscript.cpp b/plasma/scripting/appletscript.cpp
index d0b733ffa6..aff7314faf 100644
--- a/plasma/scripting/appletscript.cpp
+++ b/plasma/scripting/appletscript.cpp
@@ -1,251 +1,253 @@
/*
* Copyright 2007 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 "scripting/appletscript.h"
#include "kconfig.h"
#include "kconfigdialog.h"
#include "applet.h"
#include "package.h"
#include "private/applet_p.h"
namespace Plasma
{
class AppletScriptPrivate
{
public:
Applet *applet;
};
AppletScript::AppletScript(QObject *parent)
: ScriptEngine(parent),
d(new AppletScriptPrivate)
{
d->applet = 0;
}
AppletScript::~AppletScript()
{
delete d;
}
void AppletScript::setApplet(Plasma::Applet *applet)
{
d->applet = applet;
}
Applet *AppletScript::applet() const
{
Q_ASSERT(d->applet);
return d->applet;
}
void AppletScript::paintInterface(QPainter *painter,
const QStyleOptionGraphicsItem *option,
const QRect &contentsRect)
{
Q_UNUSED(painter);
Q_UNUSED(option);
Q_UNUSED(contentsRect);
}
QSizeF AppletScript::size() const
{
if (applet()) {
return applet()->size();
}
return QSizeF();
}
void AppletScript::constraintsEvent(Plasma::Constraints constraints)
{
Q_UNUSED(constraints);
}
QList<QAction*> AppletScript::contextualActions()
{
return QList<QAction*>();
}
QPainterPath AppletScript::shape() const
{
if (applet()) {
QPainterPath path;
path.addRect(applet()->boundingRect());
return path;
}
return QPainterPath();
}
void AppletScript::setHasConfigurationInterface(bool hasInterface)
{
if (applet()) {
applet()->setHasConfigurationInterface(hasInterface);
}
}
void AppletScript::setConfigurationRequired(bool req, const QString &reason)
{
if (applet()) {
applet()->setConfigurationRequired(req, reason);
}
}
void AppletScript::setFailedToLaunch(bool failed, const QString &reason)
{
if (applet()) {
applet()->setFailedToLaunch(failed, reason);
}
}
void AppletScript::configNeedsSaving() const
{
if (applet()) {
emit applet()->configNeedsSaving();
}
}
void AppletScript::showConfigurationInterface()
{
if (applet()) {
KConfigDialog *dialog = applet()->d->generateGenericConfigDialog();
applet()->d->addStandardConfigurationPages(dialog);
dialog->show();
}
}
KConfigDialog *AppletScript::standardConfigurationDialog()
{
if (applet()) {
return applet()->d->generateGenericConfigDialog();
}
return 0;
}
void AppletScript::addStandardConfigurationPages(KConfigDialog *dialog)
{
if (applet()) {
applet()->d->addStandardConfigurationPages(dialog);
}
}
void AppletScript::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons)
{
if (applet()) {
applet()->showMessage(icon, message, buttons);
}
}
void AppletScript::registerAsDragHandle(QGraphicsItem *item)
{
if (applet()) {
applet()->registerAsDragHandle(item);
}
}
void AppletScript::unregisterAsDragHandle(QGraphicsItem *item)
{
if (applet()) {
applet()->unregisterAsDragHandle(item);
}
}
bool AppletScript::isRegisteredAsDragHandle(QGraphicsItem *item)
{
if (applet()) {
return applet()->isRegisteredAsDragHandle(item);
}
return false;
}
void AppletScript::configChanged()
{
}
DataEngine *AppletScript::dataEngine(const QString &engine) const
{
Q_ASSERT(d->applet);
return d->applet->dataEngine(engine);
}
QString AppletScript::mainScript() const
{
Q_ASSERT(d->applet);
return d->applet->package().filePath("mainscript");
}
Package AppletScript::package() const
{
Q_ASSERT(d->applet);
return d->applet->package();
}
KPluginInfo AppletScript::description() const
{
Q_ASSERT(d->applet);
return d->applet->d->appletDescription;
}
bool AppletScript::drawWallpaper() const
{
Q_ASSERT(d->applet);
Plasma::Containment *cont = qobject_cast<Plasma::Containment *>(d->applet);
if (cont) {
return cont->drawWallpaper();
} else {
return false;
}
}
void AppletScript::setDrawWallpaper(bool drawWallpaper)
{
Q_ASSERT(d->applet);
Plasma::Containment *cont = qobject_cast<Plasma::Containment *>(d->applet);
if (cont) {
cont->setDrawWallpaper(drawWallpaper);
}
}
Containment::Type AppletScript::containmentType() const
{
Q_ASSERT(d->applet);
Plasma::Containment *cont = qobject_cast<Plasma::Containment *>(d->applet);
if (cont) {
return cont->containmentType();
} else {
return Containment::NoContainmentType;
}
}
void AppletScript::setContainmentType(Containment::Type type)
{
Q_ASSERT(d->applet);
Plasma::Containment *cont = qobject_cast<Plasma::Containment *>(d->applet);
if (cont) {
cont->setContainmentType(type);
}
}
} // Plasma namespace
+
+#include "moc_appletscript.cpp"
diff --git a/plasma/scripting/dataenginescript.cpp b/plasma/scripting/dataenginescript.cpp
index 4c11f46bf8..95ad1cb5c5 100644
--- a/plasma/scripting/dataenginescript.cpp
+++ b/plasma/scripting/dataenginescript.cpp
@@ -1,220 +1,222 @@
/*
* Copyright 2007 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 "dataenginescript.h"
#include "package.h"
#include "private/dataengine_p.h"
#include "private/service_p.h"
namespace Plasma
{
class DataEngineScriptPrivate
{
public:
DataEngine *dataEngine;
};
DataEngineScript::DataEngineScript(QObject *parent)
: ScriptEngine(parent),
d(new DataEngineScriptPrivate)
{
}
DataEngineScript::~DataEngineScript()
{
delete d;
}
void DataEngineScript::setDataEngine(DataEngine *dataEngine)
{
d->dataEngine = dataEngine;
}
DataEngine *DataEngineScript::dataEngine() const
{
return d->dataEngine;
}
QStringList DataEngineScript::sources() const
{
return d->dataEngine->containerDict().keys();
}
bool DataEngineScript::sourceRequestEvent(const QString &name)
{
Q_UNUSED(name);
return false;
}
bool DataEngineScript::updateSourceEvent(const QString &source)
{
Q_UNUSED(source);
return false;
}
Service *DataEngineScript::serviceForSource(const QString &source)
{
Q_ASSERT(d->dataEngine);
return new NullService(source, d->dataEngine);
}
QString DataEngineScript::mainScript() const
{
Q_ASSERT(d->dataEngine);
return d->dataEngine->package().filePath("mainscript");
}
Package DataEngineScript::package() const
{
Q_ASSERT(d->dataEngine);
return d->dataEngine->package();
}
KPluginInfo DataEngineScript::description() const
{
Q_ASSERT(d->dataEngine);
return d->dataEngine->d->dataEngineDescription;
}
void DataEngineScript::setData(const QString &source, const QString &key,
const QVariant &value)
{
if (d->dataEngine) {
d->dataEngine->setData(source, key, value);
}
}
void DataEngineScript::setData(const QString &source, const QVariant &value)
{
if (d->dataEngine) {
d->dataEngine->setData(source, value);
}
}
void DataEngineScript::setData(const QString &source, const DataEngine::Data &values)
{
if (d->dataEngine) {
d->dataEngine->setData(source, values);
}
}
void DataEngineScript::removeAllData(const QString &source)
{
if (d->dataEngine) {
d->dataEngine->removeAllData(source);
}
}
void DataEngineScript::removeData(const QString &source, const QString &key)
{
if (d->dataEngine) {
d->dataEngine->removeData(source, key);
}
}
void DataEngineScript::setMinimumPollingInterval(int minimumMs)
{
if (d->dataEngine) {
d->dataEngine->setMinimumPollingInterval(minimumMs);
}
}
int DataEngineScript::minimumPollingInterval() const
{
if (d->dataEngine) {
return d->dataEngine->minimumPollingInterval();
}
return 0;
}
void DataEngineScript::setPollingInterval(uint frequency)
{
if (d->dataEngine) {
d->dataEngine->setPollingInterval(frequency);
}
}
void DataEngineScript::removeAllSources()
{
if (d->dataEngine) {
d->dataEngine->removeAllSources();
}
}
void DataEngineScript::addSource(DataContainer *source)
{
if (d->dataEngine) {
d->dataEngine->addSource(source);
}
}
DataEngine::SourceDict DataEngineScript::containerDict() const
{
if (d->dataEngine) {
return d->dataEngine->containerDict();
}
return DataEngine::SourceDict();
}
void DataEngineScript::setName(const QString &name)
{
if (d->dataEngine) {
d->dataEngine->setName(name);
}
}
void DataEngineScript::setIcon(const QString &icon)
{
if (d->dataEngine) {
d->dataEngine->setIcon(icon);
}
}
void DataEngineScript::scheduleSourcesUpdated()
{
if (d->dataEngine) {
d->dataEngine->scheduleSourcesUpdated();
}
}
void DataEngineScript::removeSource(const QString &source)
{
if (d->dataEngine) {
d->dataEngine->removeSource(source);
}
}
void DataEngineScript::updateAllSources()
{
if (d->dataEngine) {
d->dataEngine->updateAllSources();
}
}
void DataEngineScript::forceImmediateUpdateOfAllVisualizations()
{
if (d->dataEngine) {
d->dataEngine->forceImmediateUpdateOfAllVisualizations();
}
}
} // Plasma namespace
+
+#include "moc_dataenginescript.cpp"
diff --git a/plasma/scripting/runnerscript.cpp b/plasma/scripting/runnerscript.cpp
index adf818ed2a..e1ec8ba37f 100644
--- a/plasma/scripting/runnerscript.cpp
+++ b/plasma/scripting/runnerscript.cpp
@@ -1,190 +1,192 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "plasma/scripting/runnerscript.h"
#include "plasma/abstractrunner.h"
#include "plasma/dataenginemanager.h"
#include "plasma/package.h"
#include "plasma/private/abstractrunner_p.h"
namespace Plasma
{
class RunnerScriptPrivate
{
public:
AbstractRunner *runner;
};
RunnerScript::RunnerScript(QObject *parent)
: ScriptEngine(parent),
d(new RunnerScriptPrivate)
{
}
RunnerScript::~RunnerScript()
{
delete d;
}
void RunnerScript::setRunner(AbstractRunner *runner)
{
d->runner = runner;
connect(runner, SIGNAL(prepare()), this, SIGNAL(prepare()));
connect(runner, SIGNAL(teardown()), this, SIGNAL(teardown()));
}
AbstractRunner *RunnerScript::runner() const
{
return d->runner;
}
void RunnerScript::match(Plasma::RunnerContext &search)
{
Q_UNUSED(search);
}
void RunnerScript::run(const Plasma::RunnerContext &search, const Plasma::QueryMatch &action)
{
Q_UNUSED(search);
Q_UNUSED(action);
}
DataEngine *RunnerScript::dataEngine(const QString &name)
{
if (d->runner) {
return d->runner->dataEngine(name);
}
return DataEngineManager::self()->engine(QString());
}
KConfigGroup RunnerScript::config() const
{
if (d->runner) {
return d->runner->config();
}
return KConfigGroup();
}
void RunnerScript::setIgnoredTypes(RunnerContext::Types types)
{
if (d->runner) {
d->runner->setIgnoredTypes(types);
}
}
void RunnerScript::setHasRunOptions(bool hasRunOptions)
{
if (d->runner) {
d->runner->setHasRunOptions(hasRunOptions);
}
}
void RunnerScript::setSpeed(AbstractRunner::Speed newSpeed)
{
if (d->runner) {
d->runner->setSpeed(newSpeed);
}
}
void RunnerScript::setPriority(AbstractRunner::Priority newPriority)
{
if (d->runner) {
d->runner->setPriority(newPriority);
}
}
QAction* RunnerScript::addAction(const QString &id, const QIcon &icon, const QString &text)
{
if (d->runner) {
return d->runner->addAction(id, icon, text);
}
return 0;
}
void RunnerScript::addAction(const QString &id, QAction *action)
{
if (d->runner) {
d->runner->addAction(id, action);
}
}
void RunnerScript::removeAction(const QString &id)
{
if (d->runner) {
d->runner->removeAction(id);
}
}
QAction* RunnerScript::action(const QString &id) const
{
if (d->runner) {
return d->runner->action(id);
}
return 0;
}
QHash<QString, QAction*> RunnerScript::actions() const
{
if (d->runner) {
return d->runner->actions();
}
return QHash<QString, QAction*>();
}
void RunnerScript::clearActions()
{
if (d->runner) {
d->runner->clearActions();
}
}
void RunnerScript::addSyntax(const RunnerSyntax &syntax)
{
if (d->runner) {
d->runner->addSyntax(syntax);
}
}
void RunnerScript::setSyntaxes(const QList<RunnerSyntax> &syns)
{
if (d->runner) {
d->runner->setSyntaxes(syns);
}
}
Package RunnerScript::package() const
{
return d->runner ? d->runner->package() : Package();
}
KPluginInfo RunnerScript::description() const
{
return d->runner ? d->runner->d->runnerDescription : KPluginInfo();
}
QString RunnerScript::mainScript() const
{
return package().filePath("mainscript");
}
} // Plasma namespace
+
+#include "moc_runnerscript.cpp"
diff --git a/plasma/scripting/scriptengine.cpp b/plasma/scripting/scriptengine.cpp
index 52f20926b2..b274de7311 100644
--- a/plasma/scripting/scriptengine.cpp
+++ b/plasma/scripting/scriptengine.cpp
@@ -1,260 +1,259 @@
/*
* Copyright 2007 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 "scripting/scriptengine.h"
#include <kdebug.h>
#include <kservice.h>
#include <kservicetypetrader.h>
#include "abstractrunner.h"
#include "applet.h"
#include "dataengine.h"
#include "package.h"
#include "private/componentinstaller_p.h"
#include "scripting/appletscript.h"
#include "scripting/dataenginescript.h"
#include "scripting/runnerscript.h"
#include "scripting/wallpaperscript.h"
namespace Plasma
{
ScriptEngine::ScriptEngine(QObject *parent)
: QObject(parent),
d(0)
{
}
ScriptEngine::~ScriptEngine()
{
// delete d;
}
bool ScriptEngine::init()
{
return true;
}
Package ScriptEngine::package() const
{
return Package();
}
QString ScriptEngine::mainScript() const
{
return QString();
}
QStringList knownLanguages(ComponentTypes types)
{
QString constraintTemplate = "'%1' in [X-Plasma-ComponentTypes]";
QString constraint;
if (types & AppletComponent) {
// currently this if statement is not needed, but this future proofs
// the code against someone initializing constraint to something
// before we get here.
if (!constraint.isEmpty()) {
constraint.append(" or ");
}
constraint.append(constraintTemplate.arg("Applet"));
}
if (types & DataEngineComponent) {
if (!constraint.isEmpty()) {
constraint.append(" or ");
}
constraint.append(constraintTemplate.arg("DataEngine"));
}
if (types & RunnerComponent) {
if (!constraint.isEmpty()) {
constraint.append(" or ");
}
constraint.append(constraintTemplate.arg("Runner"));
}
if (types & WallpaperComponent) {
if (!constraint.isEmpty()) {
constraint.append(" or ");
}
constraint.append(constraintTemplate.arg("Wallpaper"));
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint);
//kDebug() << "Applet::knownApplets constraint was '" << constraint
// << "' which got us " << offers.count() << " matches";
QStringList languages;
foreach (const KService::Ptr &service, offers) {
QString language = service->property("X-Plasma-API").toString();
if (!languages.contains(language)) {
languages.append(language);
}
}
return languages;
}
KService::List engineOffers(const QString &language, ComponentType type)
{
if (language.isEmpty()) {
return KService::List();
}
QRegExp re("[^a-zA-Z0-9\\-_]");
if (re.indexIn(language) != -1) {
#ifndef NDEBUG
kDebug() << "invalid language attempted:" << language;
#endif
return KService::List();
}
QString component;
switch (type) {
case AppletComponent:
component = "Applet";
break;
case DataEngineComponent:
component = "DataEngine";
break;
case RunnerComponent:
component = "Runner";
break;
case WallpaperComponent:
component = "Wallpaper";
break;
default:
return KService::List();
break;
}
QString constraint = QString("[X-Plasma-API] == '%1' and "
"'%2' in [X-Plasma-ComponentTypes]").arg(language, component);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint);
/* kDebug() << "********************* loadingApplet with Plasma/ScriptEngine" << constraint
<< "resulting in" << offers.count() << "results";*/
if (offers.isEmpty()) {
#ifndef NDEBUG
kDebug() << "No offers for \"" << language << "\"";
#endif
}
return offers;
}
ScriptEngine *loadEngine(const QString &language, ComponentType type, QObject *parent)
{
KService::List offers = engineOffers(language, type);
QVariantList args;
QString error;
ScriptEngine *engine = 0;
foreach (const KService::Ptr &service, offers) {
switch (type) {
case AppletComponent:
engine = service->createInstance<Plasma::AppletScript>(parent, args, &error);
break;
case DataEngineComponent:
engine = service->createInstance<Plasma::DataEngineScript>(parent, args, &error);
break;
case RunnerComponent:
engine = service->createInstance<Plasma::RunnerScript>(parent, args, &error);
break;
case WallpaperComponent:
engine = service->createInstance<Plasma::WallpaperScript>(parent, args, &error);
break;
default:
return 0;
break;
}
if (engine) {
return engine;
}
#ifndef NDEBUG
kDebug() << "Couldn't load script engine for language " << language
<< "! error reported: " << error;
#endif
}
// Try installing the engine. However, it's too late for this request.
ComponentInstaller::self()->installMissingComponent("scriptengine", language);
return 0;
}
AppletScript *loadScriptEngine(const QString &language, Applet *applet)
{
AppletScript *engine =
static_cast<AppletScript*>(loadEngine(language, AppletComponent, applet));
if (engine) {
engine->setApplet(applet);
}
return engine;
}
DataEngineScript *loadScriptEngine(const QString &language, DataEngine *dataEngine)
{
DataEngineScript *engine =
static_cast<DataEngineScript*>(loadEngine(language, DataEngineComponent, dataEngine));
if (engine) {
engine->setDataEngine(dataEngine);
}
return engine;
}
RunnerScript *loadScriptEngine(const QString &language, AbstractRunner *runner)
{
RunnerScript *engine = static_cast<RunnerScript*>(loadEngine(language, RunnerComponent, runner));
if (engine) {
engine->setRunner(runner);
}
return engine;
}
WallpaperScript *loadScriptEngine(const QString &language, Wallpaper *wallpaper)
{
WallpaperScript *engine =
static_cast<WallpaperScript*>(loadEngine(language, WallpaperComponent, wallpaper));
if (engine) {
engine->setWallpaper(wallpaper);
}
return engine;
}
} // namespace Plasma
-#include <scriptengine.moc>
-
+#include "moc_scriptengine.cpp"
diff --git a/plasma/scripting/wallpaperscript.cpp b/plasma/scripting/wallpaperscript.cpp
index 483a26f2c5..8ed7f0d2ec 100644
--- a/plasma/scripting/wallpaperscript.cpp
+++ b/plasma/scripting/wallpaperscript.cpp
@@ -1,223 +1,225 @@
/*
* Copyright 2009 by Aaron Seigo <aseigo@kde.org>
* Copyright 2009 by Petri Damsten <damu@iki.fi>
*
* 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 "wallpaperscript.h"
#include "private/wallpaper_p.h"
#include "package.h"
namespace Plasma
{
class WallpaperScriptPrivate
{
public:
Wallpaper *wallpaper;
};
WallpaperScript::WallpaperScript(QObject *parent)
: ScriptEngine(parent),
d(new WallpaperScriptPrivate)
{
}
WallpaperScript::~WallpaperScript()
{
delete d;
}
void WallpaperScript::setWallpaper(Wallpaper *wallpaper)
{
d->wallpaper = wallpaper;
connect(wallpaper, SIGNAL(renderCompleted(const QImage&)),
this, SLOT(renderCompleted(const QImage&)));
}
Wallpaper *WallpaperScript::wallpaper() const
{
return d->wallpaper;
}
QString WallpaperScript::mainScript() const
{
Q_ASSERT(d->wallpaper);
return d->wallpaper->package().filePath("mainscript");
}
Package WallpaperScript::package() const
{
Q_ASSERT(d->wallpaper);
return d->wallpaper->package();
}
KPluginInfo WallpaperScript::description() const
{
Q_ASSERT(d->wallpaper);
return d->wallpaper->d->wallpaperDescription;
}
void WallpaperScript::initWallpaper(const KConfigGroup &config)
{
Q_UNUSED(config)
}
void WallpaperScript::paint(QPainter *painter, const QRectF &exposedRect)
{
Q_UNUSED(painter)
Q_UNUSED(exposedRect)
}
void WallpaperScript::save(KConfigGroup &config)
{
Q_UNUSED(config)
}
QWidget *WallpaperScript::createConfigurationInterface(QWidget *parent)
{
Q_UNUSED(parent)
return 0;
}
void WallpaperScript::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event)
}
void WallpaperScript::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event)
}
void WallpaperScript::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event)
}
void WallpaperScript::wheelEvent(QGraphicsSceneWheelEvent *event)
{
Q_UNUSED(event)
}
void WallpaperScript::addUrls(const KUrl::List urls)
{
Q_UNUSED(urls)
}
bool WallpaperScript::isInitialized() const
{
if (d->wallpaper) {
return d->wallpaper->isInitialized();
}
return false;
}
QRectF WallpaperScript::boundingRect() const
{
if (d->wallpaper) {
return d->wallpaper->boundingRect();
}
return QRectF();
}
DataEngine *WallpaperScript::dataEngine(const QString &name) const
{
Q_ASSERT(d->wallpaper);
return d->wallpaper->dataEngine(name);
}
void WallpaperScript::setResizeMethodHint(Wallpaper::ResizeMethod resizeMethod)
{
if (d->wallpaper) {
d->wallpaper->setResizeMethodHint(resizeMethod);
}
}
void WallpaperScript::setTargetSizeHint(const QSizeF &targetSize)
{
if (d->wallpaper) {
d->wallpaper->setTargetSizeHint(targetSize);
}
}
void WallpaperScript::setConfigurationRequired(bool needsConfiguring, const QString &reason)
{
if (d->wallpaper) {
d->wallpaper->setConfigurationRequired(needsConfiguring, reason);
}
}
void WallpaperScript::render(const QString &sourceImagePath, const QSize &size,
Wallpaper::ResizeMethod resizeMethod, const QColor &color)
{
if (d->wallpaper) {
d->wallpaper->render(sourceImagePath, size, resizeMethod, color);
}
}
void WallpaperScript::setUsingRenderingCache(bool useCache)
{
if (d->wallpaper) {
d->wallpaper->setUsingRenderingCache(useCache);
}
}
bool WallpaperScript::findInCache(const QString &key, QImage &image, unsigned int lastModified)
{
if (d->wallpaper) {
return d->wallpaper->findInCache(key, image, lastModified);
}
return false;
}
void WallpaperScript::insertIntoCache(const QString& key, const QImage &image)
{
if (d->wallpaper) {
d->wallpaper->insertIntoCache(key, image);
}
}
void WallpaperScript::setContextualActions(const QList<QAction*> &actions)
{
if (d->wallpaper) {
d->wallpaper->setContextualActions(actions);
}
}
void WallpaperScript::update(const QRectF &exposedArea)
{
if (d->wallpaper) {
d->wallpaper->update(exposedArea);
}
}
void WallpaperScript::configNeedsSaving()
{
if (d->wallpaper) {
d->wallpaper->configNeedsSaving();
}
}
void WallpaperScript::renderCompleted(const QImage &image)
{
Q_UNUSED(image)
}
} // Plasma namespace
+
+#include "moc_wallpaperscript.cpp"
diff --git a/plasma/service.cpp b/plasma/service.cpp
index 0b728abe2d..9ddecf2dca 100644
--- a/plasma/service.cpp
+++ b/plasma/service.cpp
@@ -1,420 +1,422 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "service.h"
#include "private/service_p.h"
#include "private/serviceprovider_p.h"
#include "config-plasma.h"
#include <QFile>
#include <QTimer>
#include <kdebug.h>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <ksharedconfig.h>
#include <kstandarddirs.h>
#include <dnssd/publicservice.h>
#include <dnssd/servicebrowser.h>
#include "configloader.h"
#include "version.h"
#include "private/configloader_p.h"
#include "private/remoteservice_p.h"
#include "private/remoteservicejob_p.h"
#include "pluginloader.h"
#include "remote/authorizationmanager_p.h"
namespace Plasma
{
Service::Service(QObject *parent)
: QObject(parent),
d(new ServicePrivate(this))
{
}
Service::Service(QObject *parent, const QVariantList &args)
: QObject(parent),
d(new ServicePrivate(this))
{
Q_UNUSED(args)
}
Service::~Service()
{
d->unpublish();
delete d;
}
Service *Service::access(const KUrl &url, QObject *parent)
{
return new RemoteService(parent, url);
}
void ServicePrivate::associatedWidgetDestroyed(QObject *obj)
{
associatedWidgets.remove(static_cast<QWidget*>(obj));
}
void ServicePrivate::associatedGraphicsWidgetDestroyed(QObject *obj)
{
associatedGraphicsWidgets.remove(static_cast<QGraphicsWidget*>(obj));
}
void ServicePrivate::publish(AnnouncementMethods methods, const QString &name, const KPluginInfo &metadata)
{
#ifdef ENABLE_REMOTE_WIDGETS
if (!serviceProvider) {
AuthorizationManager::self()->d->prepareForServicePublication();
serviceProvider = new ServiceProvider(name, q);
if (methods.testFlag(ZeroconfAnnouncement) &&
(DNSSD::ServiceBrowser::isAvailable() == DNSSD::ServiceBrowser::Working)) {
//TODO: dynamically pick a free port number.
publicService = new DNSSD::PublicService(name, "_plasma._tcp", 4000);
QMap<QString, QByteArray> textData;
textData["name"] = name.toUtf8();
textData["plasmoidname"] = metadata.name().toUtf8();
textData["description"] = metadata.comment().toUtf8();
textData["icon"] = metadata.icon().toUtf8();
publicService->setTextData(textData);
#ifndef NDEBUG
kDebug() << "about to publish";
#endif
publicService->publishAsync();
} else if (methods.testFlag(ZeroconfAnnouncement) &&
(DNSSD::ServiceBrowser::isAvailable() != DNSSD::ServiceBrowser::Working)) {
#ifndef NDEBUG
kDebug() << "sorry, but your zeroconf daemon doesn't seem to be running.";
#endif
}
} else {
#ifndef NDEBUG
kDebug() << "already published!";
#endif
}
#else
kWarning() << "libplasma is compiled without support for remote widgets. not publishing.";
#endif
}
void ServicePrivate::unpublish()
{
delete serviceProvider;
serviceProvider = 0;
delete publicService;
publicService = 0;
}
bool ServicePrivate::isPublished() const
{
if (serviceProvider) {
return true;
} else {
return false;
}
}
KConfigGroup ServicePrivate::dummyGroup()
{
if (!dummyConfig) {
dummyConfig = new KConfig(QString(), KConfig::SimpleConfig);
}
return KConfigGroup(dummyConfig, "DummyGroup");
}
void Service::setDestination(const QString &destination)
{
d->destination = destination;
}
QString Service::destination() const
{
return d->destination;
}
QStringList Service::operationNames() const
{
if (!d->config) {
#ifndef NDEBUG
kDebug() << "No valid operations scheme has been registered";
#endif
return QStringList();
}
return d->config->groupList();
}
KConfigGroup Service::operationDescription(const QString &operationName)
{
if (!d->config) {
#ifndef NDEBUG
kDebug() << "No valid operations scheme has been registered";
#endif
return d->dummyGroup();
}
d->config->writeConfig();
KConfigGroup params(d->config->config(), operationName);
//kDebug() << "operation" << operationName
// << "requested, has keys" << params.keyList() << "from"
// << d->config->config()->name();
return params;
}
QHash<QString, QVariant> Service::parametersFromDescription(const KConfigGroup &description)
{
QHash<QString, QVariant> params;
if (!d->config || !description.isValid()) {
return params;
}
const QString op = description.name();
foreach (const QString &key, description.keyList()) {
KConfigSkeletonItem *item = d->config->findItem(op, key);
if (item) {
params.insert(key, description.readEntry(key, item->property()));
}
}
return params;
}
ServiceJob *Service::startOperationCall(const KConfigGroup &description, QObject *parent)
{
// TODO: nested groups?
ServiceJob *job = 0;
const QString op = description.isValid() ? description.name() : QString();
RemoteService *rs = qobject_cast<RemoteService *>(this);
if (!op.isEmpty() && rs && !rs->isReady()) {
// if we have an operation, but a non-ready remote service, just let it through
#ifndef NDEBUG
kDebug() << "Remote service is not ready; queueing operation";
#endif
QHash<QString, QVariant> params;
job = createJob(op, params);
RemoteServiceJob *rsj = qobject_cast<RemoteServiceJob *>(job);
if (rsj) {
rsj->setDelayedDescription(description);
}
} else if (!d->config) {
#ifndef NDEBUG
kDebug() << "No valid operations scheme has been registered";
#endif
} else if (!op.isEmpty() && d->config->hasGroup(op)) {
if (d->disabledOperations.contains(op)) {
#ifndef NDEBUG
kDebug() << "Operation" << op << "is disabled";
#endif
} else {
QHash<QString, QVariant> params = parametersFromDescription(description);
job = createJob(op, params);
}
} else {
#ifndef NDEBUG
kDebug() << "Not a valid group!"<<d->config->groupList();
#endif
}
if (!job) {
job = new NullServiceJob(d->destination, op, this);
}
job->setParent(parent ? parent : this);
QTimer::singleShot(0, job, SLOT(autoStart()));
return job;
}
void Service::associateWidget(QWidget *widget, const QString &operation)
{
if (!widget) {
return;
}
disassociateWidget(widget);
d->associatedWidgets.insert(widget, operation);
connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(associatedWidgetDestroyed(QObject*)));
widget->setEnabled(!d->disabledOperations.contains(operation));
}
void Service::disassociateWidget(QWidget *widget)
{
if (!widget) {
return;
}
disconnect(widget, SIGNAL(destroyed(QObject*)),
this, SLOT(associatedWidgetDestroyed(QObject*)));
d->associatedWidgets.remove(widget);
}
void Service::associateWidget(QGraphicsWidget *widget, const QString &operation)
{
if (!widget) {
return;
}
disassociateWidget(widget);
d->associatedGraphicsWidgets.insert(widget, operation);
connect(widget, SIGNAL(destroyed(QObject*)),
this, SLOT(associatedGraphicsWidgetDestroyed(QObject*)));
widget->setEnabled(!d->disabledOperations.contains(operation));
}
void Service::disassociateWidget(QGraphicsWidget *widget)
{
if (!widget) {
return;
}
disconnect(widget, SIGNAL(destroyed(QObject*)),
this, SLOT(associatedGraphicsWidgetDestroyed(QObject*)));
d->associatedGraphicsWidgets.remove(widget);
}
QString Service::name() const
{
return d->name;
}
void Service::setName(const QString &name)
{
d->name = name;
// now reset the config, which may be based on our name
delete d->config;
d->config = 0;
delete d->dummyConfig;
d->dummyConfig = 0;
registerOperationsScheme();
emit serviceReady(this);
}
void Service::setOperationEnabled(const QString &operation, bool enable)
{
if (!d->config || !d->config->hasGroup(operation)) {
return;
}
if (enable) {
d->disabledOperations.remove(operation);
} else {
d->disabledOperations.insert(operation);
}
{
QHashIterator<QWidget *, QString> it(d->associatedWidgets);
while (it.hasNext()) {
it.next();
if (it.value() == operation) {
it.key()->setEnabled(enable);
}
}
}
{
QHashIterator<QGraphicsWidget *, QString> it(d->associatedGraphicsWidgets);
while (it.hasNext()) {
it.next();
if (it.value() == operation) {
it.key()->setEnabled(enable);
}
}
}
}
bool Service::isOperationEnabled(const QString &operation) const
{
return d->config && d->config->hasGroup(operation) && !d->disabledOperations.contains(operation);
}
void Service::setOperationsScheme(QIODevice *xml)
{
delete d->config;
delete d->dummyConfig;
d->dummyConfig = 0;
KSharedConfigPtr c = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
d->config = new ConfigLoader(c, xml, this);
d->config->d->setWriteDefaults(true);
emit operationsChanged();
{
QHashIterator<QWidget *, QString> it(d->associatedWidgets);
while (it.hasNext()) {
it.next();
it.key()->setEnabled(d->config->hasGroup(it.value()));
}
}
{
QHashIterator<QGraphicsWidget *, QString> it(d->associatedGraphicsWidgets);
while (it.hasNext()) {
it.next();
it.key()->setEnabled(d->config->hasGroup(it.value()));
}
}
}
void Service::registerOperationsScheme()
{
if (d->config) {
// we've already done our job. let's go home.
return;
}
if (d->name.isEmpty()) {
#ifndef NDEBUG
kDebug() << "No name found";
#endif
return;
}
const QString path = KStandardDirs::locate("data", "plasma/services/" + d->name + ".operations");
if (path.isEmpty()) {
#ifndef NDEBUG
kDebug() << "Cannot find operations description:" << d->name << ".operations";
#endif
return;
}
QFile file(path);
setOperationsScheme(&file);
}
} // namespace Plasma
+
+#include "moc_service.cpp"
diff --git a/plasma/servicejob.cpp b/plasma/servicejob.cpp
index 899c053e87..338b308ce5 100644
--- a/plasma/servicejob.cpp
+++ b/plasma/servicejob.cpp
@@ -1,102 +1,104 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "servicejob.h"
#include <kdebug.h>
#include <plasma/private/servicejob_p.h>
namespace Plasma
{
ServiceJobPrivate::ServiceJobPrivate(ServiceJob *owner, const QString &dest,
const QString &op, const QHash<QString, QVariant> &params)
: q(owner),
destination(dest),
operation(op),
parameters(params),
m_allowAutoStart(true)
{
}
void ServiceJobPrivate::preventAutoStart()
{
m_allowAutoStart = false;
}
void ServiceJobPrivate::autoStart()
{
if (m_allowAutoStart) {
q->start();
}
}
ServiceJob::ServiceJob(const QString &destination, const QString &operation,
const QHash<QString, QVariant> &parameters, QObject *parent)
: KJob(parent),
d(new ServiceJobPrivate(this, destination, operation, parameters))
{
connect(this, SIGNAL(finished(KJob*)), this, SLOT(preventAutoStart()));
}
ServiceJob::~ServiceJob()
{
delete d;
}
QString ServiceJob::destination() const
{
return d->destination;
}
QString ServiceJob::operationName() const
{
return d->operation;
}
QHash<QString, QVariant> ServiceJob::parameters() const
{
return d->parameters;
}
Credentials ServiceJob::identity() const
{
return d->identity;
}
QVariant ServiceJob::result() const
{
return d->result;
}
void ServiceJob::setResult(const QVariant &result)
{
d->result = result;
emitResult();
}
void ServiceJob::start()
{
setResult(false);
}
} // namespace Plasma
+
+#include "moc_servicejob.cpp"
diff --git a/plasma/svg.cpp b/plasma/svg.cpp
index 5a9806bd48..776f9c681e 100644
--- a/plasma/svg.cpp
+++ b/plasma/svg.cpp
@@ -1,828 +1,830 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
* Copyright 2008-2010 Marco Martin <notmart@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "svg.h"
#include "private/svg_p.h"
#include <cmath>
#include <QDir>
#include <QDomDocument>
#include <QMatrix>
#include <QPainter>
#include <QStringBuilder>
#include <kcolorscheme.h>
#include <kconfiggroup.h>
#include <kdebug.h>
#include <kfilterdev.h>
#include <kiconeffect.h>
#include <kglobalsettings.h>
#include <ksharedptr.h>
#include "applet.h"
#include "package.h"
#include "theme.h"
namespace Plasma
{
SharedSvgRenderer::SharedSvgRenderer(QObject *parent)
: QSvgRenderer(parent)
{
}
SharedSvgRenderer::SharedSvgRenderer(
const QString &filename,
const QString &styleSheet,
QHash<QString, QRectF> &interestingElements,
QObject *parent)
: QSvgRenderer(parent)
{
KCompressionDevice file(filename, KCompressionDevice::GZip);
if (!file.open(QIODevice::ReadOnly)) {
return;
}
load(file.readAll(), styleSheet, interestingElements);
}
SharedSvgRenderer::SharedSvgRenderer(
const QByteArray &contents,
const QString &styleSheet,
QHash<QString, QRectF> &interestingElements,
QObject *parent)
: QSvgRenderer(parent)
{
load(contents, styleSheet, interestingElements);
}
bool SharedSvgRenderer::load(
const QByteArray &contents,
const QString &styleSheet,
QHash<QString, QRectF> &interestingElements)
{
// Apply the style sheet.
if (!styleSheet.isEmpty() && contents.contains("current-color-scheme")) {
QDomDocument svg;
if (!svg.setContent(contents)) {
return false;
}
QDomNode defs = svg.elementsByTagName("defs").item(0);
for (QDomElement style = defs.firstChildElement("style"); !style.isNull();
style = style.nextSiblingElement("style")) {
if (style.attribute("id") == "current-color-scheme") {
QDomElement colorScheme = svg.createElement("style");
colorScheme.setAttribute("type", "text/css");
colorScheme.setAttribute("id", "current-color-scheme");
defs.replaceChild(colorScheme, style);
colorScheme.appendChild(svg.createCDATASection(styleSheet));
interestingElements.insert("current-color-scheme", QRect(0,0,1,1));
break;
}
}
if (!QSvgRenderer::load(svg.toByteArray(-1))) {
return false;
}
} else if (!QSvgRenderer::load(contents)) {
return false;
}
// Search the SVG to find and store all ids that contain size hints.
const QString contentsAsString(QString::fromLatin1(contents));
QRegExp idExpr("id\\s*=\\s*(['\"])(\\d+-\\d+-.*)\\1");
idExpr.setMinimal(true);
int pos = 0;
while ((pos = idExpr.indexIn(contentsAsString, pos)) != -1) {
QString elementId = idExpr.cap(2);
QRectF elementRect = boundsOnElement(elementId);
if (elementRect.isValid()) {
interestingElements.insert(elementId, elementRect);
}
pos += idExpr.matchedLength();
}
return true;
}
#define QLSEP QLatin1Char('_')
#define CACHE_ID_WITH_SIZE(size, id) QString::number(int(size.width())) % QLSEP % QString::number(int(size.height())) % QLSEP % id
#define CACHE_ID_NATURAL_SIZE(id) QLatin1Literal("Natural") % QLSEP % id
SvgPrivate::SvgPrivate(Svg *svg)
: q(svg),
renderer(0),
styleCrc(0),
lastModified(0),
multipleImages(false),
themed(false),
applyColors(false),
usesColors(false),
cacheRendering(true),
themeFailed(false)
{
}
SvgPrivate::~SvgPrivate()
{
eraseRenderer();
}
//This function is meant for the rects cache
QString SvgPrivate::cacheId(const QString &elementId)
{
if (size.isValid() && size != naturalSize) {
return CACHE_ID_WITH_SIZE(size, elementId);
} else {
return CACHE_ID_NATURAL_SIZE(elementId);
}
}
//This function is meant for the pixmap cache
QString SvgPrivate::cachePath(const QString &path, const QSize &size)
{
return CACHE_ID_WITH_SIZE(size, path);
}
bool SvgPrivate::setImagePath(const QString &imagePath)
{
const bool isThemed = !QDir::isAbsolutePath(imagePath);
// lets check to see if we're already set to this file
if (isThemed == themed &&
((themed && themePath == imagePath) ||
(!themed && path == imagePath))) {
return false;
}
eraseRenderer();
// if we don't have any path right now and are going to set one,
// then lets not schedule a repaint because we are just initializing!
bool updateNeeded = true; //!path.isEmpty() || !themePath.isEmpty();
QObject::disconnect(actualTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()));
if (isThemed && !themed && s_systemColorsCache) {
// catch the case where we weren't themed, but now we are, and the colors cache was set up
// ensure we are not connected to that theme previously
QObject::disconnect(s_systemColorsCache.data(), 0, q, 0);
}
themed = isThemed;
path.clear();
themePath.clear();
localRectCache.clear();
elementsWithSizeHints.clear();
if (themed) {
themePath = imagePath;
themeFailed = false;
QObject::connect(actualTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()));
} else if (QFile::exists(imagePath)) {
QObject::connect(cacheAndColorsTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()), Qt::UniqueConnection);
path = imagePath;
} else {
#ifndef NDEBUG
kDebug() << "file '" << path << "' does not exist!";
#endif
}
// check if svg wants colorscheme applied
checkColorHints();
// also images with absolute path needs to have a natural size initialized,
// even if looks a bit weird using Theme to store non-themed stuff
if (themed || QFile::exists(imagePath)) {
QRectF rect;
if (cacheAndColorsTheme()->findInRectsCache(path, "_Natural", rect)) {
naturalSize = rect.size();
} else {
createRenderer();
naturalSize = renderer->defaultSize();
//kDebug() << "natural size for" << path << "from renderer is" << naturalSize;
cacheAndColorsTheme()->insertIntoRectsCache(path, "_Natural", QRectF(QPointF(0,0), naturalSize));
//kDebug() << "natural size for" << path << "from cache is" << naturalSize;
}
}
if (!themed) {
QFile f(imagePath);
QFileInfo info(f);
lastModified = info.lastModified().toTime_t();
}
return updateNeeded;
}
Theme *SvgPrivate::actualTheme()
{
if (!theme) {
theme = Plasma::Theme::defaultTheme();
}
return theme.data();
}
Theme *SvgPrivate::cacheAndColorsTheme()
{
if (themed) {
return actualTheme();
} else {
// use a separate cache source for unthemed svg's
if (!s_systemColorsCache) {
//FIXME: reference count this, so that it is deleted when no longer in use
s_systemColorsCache = new Plasma::Theme("internal-system-colors");
}
return s_systemColorsCache.data();
}
}
QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s)
{
QSize size;
QString actualElementId;
if (elementsWithSizeHints.isEmpty()) {
// Fetch all size hinted element ids from the theme's rect cache
// and store them locally.
QRegExp sizeHintedKeyExpr(CACHE_ID_NATURAL_SIZE("(\\d+)-(\\d+)-(.+)"));
foreach (const QString &key, cacheAndColorsTheme()->listCachedRectKeys(path)) {
if (sizeHintedKeyExpr.exactMatch(key)) {
QString baseElementId = sizeHintedKeyExpr.cap(3);
QSize sizeHint(sizeHintedKeyExpr.cap(1).toInt(),
sizeHintedKeyExpr.cap(2).toInt());
if (sizeHint.isValid()) {
elementsWithSizeHints.insertMulti(baseElementId, sizeHint);
}
}
}
if (elementsWithSizeHints.isEmpty()) {
// Make sure we won't query the theme unnecessarily.
elementsWithSizeHints.insert(QString(), QSize());
}
}
// Look at the size hinted elements and try to find the smallest one with an
// identical aspect ratio.
if (s.isValid() && !elementId.isEmpty()) {
QList<QSize> elementSizeHints = elementsWithSizeHints.values(elementId);
if (!elementSizeHints.isEmpty()) {
QSize bestFit(-1, -1);
Q_FOREACH(const QSize &hint, elementSizeHints) {
if (hint.width() >= s.width() && hint.height() >= s.height() &&
(!bestFit.isValid() ||
(bestFit.width() * bestFit.height()) > (hint.width() * hint.height()))) {
bestFit = hint;
}
}
if (bestFit.isValid()) {
actualElementId = QString::number(bestFit.width()) % "-" %
QString::number(bestFit.height()) % "-" % elementId;
}
}
}
if (elementId.isEmpty() || !q->hasElement(actualElementId)) {
actualElementId = elementId;
}
if (elementId.isEmpty() || (multipleImages && s.isValid())) {
size = s.toSize();
} else {
size = elementRect(actualElementId).size().toSize();
}
if (size.isEmpty()) {
return QPixmap();
}
QString id = cachePath(path, size);
if (!actualElementId.isEmpty()) {
id.append(actualElementId);
}
//kDebug() << "id is " << id;
QPixmap p;
if (cacheRendering && cacheAndColorsTheme()->findInCache(id, p, lastModified)) {
//kDebug() << "found cached version of " << id << p.size();
return p;
}
//kDebug() << "didn't find cached version of " << id << ", so re-rendering";
//kDebug() << "size for " << actualElementId << " is " << s;
// we have to re-render this puppy
createRenderer();
QRectF finalRect = makeUniform(renderer->boundsOnElement(actualElementId), QRect(QPoint(0,0), size));
//don't alter the pixmap size or it won't match up properly to, e.g., FrameSvg elements
//makeUniform should never change the size so much that it gains or loses a whole pixel
p = QPixmap(size);
p.fill(Qt::transparent);
QPainter renderPainter(&p);
if (actualElementId.isEmpty()) {
renderer->render(&renderPainter, finalRect);
} else {
renderer->render(&renderPainter, actualElementId, finalRect);
}
renderPainter.end();
// Apply current color scheme if the svg asks for it
if (applyColors) {
QImage itmp = p.toImage();
KIconEffect::colorize(itmp, cacheAndColorsTheme()->color(Theme::BackgroundColor), 1.0);
p = p.fromImage(itmp);
}
if (cacheRendering) {
cacheAndColorsTheme()->insertIntoCache(id, p, QString::number((qint64)q, 16) % QLSEP % actualElementId);
}
return p;
}
void SvgPrivate::createRenderer()
{
if (renderer) {
return;
}
//kDebug() << kBacktrace();
if (themed && path.isEmpty() && !themeFailed) {
Applet *applet = qobject_cast<Applet*>(q->parent());
//FIXME: this maybe could be more efficient if we knew if the package was empty, e.g. for
//C++; however, I'm not sure this has any real world runtime impact. something to measure
//for.
if (applet && applet->package().isValid()) {
const Package package = applet->package();
path = package.filePath("images", themePath + ".svg");
if (path.isEmpty()) {
path = package.filePath("images", themePath + ".svgz");
}
}
if (path.isEmpty()) {
path = actualTheme()->imagePath(themePath);
themeFailed = path.isEmpty();
if (themeFailed) {
kWarning() << "No image path found for" << themePath;
}
}
}
//kDebug() << "********************************";
//kDebug() << "FAIL! **************************";
//kDebug() << path << "**";
QString styleSheet = cacheAndColorsTheme()->styleSheet("SVG");
styleCrc = qChecksum(styleSheet.toUtf8(), styleSheet.size());
QHash<QString, SharedSvgRenderer::Ptr>::const_iterator it = s_renderers.constFind(styleCrc + path);
if (it != s_renderers.constEnd()) {
//kDebug() << "gots us an existing one!";
renderer = it.value();
} else {
if (path.isEmpty()) {
renderer = new SharedSvgRenderer();
} else {
QHash<QString, QRectF> interestingElements;
renderer = new SharedSvgRenderer(path, styleSheet, interestingElements);
// Add interesting elements to the theme's rect cache.
QHashIterator<QString, QRectF> i(interestingElements);
while (i.hasNext()) {
i.next();
const QString &elementId = i.key();
const QRectF &elementRect = i.value();
const QString cacheId = CACHE_ID_NATURAL_SIZE(elementId);
localRectCache.insert(cacheId, elementRect);
cacheAndColorsTheme()->insertIntoRectsCache(path, cacheId, elementRect);
}
}
s_renderers[styleCrc + path] = renderer;
}
if (size == QSizeF()) {
size = renderer->defaultSize();
}
}
void SvgPrivate::eraseRenderer()
{
if (renderer && renderer.count() == 2) {
// this and the cache reference it
s_renderers.erase(s_renderers.find(styleCrc + path));
if (theme) {
theme.data()->releaseRectsCache(path);
}
}
renderer = 0;
styleCrc = 0;
localRectCache.clear();
elementsWithSizeHints.clear();
}
QRectF SvgPrivate::elementRect(const QString &elementId)
{
if (themed && path.isEmpty()) {
if (themeFailed) {
return QRectF();
}
path = actualTheme()->imagePath(themePath);
themeFailed = path.isEmpty();
if (themeFailed) {
return QRectF();
}
}
QString id = cacheId(elementId);
if (localRectCache.contains(id)) {
return localRectCache.value(id);
}
QRectF rect;
if (cacheAndColorsTheme()->findInRectsCache(path, id, rect)) {
localRectCache.insert(id, rect);
} else {
rect = findAndCacheElementRect(elementId);
}
return rect;
}
QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId)
{
createRenderer();
// createRenderer() can insert some interesting rects in the cache, so check it
const QString id = cacheId(elementId);
if (localRectCache.contains(id)) {
return localRectCache.value(id);
}
QRectF elementRect = renderer->elementExists(elementId) ?
renderer->matrixForElement(elementId).map(renderer->boundsOnElement(elementId)).boundingRect() :
QRectF();
naturalSize = renderer->defaultSize();
qreal dx = size.width() / naturalSize.width();
qreal dy = size.height() / naturalSize.height();
elementRect = QRectF(elementRect.x() * dx, elementRect.y() * dy,
elementRect.width() * dx, elementRect.height() * dy);
cacheAndColorsTheme()->insertIntoRectsCache(path, id, elementRect);
return elementRect;
}
QMatrix SvgPrivate::matrixForElement(const QString &elementId)
{
createRenderer();
return renderer->matrixForElement(elementId);
}
void SvgPrivate::checkColorHints()
{
if (elementRect("hint-apply-color-scheme").isValid()) {
applyColors = true;
usesColors = true;
} else if (elementRect("current-color-scheme").isValid()) {
applyColors = false;
usesColors = true;
} else {
applyColors = false;
usesColors = false;
}
// check to see if we are using colors, but the theme isn't being used or isn't providing
// a colorscheme
if (usesColors && (!themed || !actualTheme()->colorScheme())) {
QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
q, SLOT(colorsChanged()), Qt::UniqueConnection);
} else {
QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
q, SLOT(colorsChanged()));
}
}
//Folowing two are utility functions to snap rendered elements to the pixel grid
//to and from are always 0 <= val <= 1
qreal SvgPrivate::closestDistance(qreal to, qreal from)
{
qreal a = to - from;
if (qFuzzyCompare(to, from))
return 0;
else if ( to > from ) {
qreal b = to - from - 1;
return (qAbs(a) > qAbs(b)) ? b : a;
} else {
qreal b = 1 + to - from;
return (qAbs(a) > qAbs(b)) ? b : a;
}
}
QRectF SvgPrivate::makeUniform(const QRectF &orig, const QRectF &dst)
{
if (qFuzzyIsNull(orig.x()) || qFuzzyIsNull(orig.y())) {
return dst;
}
QRectF res(dst);
qreal div_w = dst.width() / orig.width();
qreal div_h = dst.height() / orig.height();
qreal div_x = dst.x() / orig.x();
qreal div_y = dst.y() / orig.y();
//horizontal snap
if (!qFuzzyIsNull(div_x) && !qFuzzyCompare(div_w, div_x)) {
qreal rem_orig = orig.x() - (floor(orig.x()));
qreal rem_dst = dst.x() - (floor(dst.x()));
qreal offset = closestDistance(rem_dst, rem_orig);
res.translate(offset + offset*div_w, 0);
res.setWidth(res.width() + offset);
}
//vertical snap
if (!qFuzzyIsNull(div_y) && !qFuzzyCompare(div_h, div_y)) {
qreal rem_orig = orig.y() - (floor(orig.y()));
qreal rem_dst = dst.y() - (floor(dst.y()));
qreal offset = closestDistance(rem_dst, rem_orig);
res.translate(0, offset + offset*div_h);
res.setHeight(res.height() + offset);
}
//kDebug()<<"Aligning Rects, origin:"<<orig<<"destination:"<<dst<<"result:"<<res;
return res;
}
void SvgPrivate::themeChanged()
{
if (q->imagePath().isEmpty()) {
return;
}
if (themed) {
// check if new theme svg wants colorscheme applied
checkColorHints();
}
QString currentPath = themed ? themePath : path;
themePath.clear();
eraseRenderer();
setImagePath(currentPath);
//kDebug() << themePath << ">>>>>>>>>>>>>>>>>> theme changed";
emit q->repaintNeeded();
}
void SvgPrivate::colorsChanged()
{
if (!usesColors) {
return;
}
eraseRenderer();
//kDebug() << "repaint needed from colorsChanged";
emit q->repaintNeeded();
}
QHash<QString, SharedSvgRenderer::Ptr> SvgPrivate::s_renderers;
QWeakPointer<Theme> SvgPrivate::s_systemColorsCache;
Svg::Svg(QObject *parent)
: QObject(parent),
d(new SvgPrivate(this))
{
}
Svg::~Svg()
{
delete d;
}
QPixmap Svg::pixmap(const QString &elementID)
{
if (elementID.isNull() || d->multipleImages) {
return d->findInCache(elementID, size());
} else {
return d->findInCache(elementID);
}
}
void Svg::paint(QPainter *painter, const QPointF &point, const QString &elementID)
{
QPixmap pix((elementID.isNull() || d->multipleImages) ? d->findInCache(elementID, size()) :
d->findInCache(elementID));
if (pix.isNull()) {
return;
}
painter->drawPixmap(QRectF(point, pix.size()), pix, QRectF(QPointF(0, 0), pix.size()));
}
void Svg::paint(QPainter *painter, int x, int y, const QString &elementID)
{
paint(painter, QPointF(x, y), elementID);
}
void Svg::paint(QPainter *painter, const QRectF &rect, const QString &elementID)
{
QPixmap pix(d->findInCache(elementID, rect.size()));
painter->drawPixmap(QRectF(rect.topLeft(), pix.size()), pix, QRectF(QPointF(0, 0), pix.size()));
}
void Svg::paint(QPainter *painter, int x, int y, int width, int height, const QString &elementID)
{
QPixmap pix(d->findInCache(elementID, QSizeF(width, height)));
painter->drawPixmap(x, y, pix, 0, 0, pix.size().width(), pix.size().height());
}
QSize Svg::size() const
{
if (d->size.isEmpty()) {
d->size = d->naturalSize;
}
return d->size.toSize();
}
void Svg::resize(qreal width, qreal height)
{
resize(QSize(width, height));
}
void Svg::resize(const QSizeF &size)
{
if (qFuzzyCompare(size.width(), d->size.width()) &&
qFuzzyCompare(size.height(), d->size.height())) {
return;
}
d->size = size;
d->localRectCache.clear();
emit sizeChanged();
}
void Svg::resize()
{
if (qFuzzyCompare(d->naturalSize.width(), d->size.width()) &&
qFuzzyCompare(d->naturalSize.height(), d->size.height())) {
return;
}
d->size = d->naturalSize;
d->localRectCache.clear();
emit sizeChanged();
}
QSize Svg::elementSize(const QString &elementId) const
{
return d->elementRect(elementId).size().toSize();
}
QRectF Svg::elementRect(const QString &elementId) const
{
return d->elementRect(elementId);
}
bool Svg::hasElement(const QString &elementId) const
{
if (d->path.isNull() && d->themePath.isNull()) {
return false;
}
return d->elementRect(elementId).isValid();
}
QString Svg::elementAtPoint(const QPoint &point) const
{
Q_UNUSED(point)
return QString();
/*
FIXME: implement when Qt can support us!
d->createRenderer();
QSizeF naturalSize = d->renderer->defaultSize();
qreal dx = d->size.width() / naturalSize.width();
qreal dy = d->size.height() / naturalSize.height();
//kDebug() << point << "is really"
// << QPoint(point.x() *dx, naturalSize.height() - point.y() * dy);
return QString(); // d->renderer->elementAtPoint(QPoint(point.x() *dx, naturalSize.height() - point.y() * dy));
*/
}
bool Svg::isValid() const
{
if (d->path.isNull() && d->themePath.isNull()) {
return false;
}
d->createRenderer();
return d->renderer->isValid();
}
void Svg::setContainsMultipleImages(bool multiple)
{
d->multipleImages = multiple;
}
bool Svg::containsMultipleImages() const
{
return d->multipleImages;
}
void Svg::setImagePath(const QString &svgFilePath)
{
if (d->setImagePath(svgFilePath)) {
//kDebug() << "repaintNeeded";
emit repaintNeeded();
}
}
QString Svg::imagePath() const
{
return d->themed ? d->themePath : d->path;
}
void Svg::setUsingRenderingCache(bool useCache)
{
d->cacheRendering = useCache;
}
bool Svg::isUsingRenderingCache() const
{
return d->cacheRendering;
}
void Svg::setTheme(Plasma::Theme *theme)
{
if (!theme || theme == d->theme.data()) {
return;
}
if (d->theme) {
disconnect(d->theme.data(), 0, this, 0);
}
d->theme = theme;
connect(theme, SIGNAL(themeChanged()), this, SLOT(themeChanged()));
d->themeChanged();
}
Theme *Svg::theme() const
{
return d->theme ? d->theme.data() : Theme::defaultTheme();
}
} // Plasma namespace
+
+#include "moc_svg.cpp"
diff --git a/plasma/theme.cpp b/plasma/theme.cpp
index 5de6924200..1e424ca580 100644
--- a/plasma/theme.cpp
+++ b/plasma/theme.cpp
@@ -1,1069 +1,1069 @@
/*
* 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 "theme.h"
#include <QApplication>
#include <QFile>
#include <QFileInfo>
#include <QMutableListIterator>
#include <QPair>
#include <QStringBuilder>
#include <QTimer>
#ifdef Q_WS_X11
#include <QX11Info>
#include "private/effectwatcher_p.h"
#endif
#include <kcolorscheme.h>
#include <kcomponentdata.h>
#include <kconfiggroup.h>
#include <kdebug.h>
#include <kdirwatch.h>
#include <kglobal.h>
#include <kglobalsettings.h>
#include <kmanagerselection.h>
#include <kimagecache.h>
#include <ksharedconfig.h>
#include <kstandarddirs.h>
#include <kwindowsystem.h>
#include "libplasma-theme-global.h"
#include "private/packages_p.h"
#include "windoweffects.h"
namespace Plasma
{
//NOTE: Default wallpaper can be set from the theme configuration
#define DEFAULT_WALLPAPER_THEME "default"
#define DEFAULT_WALLPAPER_SUFFIX ".png"
static const int DEFAULT_WALLPAPER_WIDTH = 1920;
static const int DEFAULT_WALLPAPER_HEIGHT = 1200;
enum styles {
DEFAULTSTYLE,
SVGSTYLE
};
enum CacheType {
NoCache = 0,
PixmapCache = 1,
SvgElementsCache = 2
};
Q_DECLARE_FLAGS(CacheTypes, CacheType)
Q_DECLARE_OPERATORS_FOR_FLAGS(CacheTypes)
class ThemePrivate
{
public:
ThemePrivate(Theme *theme)
: q(theme),
colorScheme(QPalette::Active, KColorScheme::Window, KSharedConfigPtr(0)),
buttonColorScheme(QPalette::Active, KColorScheme::Button, KSharedConfigPtr(0)),
viewColorScheme(QPalette::Active, KColorScheme::View, KSharedConfigPtr(0)),
defaultWallpaperTheme(DEFAULT_WALLPAPER_THEME),
defaultWallpaperSuffix(DEFAULT_WALLPAPER_SUFFIX),
defaultWallpaperWidth(DEFAULT_WALLPAPER_WIDTH),
defaultWallpaperHeight(DEFAULT_WALLPAPER_HEIGHT),
pixmapCache(0),
cachesToDiscard(NoCache),
locolor(false),
compositingActive(KWindowSystem::self()->compositingActive()),
blurActive(false),
isDefault(false),
useGlobal(true),
hasWallpapers(false),
useNativeWidgetStyle(false)
{
generalFont = QApplication::font();
ThemeConfig config;
cacheTheme = config.cacheTheme();
saveTimer = new QTimer(q);
saveTimer->setSingleShot(true);
saveTimer->setInterval(600);
QObject::connect(saveTimer, SIGNAL(timeout()), q, SLOT(scheduledCacheUpdate()));
updateNotificationTimer = new QTimer(q);
updateNotificationTimer->setSingleShot(true);
updateNotificationTimer->setInterval(500);
QObject::connect(updateNotificationTimer, SIGNAL(timeout()), q, SLOT(notifyOfChanged()));
if (QPixmap::defaultDepth() > 8) {
QObject::connect(KWindowSystem::self(), SIGNAL(compositingChanged(bool)), q, SLOT(compositingChanged(bool)));
#ifdef Q_WS_X11
//watch for blur effect property changes as well
if (!s_blurEffectWatcher) {
s_blurEffectWatcher = new EffectWatcher("_KDE_NET_WM_BLUR_BEHIND_REGION");
}
QObject::connect(s_blurEffectWatcher, SIGNAL(effectChanged(bool)), q, SLOT(blurBehindChanged(bool)));
#endif
}
}
~ThemePrivate()
{
delete pixmapCache;
}
KConfigGroup &config()
{
if (!cfg.isValid()) {
QString groupName = "Theme";
if (!useGlobal) {
QString app = KGlobal::mainComponent().componentName();
if (!app.isEmpty()) {
#ifndef NDEBUG
kDebug() << "using theme for app" << app;
#endif
groupName.append("-").append(app);
}
}
cfg = KConfigGroup(KSharedConfig::openConfig(themeRcFile), groupName);
}
return cfg;
}
QString findInTheme(const QString &image, const QString &theme, bool cache = true);
void compositingChanged(bool active);
void discardCache(CacheTypes caches);
void scheduledCacheUpdate();
void scheduleThemeChangeNotification(CacheTypes caches);
void notifyOfChanged();
void colorsChanged();
void blurBehindChanged(bool blur);
bool useCache();
void settingsFileChanged(const QString &);
void setThemeName(const QString &themeName, bool writeSettings);
void onAppExitCleanup();
void processWallpaperSettings(KConfigBase *metadata);
const QString processStyleSheet(const QString &css);
static const char *defaultTheme;
static const char *systemColorsTheme;
static const char *themeRcFile;
#ifdef Q_WS_X11
static EffectWatcher *s_blurEffectWatcher;
#endif
Theme *q;
QString themeName;
QList<QString> fallbackThemes;
KSharedConfigPtr colors;
KColorScheme colorScheme;
KColorScheme buttonColorScheme;
KColorScheme viewColorScheme;
KConfigGroup cfg;
QFont generalFont;
QString defaultWallpaperTheme;
QString defaultWallpaperSuffix;
int defaultWallpaperWidth;
int defaultWallpaperHeight;
KImageCache *pixmapCache;
KSharedConfigPtr svgElementsCache;
QHash<QString, QSet<QString> > invalidElements;
QHash<QString, QPixmap> pixmapsToCache;
QHash<QString, QString> keysToCache;
QHash<QString, QString> idsToCache;
QHash<styles, QString> cachedStyleSheets;
QHash<QString, QString> discoveries;
QTimer *saveTimer;
QTimer *updateNotificationTimer;
int toolTipDelay;
CacheTypes cachesToDiscard;
bool locolor : 1;
bool compositingActive : 1;
bool blurActive : 1;
bool isDefault : 1;
bool useGlobal : 1;
bool hasWallpapers : 1;
bool cacheTheme : 1;
bool useNativeWidgetStyle :1;
};
const char *ThemePrivate::defaultTheme = "default";
const char *ThemePrivate::themeRcFile = "plasmarc";
// the system colors theme is used to cache unthemed svgs with colorization needs
// these svgs do not follow the theme's colors, but rather the system colors
const char *ThemePrivate::systemColorsTheme = "internal-system-colors";
#ifdef Q_WS_X11
EffectWatcher *ThemePrivate::s_blurEffectWatcher = 0;
#endif
bool ThemePrivate::useCache()
{
if (cacheTheme && !pixmapCache) {
ThemeConfig config;
pixmapCache = new KImageCache("plasma_theme_" + themeName, config.themeCacheKb() * 1024);
if (themeName != systemColorsTheme) {
//check for expired cache
// FIXME: when using the system colors, if they change while the application is not running
// the cache should be dropped; we need a way to detect system color change when the
// application is not running.
QFile f(KStandardDirs::locate("data", "desktoptheme/" + themeName + "/metadata.desktop"));
QFileInfo info(f);
if (info.lastModified().toTime_t() > uint(pixmapCache->lastModifiedTime())) {
pixmapCache->clear();
}
}
}
return cacheTheme;
}
void ThemePrivate::onAppExitCleanup()
{
pixmapsToCache.clear();
delete pixmapCache;
pixmapCache = 0;
cacheTheme = false;
}
QString ThemePrivate::findInTheme(const QString &image, const QString &theme, bool cache)
{
if (cache && discoveries.contains(image)) {
return discoveries[image];
}
QString search;
if (locolor) {
search = QLatin1Literal("desktoptheme/") % theme % QLatin1Literal("/locolor/") % image;
search = KStandardDirs::locate("data", search);
} else if (!compositingActive) {
search = QLatin1Literal("desktoptheme/") % theme % QLatin1Literal("/opaque/") % image;
search = KStandardDirs::locate("data", search);
} else if (WindowEffects::isEffectAvailable(WindowEffects::BlurBehind)) {
search = QLatin1Literal("desktoptheme/") % theme % QLatin1Literal("/translucent/") % image;
search = KStandardDirs::locate("data", search);
}
//not found or compositing enabled
if (search.isEmpty()) {
search = QLatin1Literal("desktoptheme/") % theme % QLatin1Char('/') % image;
search = KStandardDirs::locate("data", search);
}
if (cache && !search.isEmpty()) {
discoveries.insert(image, search);
}
return search;
}
void ThemePrivate::compositingChanged(bool active)
{
#ifdef Q_WS_X11
if (compositingActive != active) {
compositingActive = active;
//kDebug() << QTime::currentTime();
scheduleThemeChangeNotification(PixmapCache | SvgElementsCache);
}
#endif
}
void ThemePrivate::discardCache(CacheTypes caches)
{
if (caches & PixmapCache) {
pixmapsToCache.clear();
saveTimer->stop();
if (pixmapCache) {
pixmapCache->clear();
}
} else {
// This deletes the object but keeps the on-disk cache for later use
delete pixmapCache;
pixmapCache = 0;
}
cachedStyleSheets.clear();
if (caches & SvgElementsCache) {
discoveries.clear();
invalidElements.clear();
if (svgElementsCache) {
QFile f(svgElementsCache->name());
svgElementsCache = 0;
f.remove();
}
const QString svgElementsFile = KStandardDirs::locateLocal("cache", "plasma-svgelements-" + themeName);
svgElementsCache = KSharedConfig::openConfig(svgElementsFile);
}
}
void ThemePrivate::scheduledCacheUpdate()
{
if (useCache()) {
QHashIterator<QString, QPixmap> it(pixmapsToCache);
while (it.hasNext()) {
it.next();
pixmapCache->insertPixmap(idsToCache[it.key()], it.value());
}
}
pixmapsToCache.clear();
keysToCache.clear();
idsToCache.clear();
}
void ThemePrivate::colorsChanged()
{
colorScheme = KColorScheme(QPalette::Active, KColorScheme::Window, colors);
buttonColorScheme = KColorScheme(QPalette::Active, KColorScheme::Button, colors);
viewColorScheme = KColorScheme(QPalette::Active, KColorScheme::View, colors);
scheduleThemeChangeNotification(PixmapCache);
}
void ThemePrivate::blurBehindChanged(bool blur)
{
if (blurActive != blur) {
blurActive = blur;
scheduleThemeChangeNotification(PixmapCache | SvgElementsCache);
}
}
void ThemePrivate::scheduleThemeChangeNotification(CacheTypes caches)
{
cachesToDiscard |= caches;
updateNotificationTimer->start();
}
void ThemePrivate::notifyOfChanged()
{
//kDebug() << cachesToDiscard;
discardCache(cachesToDiscard);
cachesToDiscard = NoCache;
emit q->themeChanged();
}
const QString ThemePrivate::processStyleSheet(const QString &css)
{
QString stylesheet;
if (css.isEmpty()) {
stylesheet = cachedStyleSheets.value(DEFAULTSTYLE);
if (stylesheet.isEmpty()) {
stylesheet = QString("\n\
body {\n\
color: %textcolor;\n\
font-size: %fontsize;\n\
font-family: %fontfamily;\n\
}\n\
a:active { color: %activatedlink; }\n\
a:link { color: %link; }\n\
a:visited { color: %visitedlink; }\n\
a:hover { color: %hoveredlink; text-decoration: none; }\n\
");
stylesheet = processStyleSheet(stylesheet);
cachedStyleSheets.insert(DEFAULTSTYLE, stylesheet);
}
return stylesheet;
} else if (css == "SVG") {
stylesheet = cachedStyleSheets.value(SVGSTYLE);
if (stylesheet.isEmpty()) {
QString skel = ".ColorScheme-%1{color:%2;}";
stylesheet += skel.arg("Text","%textcolor");
stylesheet += skel.arg("Background","%backgroundcolor");
stylesheet += skel.arg("ButtonText","%buttontextcolor");
stylesheet += skel.arg("ButtonBackground","%buttonbackgroundcolor");
stylesheet += skel.arg("ButtonHover","%buttonhovercolor");
stylesheet += skel.arg("ButtonFocus","%buttonfocuscolor");
stylesheet += skel.arg("ViewText","%viewtextcolor");
stylesheet += skel.arg("ViewBackground","%viewbackgroundcolor");
stylesheet += skel.arg("ViewHover","%viewhovercolor");
stylesheet += skel.arg("ViewFocus","%viewfocuscolor");
stylesheet = processStyleSheet(stylesheet);
cachedStyleSheets.insert(SVGSTYLE, stylesheet);
}
return stylesheet;
} else {
stylesheet = css;
}
QHash<QString, QString> elements;
// If you add elements here, make sure their names are sufficiently unique to not cause
// clashes between element keys
elements["%textcolor"] = q->color(Theme::TextColor).name();
elements["%backgroundcolor"] = q->color(Theme::BackgroundColor).name();
elements["%visitedlink"] = q->color(Theme::VisitedLinkColor).name();
elements["%activatedlink"] = q->color(Theme::HighlightColor).name();
elements["%hoveredlink"] = q->color(Theme::HighlightColor).name();
elements["%link"] = q->color(Theme::LinkColor).name();
elements["%buttontextcolor"] = q->color(Theme::ButtonTextColor).name();
elements["%buttonbackgroundcolor"] = q->color(Theme::ButtonBackgroundColor).name();
elements["%buttonhovercolor"] = q->color(Theme::ButtonHoverColor).name();
elements["%buttonfocuscolor"] = q->color(Theme::ButtonFocusColor).name();
elements["%viewtextcolor"] = q->color(Theme::ViewTextColor).name();
elements["%viewbackgroundcolor"] = q->color(Theme::ViewBackgroundColor).name();
elements["%viewhovercolor"] = q->color(Theme::ViewHoverColor).name();
elements["%viewfocuscolor"] = q->color(Theme::ViewFocusColor).name();
QFont font = q->font(Theme::DefaultFont);
elements["%fontsize"] = QString("%1pt").arg(font.pointSize());
elements["%fontfamily"] = font.family().split('[').first();
elements["%smallfontsize"] = QString("%1pt").arg(KGlobalSettings::smallestReadableFont().pointSize());
QHash<QString, QString>::const_iterator it = elements.constBegin();
QHash<QString, QString>::const_iterator itEnd = elements.constEnd();
for ( ; it != itEnd; ++it) {
stylesheet.replace(it.key(), it.value());
}
return stylesheet;
}
class ThemeSingleton
{
public:
ThemeSingleton()
{
self.d->isDefault = true;
//FIXME: if/when kconfig gets change notification, this will be unnecessary
KDirWatch::self()->addFile(KStandardDirs::locateLocal("config", ThemePrivate::themeRcFile));
QObject::connect(KDirWatch::self(), SIGNAL(created(QString)), &self, SLOT(settingsFileChanged(QString)));
QObject::connect(KDirWatch::self(), SIGNAL(dirty(QString)), &self, SLOT(settingsFileChanged(QString)));
}
Theme self;
};
K_GLOBAL_STATIC(ThemeSingleton, privateThemeSelf)
Theme *Theme::defaultTheme()
{
return &privateThemeSelf->self;
}
Theme::Theme(QObject *parent)
: QObject(parent),
d(new ThemePrivate(this))
{
settingsChanged();
if (QCoreApplication::instance()) {
connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
this, SLOT(onAppExitCleanup()));
}
}
Theme::Theme(const QString &themeName, QObject *parent)
: QObject(parent),
d(new ThemePrivate(this))
{
// turn off caching so we don't accidently trigger unnecessary disk activity at this point
bool useCache = d->cacheTheme;
d->cacheTheme = false;
setThemeName(themeName);
d->cacheTheme = useCache;
if (QCoreApplication::instance()) {
connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
this, SLOT(onAppExitCleanup()));
}
}
Theme::~Theme()
{
if (d->svgElementsCache) {
QHashIterator<QString, QSet<QString> > it(d->invalidElements);
while (it.hasNext()) {
it.next();
KConfigGroup imageGroup(d->svgElementsCache, it.key());
imageGroup.writeEntry("invalidElements", it.value().toList()); //FIXME: add QSet support to KConfig
}
}
d->onAppExitCleanup();
delete d;
}
KPluginInfo::List Theme::listThemeInfo()
{
const QStringList themes = KGlobal::dirs()->findAllResources("data", "desktoptheme/*/metadata.desktop",
KStandardDirs::NoDuplicates);
return KPluginInfo::fromFiles(themes);
}
void ThemePrivate::settingsFileChanged(const QString &file)
{
if (file.endsWith(themeRcFile)) {
config().config()->reparseConfiguration();
q->settingsChanged();
}
}
void Theme::settingsChanged()
{
KConfigGroup cg = d->config();
d->setThemeName(cg.readEntry("name", ThemePrivate::defaultTheme), false);
cg = KConfigGroup(cg.config(), "PlasmaToolTips");
d->toolTipDelay = cg.readEntry("Delay", 700);
}
void Theme::setThemeName(const QString &themeName)
{
d->setThemeName(themeName, true);
}
void ThemePrivate::processWallpaperSettings(KConfigBase *metadata)
{
if (!defaultWallpaperTheme.isEmpty() && defaultWallpaperTheme != DEFAULT_WALLPAPER_THEME) {
return;
}
KConfigGroup cg;
if (metadata->hasGroup("Wallpaper")) {
// we have a theme color config, so let's also check to see if
// there is a wallpaper defined in there.
cg = KConfigGroup(metadata, "Wallpaper");
} else {
// since we didn't find an entry in the theme, let's look in the main
// theme config
cg = config();
}
defaultWallpaperTheme = cg.readEntry("defaultWallpaperTheme", DEFAULT_WALLPAPER_THEME);
defaultWallpaperSuffix = cg.readEntry("defaultFileSuffix", DEFAULT_WALLPAPER_SUFFIX);
defaultWallpaperWidth = cg.readEntry("defaultWidth", DEFAULT_WALLPAPER_WIDTH);
defaultWallpaperHeight = cg.readEntry("defaultHeight", DEFAULT_WALLPAPER_HEIGHT);
}
void ThemePrivate::setThemeName(const QString &tempThemeName, bool writeSettings)
{
//kDebug() << tempThemeName;
QString theme = tempThemeName;
if (theme.isEmpty() || theme == themeName) {
// let's try and get the default theme at least
if (themeName.isEmpty()) {
theme = ThemePrivate::defaultTheme;
} else {
return;
}
}
// we have one special theme: essentially a dummy theme used to cache things with
// the system colors.
bool realTheme = theme != systemColorsTheme;
if (realTheme) {
QString themePath = KStandardDirs::locate("data", QLatin1Literal("desktoptheme/") % theme % QLatin1Char('/'));
if (themePath.isEmpty() && themeName.isEmpty()) {
themePath = KStandardDirs::locate("data", "desktoptheme/default/");
if (themePath.isEmpty()) {
return;
}
theme = ThemePrivate::defaultTheme;
}
}
// check again as ThemePrivate::defaultTheme might be empty
if (themeName == theme) {
return;
}
themeName = theme;
// load the color scheme config
const QString colorsFile = realTheme ? KStandardDirs::locate("data", QLatin1Literal("desktoptheme/") % theme % QLatin1Literal("/colors"))
: QString();
//kDebug() << "we're going for..." << colorsFile << "*******************";
// load the wallpaper settings, if any
if (realTheme) {
const QString metadataPath(KStandardDirs::locate("data", QLatin1Literal("desktoptheme/") % theme % QLatin1Literal("/metadata.desktop")));
KConfig metadata(metadataPath);
processWallpaperSettings(&metadata);
KConfigGroup cg(&metadata, "Settings");
useNativeWidgetStyle = cg.readEntry("UseNativeWidgetStyle", false);
QString fallback = cg.readEntry("FallbackTheme", QString());
fallbackThemes.clear();
while (!fallback.isEmpty() && !fallbackThemes.contains(fallback)) {
fallbackThemes.append(fallback);
QString metadataPath(KStandardDirs::locate("data", QLatin1Literal("desktoptheme/") % theme % QLatin1Literal("/metadata.desktop")));
KConfig metadata(metadataPath);
KConfigGroup cg(&metadata, "Settings");
fallback = cg.readEntry("FallbackTheme", QString());
}
if (!fallbackThemes.contains("oxygen")) {
fallbackThemes.append("oxygen");
}
if (!fallbackThemes.contains(ThemePrivate::defaultTheme)) {
fallbackThemes.append(ThemePrivate::defaultTheme);
}
foreach (const QString &theme, fallbackThemes) {
QString metadataPath(KStandardDirs::locate("data", QLatin1Literal("desktoptheme/") % theme % QLatin1Literal("/metadata.desktop")));
KConfig metadata(metadataPath);
processWallpaperSettings(&metadata);
}
}
if (colorsFile.isEmpty()) {
colors = 0;
QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
q, SLOT(colorsChanged()), Qt::UniqueConnection);
} else {
QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
q, SLOT(colorsChanged()));
colors = KSharedConfig::openConfig(colorsFile);
}
colorScheme = KColorScheme(QPalette::Active, KColorScheme::Window, colors);
buttonColorScheme = KColorScheme(QPalette::Active, KColorScheme::Button, colors);
viewColorScheme = KColorScheme(QPalette::Active, KColorScheme::View, colors);
hasWallpapers = KStandardDirs::exists(KStandardDirs::locateLocal("data", QLatin1Literal("desktoptheme/") % theme % QLatin1Literal("/wallpapers/")));
if (realTheme && isDefault && writeSettings) {
// we're the default theme, let's save our state
KConfigGroup &cg = config();
if (ThemePrivate::defaultTheme == themeName) {
cg.deleteEntry("name");
} else {
cg.writeEntry("name", themeName);
}
cg.sync();
}
scheduleThemeChangeNotification(SvgElementsCache);
}
QString Theme::themeName() const
{
return d->themeName;
}
QString Theme::imagePath(const QString &name) const
{
// look for a compressed svg file in the theme
if (name.contains("../") || name.isEmpty()) {
// we don't support relative paths
//kDebug() << "Theme says: bad image path " << name;
return QString();
}
const QString svgzName = name % QLatin1Literal(".svgz");
QString path = d->findInTheme(svgzName, d->themeName);
if (path.isEmpty()) {
// try for an uncompressed svg file
const QString svgName = name % QLatin1Literal(".svg");
path = d->findInTheme(svgName, d->themeName);
// search in fallback themes if necessary
for (int i = 0; path.isEmpty() && i < d->fallbackThemes.count(); ++i) {
if (d->themeName == d->fallbackThemes[i]) {
continue;
}
// try a compressed svg file in the fallback theme
path = d->findInTheme(svgzName, d->fallbackThemes[i]);
if (path.isEmpty()) {
// try an uncompressed svg file in the fallback theme
path = d->findInTheme(svgName, d->fallbackThemes[i]);
}
}
}
/*
if (path.isEmpty()) {
#ifndef NDEBUG
kDebug() << "Theme says: bad image path " << name;
#endif
}
*/
return path;
}
QString Theme::styleSheet(const QString &css) const
{
return d->processStyleSheet(css);
}
QString Theme::wallpaperPath(const QSize &size) const
{
QString fullPath;
QString image = d->defaultWallpaperTheme;
image.append("/contents/images/%1x%2").append(d->defaultWallpaperSuffix);
QString defaultImage = image.arg(d->defaultWallpaperWidth).arg(d->defaultWallpaperHeight);
if (size.isValid()) {
// try to customize the paper to the size requested
//TODO: this should do better than just fallback to the default size.
// a "best fit" matching would be far better, so we don't end
// up returning a 1920x1200 wallpaper for a 640x480 request ;)
image = image.arg(size.width()).arg(size.height());
} else {
image = defaultImage;
}
//TODO: the theme's wallpaper overrides regularly installed wallpapers.
// should it be possible for user installed (e.g. locateLocal) wallpapers
// to override the theme?
if (d->hasWallpapers) {
// check in the theme first
fullPath = d->findInTheme(QLatin1Literal("wallpapers/") % image, d->themeName);
if (fullPath.isEmpty()) {
fullPath = d->findInTheme(QLatin1Literal("wallpapers/") % defaultImage, d->themeName);
}
}
if (fullPath.isEmpty()) {
// we failed to find it in the theme, so look in the standard directories
//kDebug() << "looking for" << image;
fullPath = KStandardDirs::locate("wallpaper", image);
}
if (fullPath.isEmpty()) {
// we still failed to find it in the theme, so look for the default in
// the standard directories
//kDebug() << "looking for" << defaultImage;
fullPath = KStandardDirs::locate("wallpaper", defaultImage);
if (fullPath.isEmpty()) {
#ifndef NDEBUG
kDebug() << "exhausted every effort to find a wallpaper.";
#endif
}
}
return fullPath;
}
bool Theme::currentThemeHasImage(const QString &name) const
{
if (name.contains("../")) {
// we don't support relative paths
return false;
}
return !(d->findInTheme(name % QLatin1Literal(".svgz"), d->themeName, false).isEmpty()) ||
!(d->findInTheme(name % QLatin1Literal(".svg"), d->themeName, false).isEmpty());
}
KSharedConfigPtr Theme::colorScheme() const
{
return d->colors;
}
QColor Theme::color(ColorRole role) const
{
switch (role) {
case TextColor:
return d->colorScheme.foreground(KColorScheme::NormalText).color();
case HighlightColor:
return d->colorScheme.decoration(KColorScheme::HoverColor).color();
case BackgroundColor:
return d->colorScheme.background(KColorScheme::NormalBackground).color();
case ButtonTextColor:
return d->buttonColorScheme.foreground(KColorScheme::NormalText).color();
case ButtonBackgroundColor:
return d->buttonColorScheme.background(KColorScheme::NormalBackground).color();
case ButtonHoverColor:
return d->buttonColorScheme.decoration(KColorScheme::HoverColor).color();
case ButtonFocusColor:
return d->buttonColorScheme.decoration(KColorScheme::FocusColor).color();
case ViewTextColor:
return d->viewColorScheme.foreground(KColorScheme::NormalText).color();
case ViewBackgroundColor:
return d->viewColorScheme.background(KColorScheme::NormalBackground).color();
case ViewHoverColor:
return d->viewColorScheme.decoration(KColorScheme::HoverColor).color();
case ViewFocusColor:
return d->viewColorScheme.decoration(KColorScheme::FocusColor).color();
case LinkColor:
return d->viewColorScheme.foreground(KColorScheme::LinkText).color();
case VisitedLinkColor:
return d->viewColorScheme.foreground(KColorScheme::VisitedText).color();
}
return QColor();
}
void Theme::setFont(const QFont &font, FontRole role)
{
Q_UNUSED(role)
d->generalFont = font;
}
QFont Theme::font(FontRole role) const
{
switch (role) {
case DesktopFont: {
KConfigGroup cg(KGlobal::config(), "General");
return cg.readEntry("desktopFont", d->generalFont);
}
break;
case DefaultFont:
default:
return d->generalFont;
break;
case SmallestFont:
return KGlobalSettings::smallestReadableFont();
break;
}
return d->generalFont;
}
QFontMetrics Theme::fontMetrics() const
{
//TODO: allow this to be overridden with a plasma specific font?
return QFontMetrics(d->generalFont);
}
bool Theme::windowTranslucencyEnabled() const
{
return d->compositingActive;
}
void Theme::setUseGlobalSettings(bool useGlobal)
{
if (d->useGlobal == useGlobal) {
return;
}
d->useGlobal = useGlobal;
d->cfg = KConfigGroup();
d->themeName.clear();
settingsChanged();
}
bool Theme::useGlobalSettings() const
{
return d->useGlobal;
}
bool Theme::useNativeWidgetStyle() const
{
return d->useNativeWidgetStyle;
}
bool Theme::findInCache(const QString &key, QPixmap &pix, unsigned int lastModified)
{
if (lastModified != 0 && d->useCache() && lastModified > uint(d->pixmapCache->lastModifiedTime())) {
return false;
}
if (d->useCache()) {
const QString id = d->keysToCache.value(key);
if (d->pixmapsToCache.contains(id)) {
pix = d->pixmapsToCache.value(id);
return !pix.isNull();
}
QPixmap temp;
if (d->pixmapCache->findPixmap(key, &temp) && !temp.isNull()) {
pix = temp;
return true;
}
}
return false;
}
void Theme::insertIntoCache(const QString& key, const QPixmap& pix)
{
if (d->useCache()) {
d->pixmapCache->insertPixmap(key, pix);
}
}
void Theme::insertIntoCache(const QString& key, const QPixmap& pix, const QString& id)
{
if (d->useCache()) {
d->pixmapsToCache.insert(id, pix);
if (d->idsToCache.contains(id)) {
d->keysToCache.remove(d->idsToCache[id]);
}
d->keysToCache.insert(key, id);
d->idsToCache.insert(id, key);
d->saveTimer->start();
}
}
bool Theme::findInRectsCache(const QString &image, const QString &element, QRectF &rect) const
{
if (!d->svgElementsCache) {
return false;
}
KConfigGroup imageGroup(d->svgElementsCache, image);
rect = imageGroup.readEntry(element % QLatin1Literal("Size"), QRectF());
if (rect.isValid()) {
return true;
}
//Name starting by _ means the element is empty and we're asked for the size of
//the whole image, so the whole image is never invalid
if (element.indexOf('_') <= 0) {
return false;
}
bool invalid = false;
QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
if (it == d->invalidElements.end()) {
QSet<QString> elements = imageGroup.readEntry("invalidElements", QStringList()).toSet();
d->invalidElements.insert(image, elements);
invalid = elements.contains(element);
} else {
invalid = it.value().contains(element);
}
return invalid;
}
QStringList Theme::listCachedRectKeys(const QString &image) const
{
if (!d->svgElementsCache) {
return QStringList();
}
KConfigGroup imageGroup(d->svgElementsCache, image);
QStringList keys = imageGroup.keyList();
QMutableListIterator<QString> i(keys);
while (i.hasNext()) {
QString key = i.next();
if (key.endsWith("Size")) {
// The actual cache id used from outside doesn't end on "Size".
key.resize(key.size() - 4);
i.setValue(key);
} else {
i.remove();
}
}
return keys;
}
void Theme::insertIntoRectsCache(const QString& image, const QString &element, const QRectF &rect)
{
if (!d->svgElementsCache) {
return;
}
if (rect.isValid()) {
KConfigGroup imageGroup(d->svgElementsCache, image);
imageGroup.writeEntry(element % QLatin1Literal("Size"), rect);
} else {
QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
if (it == d->invalidElements.end()) {
d->invalidElements[image].insert(element);
} else if (!it.value().contains(element)) {
if (it.value().count() > 1000) {
it.value().erase(it.value().begin());
}
it.value().insert(element);
}
}
}
void Theme::invalidateRectsCache(const QString& image)
{
if (d->svgElementsCache) {
KConfigGroup imageGroup(d->svgElementsCache, image);
imageGroup.deleteGroup();
}
d->invalidElements.remove(image);
}
void Theme::releaseRectsCache(const QString &image)
{
QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
if (it != d->invalidElements.end()) {
if (!d->svgElementsCache) {
KConfigGroup imageGroup(d->svgElementsCache, it.key());
imageGroup.writeEntry("invalidElements", it.value().toList());
}
d->invalidElements.erase(it);
}
}
void Theme::setCacheLimit(int kbytes)
{
Q_UNUSED(kbytes)
if (d->useCache()) {
;
// Too late for you bub.
// d->pixmapCache->setCacheLimit(kbytes);
}
}
KUrl Theme::homepage() const
{
const QString metadataPath(KStandardDirs::locate("data", QLatin1Literal("desktoptheme/") % d->themeName % QLatin1Literal("/metadata.desktop")));
KConfig metadata(metadataPath);
KConfigGroup brandConfig(&metadata, "Branding");
return brandConfig.readEntry("homepage", KUrl("http://www.kde.org"));
}
int Theme::toolTipDelay() const
{
return d->toolTipDelay;
}
}
-#include <theme.moc>
+#include "moc_theme.cpp"
diff --git a/plasma/tooltipmanager.cpp b/plasma/tooltipmanager.cpp
index a037b857a6..f7725e9b1a 100644
--- a/plasma/tooltipmanager.cpp
+++ b/plasma/tooltipmanager.cpp
@@ -1,498 +1,500 @@
/*
* Copyright 2007 by Dan Meltzer <hydrogen@notyetimplemented.com>
* Copyright 2008 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Alexis Mテゥnard <darktears31@gmail.com>
*
* 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 "tooltipmanager.h"
//Qt
#include <QCoreApplication>
#include <QLabel>
#include <QTimer>
#include <QGridLayout>
#include <QGraphicsView>
#include <QGraphicsSceneHoverEvent>
//KDE
#include <kwindowsystem.h>
//X11
#ifdef Q_WS_X11
#include <QX11Info>
#include <X11/Xlib.h>
#include <fixx11h.h>
#endif
//Plasma
#include "plasma/applet.h"
#include "plasma/containment.h"
#include "plasma/corona.h"
#include "plasma/framesvg.h"
#include "plasma/popupapplet.h"
#include "plasma/theme.h"
#include "plasma/view.h"
#include "plasma/private/tooltip_p.h"
namespace Plasma
{
class ToolTipManagerPrivate
{
public :
ToolTipManagerPrivate(ToolTipManager *manager)
: q(manager),
currentWidget(0),
showTimer(new QTimer(manager)),
hideTimer(new QTimer(manager)),
tipWidget(0),
state(ToolTipManager::Activated),
isShown(false),
delayedHide(false),
clickable(false)
{
}
~ToolTipManagerPrivate()
{
if (!QCoreApplication::closingDown()) {
delete tipWidget;
}
}
void showToolTip();
void resetShownState();
/**
* called when a widget inside the tooltip manager is deleted
*/
void onWidgetDestroyed(QObject * object);
void removeWidget(QGraphicsWidget *w, bool canSafelyAccess = true);
void clearTips();
void doDelayedHide();
void toolTipHovered(bool);
void createTipWidget();
void hideTipWidget();
ToolTipManager *q;
QGraphicsWidget *currentWidget;
QTimer *showTimer;
QTimer *hideTimer;
QHash<QGraphicsWidget *, ToolTipContent> tooltips;
ToolTip *tipWidget;
ToolTipManager::State state;
bool isShown : 1;
bool delayedHide : 1;
bool clickable : 1;
};
//TOOLTIP IMPLEMENTATION
class ToolTipManagerSingleton
{
public:
ToolTipManagerSingleton()
{
}
ToolTipManager self;
};
K_GLOBAL_STATIC(ToolTipManagerSingleton, privateInstance)
ToolTipManager *ToolTipManager::self()
{
return &privateInstance->self;
}
ToolTipManager::ToolTipManager(QObject *parent)
: QObject(parent),
d(new ToolTipManagerPrivate(this))
{
d->showTimer->setSingleShot(true);
connect(d->showTimer, SIGNAL(timeout()), SLOT(showToolTip()));
d->hideTimer->setSingleShot(true);
connect(d->hideTimer, SIGNAL(timeout()), SLOT(resetShownState()));
}
ToolTipManager::~ToolTipManager()
{
delete d;
}
void ToolTipManager::show(QGraphicsWidget *widget)
{
if (!d->tooltips.contains(widget)) {
return;
}
d->delayedHide = false;
d->hideTimer->stop();
d->showTimer->stop();
const int defaultDelay = Theme::defaultTheme()->toolTipDelay();
if (defaultDelay < 0) {
return;
}
ToolTipContent content = d->tooltips[widget];
qreal delay = content.isInstantPopup() ? 0.0 : defaultDelay;
d->currentWidget = widget;
if (d->isShown) {
// small delay to prevent unnecessary showing when the mouse is moving quickly across items
// which can be too much for less powerful CPUs to keep up with
d->showTimer->start(200);
} else {
d->showTimer->start(qMax(qreal(200), delay));
}
}
bool ToolTipManager::isVisible(QGraphicsWidget *widget) const
{
return d->currentWidget == widget && d->tipWidget && d->tipWidget->isVisible();
}
void ToolTipManagerPrivate::doDelayedHide()
{
showTimer->stop(); // stop the timer to show the tooltip
delayedHide = true;
if (isShown && clickable) {
// leave enough time for user to choose
hideTimer->start(1000);
} else {
hideTimer->start(250);
}
}
void ToolTipManager::hide(QGraphicsWidget *widget)
{
if (d->currentWidget != widget) {
return;
}
d->currentWidget = 0;
d->showTimer->stop(); // stop the timer to show the tooltip
d->delayedHide = false;
d->hideTipWidget();
}
void ToolTipManager::registerWidget(QGraphicsWidget *widget)
{
if (d->state == Deactivated || d->tooltips.contains(widget)) {
return;
}
//the tooltip is not registered we add it in our map of tooltips
d->tooltips.insert(widget, ToolTipContent());
widget->installEventFilter(this);
connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(onWidgetDestroyed(QObject*)));
}
void ToolTipManager::unregisterWidget(QGraphicsWidget *widget)
{
if (!d->tooltips.contains(widget)) {
return;
}
if (widget == d->currentWidget) {
d->currentWidget = 0;
d->showTimer->stop(); // stop the timer to show the tooltip
d->delayedHide = false;
d->hideTipWidget();
}
widget->removeEventFilter(this);
d->removeWidget(widget);
}
void ToolTipManager::setContent(QGraphicsWidget *widget, const ToolTipContent &data)
{
if (d->state == Deactivated || !widget) {
return;
}
registerWidget(widget);
d->tooltips.insert(widget, data);
if (d->currentWidget == widget && d->tipWidget && d->tipWidget->isVisible()) {
if (data.isEmpty()) {
// after this call, d->tipWidget will be null
hide(widget);
} else {
d->delayedHide = data.autohide();
d->clickable = data.isClickable();
if (d->delayedHide) {
//kDebug() << "starting authoide";
d->hideTimer->start(3000);
} else {
d->hideTimer->stop();
}
}
if (d->tipWidget) {
d->tipWidget->setContent(widget, data);
d->tipWidget->prepareShowing();
//look if the data prefers aother graphicswidget, otherwise use the one used as event catcher
QGraphicsWidget *referenceWidget = data.graphicsWidget() ? data.graphicsWidget() : widget;
Corona *corona = qobject_cast<Corona *>(referenceWidget->scene());
if (corona) {
d->tipWidget->moveTo(corona->popupPosition(referenceWidget, d->tipWidget->size(), Qt::AlignCenter));
}
}
}
}
void ToolTipManager::clearContent(QGraphicsWidget *widget)
{
setContent(widget, ToolTipContent());
}
void ToolTipManager::setState(ToolTipManager::State state)
{
d->state = state;
switch (state) {
case Activated:
break;
case Deactivated:
d->clearTips();
//fallthrough
case Inhibited:
d->resetShownState();
break;
}
}
ToolTipManager::State ToolTipManager::state() const
{
return d->state;
}
void ToolTipManagerPrivate::createTipWidget()
{
if (tipWidget) {
return;
}
tipWidget = new ToolTip(0);
QObject::connect(tipWidget, SIGNAL(activateWindowByWId(WId,Qt::MouseButtons,Qt::KeyboardModifiers,QPoint)),
q, SIGNAL(windowPreviewActivated(WId,Qt::MouseButtons,Qt::KeyboardModifiers,QPoint)));
QObject::connect(tipWidget, SIGNAL(linkActivated(QString,Qt::MouseButtons,Qt::KeyboardModifiers,QPoint)),
q, SIGNAL(linkActivated(QString,Qt::MouseButtons,Qt::KeyboardModifiers,QPoint)));
QObject::connect(tipWidget, SIGNAL(hovered(bool)), q, SLOT(toolTipHovered(bool)));
}
void ToolTipManagerPrivate::hideTipWidget()
{
if (tipWidget) {
tipWidget->hide();
tipWidget->deleteLater();
tipWidget = 0;
}
}
void ToolTipManagerPrivate::onWidgetDestroyed(QObject *object)
{
if (!object) {
return;
}
// we do a static_cast here since it really isn't a QGraphicsWidget 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.
//
// NOTE: DO NOT USE THE w VARIABLE FOR ANYTHING OTHER THAN COMPARING
// THE ADDRESS! ACTUALLY USING THE OBJECT WILL RESULT IN A CRASH!!!
QGraphicsWidget *w = static_cast<QGraphicsWidget*>(object);
removeWidget(w, false);
}
void ToolTipManagerPrivate::removeWidget(QGraphicsWidget *w, bool canSafelyAccess)
{
if (currentWidget == w && currentWidget) {
currentWidget = 0;
showTimer->stop(); // stop the timer to show the tooltip
hideTipWidget();
delayedHide = false;
}
if (w && canSafelyAccess) {
QObject::disconnect(q, 0, w, 0);
}
tooltips.remove(w);
}
void ToolTipManagerPrivate::clearTips()
{
tooltips.clear();
}
void ToolTipManagerPrivate::resetShownState()
{
if (!tipWidget || !tipWidget->isVisible() || delayedHide) {
//One might have moused out and back in again
showTimer->stop();
delayedHide = false;
isShown = false;
currentWidget = 0;
hideTipWidget();
}
}
void ToolTipManagerPrivate::showToolTip()
{
if (state != ToolTipManager::Activated ||
!currentWidget ||
QApplication::activePopupWidget() ||
QApplication::activeModalWidget()) {
return;
}
PopupApplet *popup = qobject_cast<PopupApplet*>(currentWidget);
if (popup && popup->isPopupShowing()) {
return;
}
if (currentWidget->metaObject()->indexOfMethod("toolTipAboutToShow()") != -1) {
// toolTipAboutToShow may call into methods such as setContent which play
// with the current widget; so let's just pretend for a moment that we don't have
// a current widget
QGraphicsWidget *temp = currentWidget;
currentWidget = 0;
QMetaObject::invokeMethod(temp, "toolTipAboutToShow");
currentWidget = temp;
}
QHash<QGraphicsWidget *, ToolTipContent>::const_iterator tooltip = tooltips.constFind(currentWidget);
if (tooltip == tooltips.constEnd() || tooltip.value().isEmpty()) {
if (isShown) {
delayedHide = true;
hideTimer->start(250);
}
return;
}
createTipWidget();
Containment *c = dynamic_cast<Containment *>(currentWidget->topLevelItem());
//kDebug() << "about to show" << (QObject*)c;
if (c) {
tipWidget->setDirection(Plasma::locationToDirection(c->location()));
}
clickable = tooltip.value().isClickable();
tipWidget->setContent(currentWidget, tooltip.value());
tipWidget->prepareShowing();
QGraphicsWidget *referenceWidget = tooltip.value().graphicsWidget() ? tooltip.value().graphicsWidget() : currentWidget;
Corona *corona = qobject_cast<Corona *>(referenceWidget->scene());
if (corona) {
tipWidget->moveTo(corona->popupPosition(referenceWidget, tipWidget->size(), Qt::AlignCenter));
}
tipWidget->show();
isShown = true; //ToolTip is visible
delayedHide = tooltip.value().autohide();
if (delayedHide) {
//kDebug() << "starting authoide";
hideTimer->start(3000);
} else {
hideTimer->stop();
}
}
void ToolTipManagerPrivate::toolTipHovered(bool hovered)
{
if (!clickable) {
return;
}
if (hovered) {
hideTimer->stop();
} else {
hideTimer->start(500);
}
}
bool ToolTipManager::eventFilter(QObject *watched, QEvent *event)
{
QGraphicsWidget * widget = dynamic_cast<QGraphicsWidget *>(watched);
if (d->state != Activated || !widget) {
return QObject::eventFilter(watched, event);
}
switch (event->type()) {
case QEvent::GraphicsSceneHoverMove:
// If the tooltip isn't visible, run through showing the tooltip again
// so that it only becomes visible after a stationary hover
if (Plasma::ToolTipManager::self()->isVisible(widget)) {
break;
}
// Don't restart the show timer on a mouse move event if there hasn't
// been an enter event or the current widget has been cleared by a click
// or wheel event.
{
QGraphicsSceneHoverEvent *me = static_cast<QGraphicsSceneHoverEvent *>(event);
//FIXME: seems that wheel events generate hovermoves as well, with 0 delta
if (!d->currentWidget || (me->pos() == me->lastPos())) {
break;
}
}
case QEvent::GraphicsSceneHoverEnter:
{
// Check that there is a tooltip to show
if (!d->tooltips.contains(widget)) {
break;
}
show(widget);
break;
}
case QEvent::GraphicsSceneHoverLeave:
if (d->currentWidget == widget) {
d->doDelayedHide();
}
break;
case QEvent::GraphicsSceneMousePress:
if (d->currentWidget == widget) {
hide(widget);
}
break;
case QEvent::GraphicsSceneWheel:
default:
break;
}
return QObject::eventFilter(watched, event);
}
} // Plasma namespace
+
+#include "moc_tooltipmanager.cpp"
diff --git a/plasma/view.cpp b/plasma/view.cpp
index 6dde8b7cea..8bedf91498 100644
--- a/plasma/view.cpp
+++ b/plasma/view.cpp
@@ -1,421 +1,423 @@
/*
* 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 "view.h"
#include <QTimer>
#include <kdebug.h>
#include <kglobal.h>
#include <kwindowsystem.h>
#include <kactioncollection.h>
#include "corona.h"
#include "containment.h"
#include "wallpaper.h"
using namespace Plasma;
namespace Plasma
{
class ViewPrivate
{
public:
ViewPrivate(View *view, int uniqueId)
: q(view),
containment(0),
viewId(0),
lastScreen(-1),
lastDesktop(-2),
drawWallpaper(true),
trackChanges(true),
init(false)
{
if (uniqueId > 0 && !viewIds.contains(uniqueId)) {
s_maxViewId = uniqueId;
viewId = uniqueId;
}
if (viewId == 0) {
// we didn't get a sane value assigned to us, so lets
// grab the next available id
viewId = ++s_maxViewId;
}
viewIds.insert(viewId);
}
~ViewPrivate()
{
}
void privateInit()
{
q->setContainment(containment);
init = true;
}
void updateSceneRect()
{
if (!containment || !trackChanges) {
return;
}
#ifndef NDEBUG
kDebug() << "!!!!!!!!!!!!!!!!! setting the scene rect to"
<< containment->sceneBoundingRect()
<< "associated screen is" << containment->screen();
#endif
emit q->sceneRectAboutToChange();
if (q->transform().isIdentity()) { //we're not zoomed out
q->setSceneRect(containment->sceneBoundingRect());
} else {
//kDebug() << "trying to show the containment nicely";
q->ensureVisible(containment->sceneBoundingRect());
//q->centerOn(containment);
}
emit q->sceneRectChanged();
}
void containmentDestroyed()
{
containment = 0;
emit q->lostContainment();
}
void containmentScreenChanged(int wasScreen, int newScreen, Plasma::Containment *containment)
{
Q_UNUSED(wasScreen)
lastScreen = newScreen;
lastDesktop = containment->desktop();
}
void initGraphicsView()
{
q->setFrameShape(QFrame::NoFrame);
q->setAttribute(Qt::WA_TranslucentBackground);
q->setAutoFillBackground(true);
q->setDragMode(QGraphicsView::NoDrag);
q->setInteractive(true);
q->setAcceptDrops(true);
q->setAlignment(Qt::AlignLeft | Qt::AlignTop);
q->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
static int s_maxViewId;
//ugly but the only reliable way to do collision detection of ids
static QSet<int> viewIds;
Plasma::View *q;
Plasma::Containment *containment;
int viewId;
int lastScreen;
int lastDesktop;
bool drawWallpaper : 1;
bool trackChanges : 1;
bool init : 1;
};
int ViewPrivate::s_maxViewId(0);
QSet<int> ViewPrivate::viewIds;
View::View(Containment *containment, QWidget *parent)
: QGraphicsView(parent),
d(new ViewPrivate(this, 0))
{
d->initGraphicsView();
if (containment) {
setScene(containment->scene());
d->containment = containment;
QTimer::singleShot(0, this, SLOT(privateInit()));
}
}
View::View(Containment *containment, int viewId, QWidget *parent)
: QGraphicsView(parent),
d(new ViewPrivate(this, viewId))
{
d->initGraphicsView();
if (containment) {
setScene(containment->scene());
d->containment = containment;
QTimer::singleShot(0, this, SLOT(privateInit()));
}
}
View::~View()
{
delete d;
// FIXME FIX a focus crash but i wasn't able to reproduce in a simple test case for Qt guys
// NB: this is also done in Corona
clearFocus();
}
void View::setScreen(int screen, int desktop)
{
if (screen < 0) {
return;
}
// handle desktop views
// -1 == All desktops
if (desktop < -1 || desktop > KWindowSystem::numberOfDesktops() - 1) {
desktop = -1;
}
d->lastScreen = screen;
d->lastDesktop = desktop;
// handle views that are working with panel containment types
if (d->containment &&
(d->containment->containmentType() == Containment::PanelContainment ||
d->containment->containmentType() == Containment::CustomPanelContainment)) {
d->containment->setScreen(screen, desktop);
return;
}
Plasma::Corona *corona = qobject_cast<Plasma::Corona*>(scene());
if (corona) {
Containment *containment = corona->containmentForScreen(screen, desktop);
if (containment) {
d->containment = 0; //so that we don't end up on the old containment's screen
setContainment(containment);
}
}
}
int View::screen() const
{
return d->lastScreen;
}
int View::desktop() const
{
if (d->containment) {
return d->containment->desktop();
}
return d->lastDesktop;
}
int View::effectiveDesktop() const
{
int desk = desktop();
return desk > -1 ? desk : KWindowSystem::currentDesktop();
}
void View::setContainment(Plasma::Containment *containment)
{
if (d->init && containment == d->containment) {
return;
}
if (d->containment) {
disconnect(d->containment, SIGNAL(destroyed(QObject*)), this, SLOT(containmentDestroyed()));
disconnect(d->containment, SIGNAL(geometryChanged()), this, SLOT(updateSceneRect()));
disconnect(d->containment, SIGNAL(screenChanged(int, int, Plasma::Containment *)), this, SLOT(containmentScreenChanged(int, int, Plasma::Containment *)));
d->containment->removeAssociatedWidget(this);
}
if (!containment) {
d->containment = 0;
return;
}
Containment *oldContainment = d->containment;
int screen = d->lastScreen;
int desktop = d->lastDesktop;
if (oldContainment && oldContainment != containment) {
screen = oldContainment->screen();
desktop = oldContainment->desktop();
}
if (scene() != containment->scene()) {
setScene(containment->scene());
}
d->containment = containment;
//add keyboard-shortcut actions
d->containment->addAssociatedWidget(this);
int otherScreen = containment->screen();
int otherDesktop = containment->desktop();
if (screen > -1) {
d->lastScreen = screen;
d->lastDesktop = desktop;
//kDebug() << "set screen from setContainment due to old containment";
if (oldContainment && oldContainment != containment) {
oldContainment->setScreen(-1, -1);
}
if (screen != containment->screen() || desktop != containment->desktop()) {
containment->setScreen(screen, desktop);
}
} else {
d->lastScreen = otherScreen;
d->lastDesktop = otherDesktop;
}
if (oldContainment && oldContainment != containment && otherScreen > -1 &&
(!containment || otherScreen != containment->screen() || otherDesktop != containment->desktop())) {
// assign the old containment the old screen/desktop
//kDebug() << "set screen from setContainment" << screen << otherScreen << desktop << otherDesktop;
oldContainment->setScreen(otherScreen, otherDesktop);
}
/*
if (oldContainment) {
#ifndef NDEBUG
kDebug() << "old" << (QObject*)oldContainment << screen << oldContainment->screen()
#endif
<< "new" << (QObject*)containment << otherScreen << containment->screen();
}
*/
d->updateSceneRect();
connect(containment, SIGNAL(destroyed(QObject*)), this, SLOT(containmentDestroyed()));
connect(containment, SIGNAL(geometryChanged()), this, SLOT(updateSceneRect()));
connect(containment, SIGNAL(screenChanged(int, int, Plasma::Containment *)), this, SLOT(containmentScreenChanged(int, int, Plasma::Containment *)));
}
Containment *View::containment() const
{
return d->containment;
}
Containment *View::swapContainment(const QString &name, const QVariantList &args)
{
return swapContainment(d->containment, name, args);
}
Containment *View::swapContainment(Plasma::Containment *existing, const QString &name, const QVariantList &args)
{
if (!existing) {
return 0;
}
Containment *old = existing;
Plasma::Corona *corona = old->corona();
Plasma::Containment *c = corona->addContainmentDelayed(name, args);
if (c) {
c->init();
KConfigGroup oldConfig = old->config();
KConfigGroup newConfig = c->config();
// ensure that the old containments configuration is up to date
old->save(oldConfig);
// Copy configuration to new containment
oldConfig.copyTo(&newConfig);
if (old == d->containment) {
// set our containment to the new one, if the the old containment was us
setContainment(c);
}
// load the configuration of the old containment into the new one
c->restore(newConfig);
c->updateConstraints(Plasma::StartupCompletedConstraint);
c->flushPendingConstraintsEvents();
emit corona->containmentAdded(c);
foreach (Applet *applet, c->applets()) {
applet->init();
// We have to flush the applet constraints manually
applet->flushPendingConstraintsEvents();
}
// destroy the old one
old->destroy(false);
// and now save the config
c->save(newConfig);
corona->requestConfigSync();
return c;
}
return old;
}
KConfigGroup View::config() const
{
KConfigGroup views(KGlobal::config(), "PlasmaViews");
return KConfigGroup(&views, QString::number(d->viewId));
}
void View::configNeedsSaving() const
{
Plasma::Corona *corona = qobject_cast<Plasma::Corona*>(scene());
if (corona) {
corona->requestConfigSync();
} else {
KGlobal::config()->sync();
}
}
int View::id() const
{
return d->viewId;
}
void View::setWallpaperEnabled(bool draw)
{
d->drawWallpaper = draw;
}
bool View::isWallpaperEnabled() const
{
return d->drawWallpaper;
}
void View::setTrackContainmentChanges(bool trackChanges)
{
d->trackChanges = trackChanges;
}
bool View::trackContainmentChanges()
{
return d->trackChanges;
}
View * View::topLevelViewAt(const QPoint & pos)
{
QWidget *w = QApplication::topLevelAt(pos);
if (w) {
Plasma::View *v = qobject_cast<Plasma::View *>(w);
return v;
} else {
return 0;
}
}
} // namespace Plasma
+
+#include "moc_view.cpp"
diff --git a/plasma/wallpaper.cpp b/plasma/wallpaper.cpp
index 769cd6a559..ba2d31609d 100644
--- a/plasma/wallpaper.cpp
+++ b/plasma/wallpaper.cpp
@@ -1,666 +1,668 @@
/*
* Copyright 2008 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Petri Damsten <damu@iki.fi>
*
* 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 "wallpaper.h"
#include "config-plasma.h"
#include <QColor>
#include <QFile>
#include <QFileInfo>
#include <QImage>
#include <QAction>
#include <QQueue>
#include <QTimer>
#include <QRunnable>
#include <QThreadPool>
#include <kdebug.h>
#include <kglobal.h>
#include <kservicetypetrader.h>
#include <kstandarddirs.h>
#ifndef PLASMA_NO_KIO
#include <kio/job.h>
#endif
#include <version.h>
#include "package.h"
#include "pluginloader.h"
#include "private/dataengineconsumer_p.h"
#include "private/packages_p.h"
#include "private/wallpaper_p.h"
namespace Plasma
{
class SaveImageThread : public QRunnable
{
QImage m_image;
QString m_filePath;
public:
SaveImageThread(const QImage &image, const QString &filePath)
{
m_image = image;
m_filePath = filePath;
}
void run()
{
m_image.save(m_filePath);
}
};
LoadImageThread::LoadImageThread(const QString &filePath)
{
m_filePath = filePath;
}
void LoadImageThread::run()
{
QImage image;
image.load(m_filePath);
emit done(image);
}
class WallpaperWithPaint : public Wallpaper
{
public:
WallpaperWithPaint(QObject *parent, const QVariantList &args)
: Wallpaper(parent, args)
{
}
virtual void paint(QPainter *painter, const QRectF &exposedRect)
{
if (d->script) {
d->script->paint(painter, exposedRect);
}
}
};
Wallpaper::Wallpaper(QObject * parentObject)
: d(new WallpaperPrivate(KService::serviceByStorageId(QString()), this))
{
setParent(parentObject);
}
Wallpaper::Wallpaper(QObject *parentObject, const QVariantList &args)
: d(new WallpaperPrivate(KService::serviceByStorageId(args.count() > 0 ?
args[0].toString() : QString()), this))
{
// now remove first item since those are managed by Wallpaper and subclasses shouldn't
// need to worry about them. yes, it violates the constness of this var, but it lets us add
// or remove items later while applets can just pretend that their args always start at 0
QVariantList &mutableArgs = const_cast<QVariantList &>(args);
if (!mutableArgs.isEmpty()) {
mutableArgs.removeFirst();
}
setParent(parentObject);
}
Wallpaper::~Wallpaper()
{
delete d;
}
void Wallpaper::addUrls(const KUrl::List &urls)
{
if (d->script) {
d->script->addUrls(urls);
}
}
KPluginInfo::List Wallpaper::listWallpaperInfo(const QString &formFactor)
{
QString constraint;
if (!formFactor.isEmpty()) {
constraint.append("[X-Plasma-FormFactors] ~~ '").append(formFactor).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Wallpaper", constraint);
return KPluginInfo::fromServices(offers);
}
KPluginInfo::List Wallpaper::listWallpaperInfoForMimetype(const QString &mimeType, const QString &formFactor)
{
QString constraint = QString("'%1' in [X-Plasma-DropMimeTypes]").arg(mimeType);
if (!formFactor.isEmpty()) {
constraint.append("[X-Plasma-FormFactors] ~~ '").append(formFactor).append("'");
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Wallpaper", constraint);
#ifndef NDEBUG
kDebug() << offers.count() << constraint;
#endif
return KPluginInfo::fromServices(offers);
}
bool Wallpaper::supportsMimetype(const QString &mimetype) const
{
return d->wallpaperDescription.isValid() &&
d->wallpaperDescription.service()->hasMimeType(mimetype);
}
Wallpaper *Wallpaper::load(const QString &wallpaperName, const QVariantList &args)
{
if (wallpaperName.isEmpty()) {
return 0;
}
QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(wallpaperName);
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Wallpaper", constraint);
if (offers.isEmpty()) {
#ifndef NDEBUG
kDebug() << "offers is empty for " << wallpaperName;
#endif
return 0;
}
KService::Ptr offer = offers.first();
QVariantList allArgs;
allArgs << offer->storageId() << args;
if (!offer->property("X-Plasma-API").toString().isEmpty()) {
#ifndef NDEBUG
kDebug() << "we have a script using the"
<< offer->property("X-Plasma-API").toString() << "API";
#endif
return new WallpaperWithPaint(0, allArgs);
}
KPluginLoader plugin(*offer);
if (!Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
return 0;
}
QString error;
Wallpaper *wallpaper = offer->createInstance<Plasma::Wallpaper>(0, allArgs, &error);
if (!wallpaper) {
#ifndef NDEBUG
kDebug() << "Couldn't load wallpaper \"" << wallpaperName << "\"! reason given: " << error;
#endif
}
return wallpaper;
}
Wallpaper *Wallpaper::load(const KPluginInfo &info, const QVariantList &args)
{
if (!info.isValid()) {
return 0;
}
return load(info.pluginName(), args);
}
QString Wallpaper::name() const
{
if (!d->wallpaperDescription.isValid()) {
return i18n("Unknown Wallpaper");
}
return d->wallpaperDescription.name();
}
QString Wallpaper::icon() const
{
if (!d->wallpaperDescription.isValid()) {
return QString();
}
return d->wallpaperDescription.icon();
}
QString Wallpaper::pluginName() const
{
if (!d->wallpaperDescription.isValid()) {
return QString();
}
return d->wallpaperDescription.pluginName();
}
KServiceAction Wallpaper::renderingMode() const
{
return d->mode;
}
QList<KServiceAction> Wallpaper::listRenderingModes() const
{
if (!d->wallpaperDescription.isValid()) {
return QList<KServiceAction>();
}
return d->wallpaperDescription.service()->actions();
}
QRectF Wallpaper::boundingRect() const
{
return d->boundingRect;
}
bool Wallpaper::isInitialized() const
{
return d->initialized;
}
void Wallpaper::setBoundingRect(const QRectF &boundingRect)
{
d->boundingRect = boundingRect;
if (d->targetSize != boundingRect.size()) {
d->targetSize = boundingRect.size();
emit renderHintsChanged();
}
}
void Wallpaper::setRenderingMode(const QString &mode)
{
if (d->mode.name() == mode) {
return;
}
d->mode = KServiceAction();
if (!mode.isEmpty()) {
QList<KServiceAction> modes = listRenderingModes();
foreach (const KServiceAction &action, modes) {
if (action.name() == mode) {
d->mode = action;
break;
}
}
}
}
void Wallpaper::restore(const KConfigGroup &config)
{
init(config);
d->initialized = true;
}
void Wallpaper::init(const KConfigGroup &config)
{
if (d->script) {
d->initScript();
d->script->initWallpaper(config);
}
}
void Wallpaper::save(KConfigGroup &config)
{
if (d->script) {
d->script->save(config);
}
}
QWidget *Wallpaper::createConfigurationInterface(QWidget *parent)
{
if (d->script) {
return d->script->createConfigurationInterface(parent);
} else {
return 0;
}
}
void Wallpaper::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (d->script) {
return d->script->mouseMoveEvent(event);
}
}
void Wallpaper::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (d->script) {
return d->script->mousePressEvent(event);
}
}
void Wallpaper::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (d->script) {
return d->script->mouseReleaseEvent(event);
}
}
void Wallpaper::wheelEvent(QGraphicsSceneWheelEvent *event)
{
if (d->script) {
return d->script->wheelEvent(event);
}
}
DataEngine *Wallpaper::dataEngine(const QString &name) const
{
return d->dataEngine(name);
}
bool Wallpaper::configurationRequired() const
{
return d->needsConfig;
}
void Wallpaper::setConfigurationRequired(bool needsConfig, const QString &reason)
{
//TODO: implement something for reason. first, we need to decide where/how
// to communicate it to the user
Q_UNUSED(reason)
if (d->needsConfig == needsConfig) {
return;
}
d->needsConfig = needsConfig;
emit configurationRequired(needsConfig);
}
bool Wallpaper::isUsingRenderingCache() const
{
return d->cacheRendering;
}
void Wallpaper::setUsingRenderingCache(bool useCache)
{
d->cacheRendering = useCache;
}
void Wallpaper::setResizeMethodHint(Wallpaper::ResizeMethod resizeMethod)
{
const ResizeMethod method = qBound(ScaledResize, resizeMethod, LastResizeMethod);
if (method != d->lastResizeMethod) {
d->lastResizeMethod = method;
emit renderHintsChanged();
}
}
Wallpaper::ResizeMethod Wallpaper::resizeMethodHint() const
{
return d->lastResizeMethod;
}
void Wallpaper::setTargetSizeHint(const QSizeF &targetSize)
{
if (targetSize != d->targetSize) {
d->targetSize = targetSize;
emit renderHintsChanged();
}
}
QSizeF Wallpaper::targetSizeHint() const
{
return d->targetSize;
}
void Wallpaper::render(const QImage &image, const QSize &size,
Wallpaper::ResizeMethod resizeMethod, const QColor &color)
{
if (image.isNull()) {
return;
}
d->renderWallpaper(QString(), image, size, resizeMethod, color);
}
void Wallpaper::render(const QString &sourceImagePath, const QSize &size,
Wallpaper::ResizeMethod resizeMethod, const QColor &color)
{
if (sourceImagePath.isEmpty() || !QFile::exists(sourceImagePath)) {
//kDebug() << "failed on:" << sourceImagePath;
return;
}
d->renderWallpaper(sourceImagePath, QImage(), size, resizeMethod, color);
}
void WallpaperPrivate::renderWallpaper(const QString &sourceImagePath, const QImage &image, const QSize &size,
Wallpaper::ResizeMethod resizeMethod, const QColor &color)
{
resizeMethod = qBound(Wallpaper::ScaledResize, resizeMethod, Wallpaper::LastResizeMethod);
if (lastResizeMethod != resizeMethod) {
lastResizeMethod = resizeMethod;
emit q->renderHintsChanged();
}
if (cacheRendering) {
QFileInfo info(sourceImagePath);
QString cache = cacheKey(sourceImagePath, size, resizeMethod, color);
if (findInCache(cache, info.lastModified().toTime_t())) {
return;
}
}
WallpaperRenderRequest request;
renderToken = request.token;
request.requester = q;
request.providedImage = image;
request.file = sourceImagePath;
request.size = size;
request.resizeMethod = resizeMethod;
request.color = color;
WallpaperRenderThread::render(request);
//kDebug() << "rendering" << sourceImagePath << ", token is" << d->renderToken;
}
WallpaperPrivate::WallpaperPrivate(KService::Ptr service, Wallpaper *wallpaper) :
q(wallpaper),
wallpaperDescription(service),
package(0),
renderToken(-1),
lastResizeMethod(Wallpaper::ScaledResize),
script(0),
cacheRendering(false),
initialized(false),
needsConfig(false),
scriptInitialized(false),
previewing(false),
needsPreviewDuringConfiguration(false)
{
if (wallpaperDescription.isValid()) {
QString api = wallpaperDescription.property("X-Plasma-API").toString();
if (!api.isEmpty()) {
const QString path = KStandardDirs::locate("data",
"plasma/wallpapers/" + wallpaperDescription.pluginName() + '/');
package = new Package(PluginLoader::self()->loadPackage("Plasma/Wallpaper", api));
package->setPath(path);
if (package->isValid()) {
script = Plasma::loadScriptEngine(api, q);
}
if (!script) {
#ifndef NDEBUG
kDebug() << "Could not create a" << api << "ScriptEngine for the"
<< wallpaperDescription.name() << "Wallpaper.";
#endif
delete package;
package = 0;
}
}
}
}
QString WallpaperPrivate::cacheKey(const QString &sourceImagePath, const QSize &size,
int resizeMethod, const QColor &color) const
{
const QString id = QString("%5_%3_%4_%1x%2")
.arg(size.width()).arg(size.height()).arg(color.name())
.arg(resizeMethod).arg(sourceImagePath);
return id;
}
QString WallpaperPrivate::cachePath(const QString &key) const
{
return KGlobal::dirs()->locateLocal("cache", "plasma-wallpapers/" + key + ".png");
}
void WallpaperPrivate::newRenderCompleted(const WallpaperRenderRequest &request, const QImage &image)
{
#ifndef NDEBUG
kDebug() << request.token << renderToken;
#endif
if (request.token != renderToken) {
//kDebug() << "render token mismatch" << token << renderToken;
return;
}
if (cacheRendering) {
q->insertIntoCache(cacheKey(request.file, request.size, request.resizeMethod, request.color), image);
}
//kDebug() << "rendering complete!";
emit q->renderCompleted(image);
}
// put all setup routines for script here. at this point we can assume that
// package exists and that we have a script engine
void WallpaperPrivate::setupScriptSupport()
{
Q_ASSERT(package);
#ifndef NDEBUG
kDebug() << "setting up script support, package is in" << package->path()
<< ", main script is" << package->filePath("mainscript");
#endif
const QString translationsPath = package->filePath("translations");
if (!translationsPath.isEmpty()) {
KGlobal::dirs()->addResourceDir("locale", translationsPath);
KGlobal::locale()->insertCatalog(wallpaperDescription.pluginName());
}
}
void WallpaperPrivate::initScript()
{
if (script && !scriptInitialized) {
setupScriptSupport();
script->init();
scriptInitialized = true;
}
}
bool WallpaperPrivate::findInCache(const QString &key, unsigned int lastModified)
{
if (cacheRendering) {
QString cache = cachePath(key);
if (QFile::exists(cache)) {
if (lastModified > 0) {
QFileInfo info(cache);
if (info.lastModified().toTime_t() < lastModified) {
return false;
}
}
LoadImageThread *loadImageT = new LoadImageThread(cache);
q->connect(loadImageT, SIGNAL(done(const QImage&)), q, SIGNAL(renderCompleted(const QImage&)));
QThreadPool::globalInstance()->start(loadImageT);
return true;
}
}
return false;
}
bool Wallpaper::findInCache(const QString &key, QImage &image, unsigned int lastModified)
{
if (d->cacheRendering) {
QString cache = d->cachePath(key);
if (QFile::exists(cache)) {
if (lastModified > 0) {
QFileInfo info(cache);
if (info.lastModified().toTime_t() < lastModified) {
return false;
}
}
image.load(cache);
return true;
}
}
return false;
}
void Wallpaper::insertIntoCache(const QString& key, const QImage &image)
{
//TODO: cache limits?
if (key.isEmpty()) {
return;
}
if (d->cacheRendering) {
if (image.isNull()) {
#ifndef PLASMA_NO_KIO
KIO::file_delete(d->cachePath(key));
#else
QFile f(d->cachePath(key));
f.remove();
#endif
} else {
QThreadPool::globalInstance()->start(new SaveImageThread(image, d->cachePath(key)));
}
}
}
QList<QAction*> Wallpaper::contextualActions() const
{
return d->contextActions;
}
void Wallpaper::setContextualActions(const QList<QAction*> &actions)
{
d->contextActions = actions;
}
bool Wallpaper::isPreviewing() const
{
return d->previewing;
}
void Wallpaper::setPreviewing(bool previewing)
{
d->previewing = previewing;
}
bool Wallpaper::needsPreviewDuringConfiguration() const
{
return d->needsPreviewDuringConfiguration;
}
void Wallpaper::setPreviewDuringConfiguration(const bool preview)
{
d->needsPreviewDuringConfiguration = preview;
}
Package Wallpaper::package() const
{
return d->package ? *d->package : Package();
}
} // Plasma namespace
-#include "moc_wallpaper_p.cpp"
+
+#include "moc_wallpaper.cpp"
+#include "private/moc_wallpaper_p.cpp"
diff --git a/plasma/widgets/busywidget.cpp b/plasma/widgets/busywidget.cpp
index 65353836d5..0358807d8c 100644
--- a/plasma/widgets/busywidget.cpp
+++ b/plasma/widgets/busywidget.cpp
@@ -1,220 +1,222 @@
/*
* 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 "busywidget.h"
//Qt
#include <QPainter>
#include <QTimer>
#include <QGraphicsSceneResizeEvent>
#include <QTextOption>
//Plasma
#include "plasma/theme.h"
#include "plasma/svg.h"
namespace Plasma
{
class BusyWidgetPrivate
{
public:
BusyWidgetPrivate()
: svg(0),
timerId(0),
rotationAngle(0),
rotation(0),
running(true)
{
}
~BusyWidgetPrivate()
{
}
void themeChanged()
{
frames.clear();
rotationAngle = svg->elementSize("hint-rotation-angle").width();
//use an angle near to rotationAngle but that it fits an integer number of times in 360
int nFrames = 360/rotationAngle;
rotationAngle = 360/nFrames;
}
Svg *svg;
QString styleSheet;
int timerId;
QHash<int, QPixmap> frames;
qreal rotationAngle;
qreal rotation;
bool running;
QString label;
};
BusyWidget::BusyWidget(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new BusyWidgetPrivate)
{
d->svg = new Plasma::Svg(this);
d->svg->setImagePath("widgets/busywidget");
d->svg->setContainsMultipleImages(true);
d->themeChanged();
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(themeChanged()));
}
BusyWidget::~BusyWidget()
{
delete d;
}
void BusyWidget::setRunning(bool running)
{
if (running && !d->timerId && isVisible()) {
d->timerId = startTimer(150);
} else if (!running && d->timerId) {
killTimer(d->timerId);
d->timerId = 0;
}
d->running = running;
}
bool BusyWidget::isRunning() const
{
return d->running;
}
void BusyWidget::setLabel(const QString &label)
{
d->label = label;
update();
}
QString BusyWidget::label() const
{
return d->label;
}
void BusyWidget::timerEvent(QTimerEvent *event)
{
if (event->timerId() != d->timerId) {
QObject::timerEvent(event);
return;
}
d->rotation += d->rotationAngle;
qreal overflow = d->rotation - 360;
if ( overflow > 0) {
d->rotation = overflow;
}
update();
}
void BusyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
int intRotation = int(d->rotation);
QRectF spinnerRect(QPoint(0, 0), QSize(qMin(size().width(), size().height()), qMin(size().width(), size().height())));
spinnerRect.moveCenter(boundingRect().center());
if (!isEnabled()) {
painter->setOpacity(painter->opacity() / 2);
}
if (!d->running && d->svg->hasElement("paused")) {
d->svg->paint(painter, spinnerRect, "paused");
} else {
if (!d->frames[intRotation]) {
QPointF translatedPos(spinnerRect.width()/2, spinnerRect.height()/2);
d->frames[intRotation] = QPixmap(spinnerRect.size().toSize());
d->frames[intRotation].fill(Qt::transparent);
QPainter buffPainter(&d->frames[intRotation]);
buffPainter.setRenderHints(QPainter::SmoothPixmapTransform);
buffPainter.translate(translatedPos);
if (d->svg->hasElement("busywidget-shadow")) {
buffPainter.save();
buffPainter.translate(1,1);
buffPainter.rotate(intRotation);
d->svg->paint(&buffPainter, QRectF(-translatedPos.toPoint(), spinnerRect.size()), "busywidget-shadow");
buffPainter.restore();
}
buffPainter.rotate(intRotation);
d->svg->paint(&buffPainter, QRectF(-translatedPos.toPoint(), spinnerRect.size()), "busywidget");
}
painter->drawPixmap(spinnerRect.topLeft().toPoint(), d->frames[intRotation]);
}
painter->setPen(Plasma::Theme::defaultTheme()->color(Theme::TextColor));
Qt::Alignment align(Qt::AlignVCenter | Qt::AlignHCenter);
painter->drawText(boundingRect(), d->label, QTextOption(align));
}
void BusyWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event)
if (d->running) {
d->timerId = startTimer(150);
}
}
void BusyWidget::hideEvent(QHideEvent *event)
{
Q_UNUSED(event)
if (d->timerId) {
killTimer(d->timerId);
}
d->timerId = 0;
}
void BusyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
{
Q_UNUSED(event)
d->frames.clear();
}
void BusyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
event->setAccepted(true);
}
void BusyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if ((event->button() & Qt::LeftButton) ||
(event->buttons() & Qt::LeftButton)) {
emit clicked();
}
}
} // namespace Plasma
-#include <busywidget.moc>
+
+
+#include "moc_busywidget.cpp"
diff --git a/plasma/widgets/checkbox.cpp b/plasma/widgets/checkbox.cpp
index e37405454d..1cc0148831 100644
--- a/plasma/widgets/checkbox.cpp
+++ b/plasma/widgets/checkbox.cpp
@@ -1,185 +1,187 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "checkbox.h"
#include <QCheckBox>
#include <QPainter>
#include <QDir>
#include <kmimetype.h>
#include "private/themedwidgetinterface_p.h"
#include "svg.h"
#include "theme.h"
namespace Plasma
{
class CheckBoxPrivate : public ThemedWidgetInterface<CheckBox>
{
public:
CheckBoxPrivate(CheckBox *c)
: ThemedWidgetInterface<CheckBox>(c),
svg(0)
{
}
~CheckBoxPrivate()
{
delete svg;
}
void setPixmap()
{
if (imagePath.isEmpty()) {
delete svg;
svg = 0;
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
QPixmap pm(q->size().toSize());
if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {
if (!svg || svg->imagePath() != imagePath) {
delete svg;
svg = new Svg();
svg->setImagePath(imagePath);
QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap()));
}
QPainter p(&pm);
svg->paint(&p, pm.rect());
} else {
delete svg;
svg = 0;
pm = QPixmap(absImagePath);
}
static_cast<QCheckBox*>(q->widget())->setIcon(QIcon(pm));
}
QString imagePath;
QString absImagePath;
Svg *svg;
};
CheckBox::CheckBox(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new CheckBoxPrivate(this))
{
QCheckBox *native = new QCheckBox;
connect(native, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
d->setWidget(native);
native->setWindowIcon(QIcon());
native->setAttribute(Qt::WA_NoSystemBackground);
d->initTheming();
}
CheckBox::~CheckBox()
{
delete d;
}
void CheckBox::setText(const QString &text)
{
static_cast<QCheckBox*>(widget())->setText(text);
}
QString CheckBox::text() const
{
return static_cast<QCheckBox*>(widget())->text();
}
void CheckBox::setImage(const QString &path)
{
if (d->imagePath == path) {
return;
}
delete d->svg;
d->svg = 0;
d->imagePath = path;
bool absolutePath = !path.isEmpty() &&
#ifdef Q_WS_WIN
!QDir::isRelativePath(path)
#else
(path[0] == '/' || path.startsWith(QLatin1String(":/")))
#endif
;
if (absolutePath) {
d->absImagePath = path;
} else {
//TODO: package support
d->absImagePath = Theme::defaultTheme()->imagePath(path);
}
d->setPixmap();
}
QString CheckBox::image() const
{
return d->imagePath;
}
void CheckBox::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString CheckBox::styleSheet()
{
return widget()->styleSheet();
}
QCheckBox *CheckBox::nativeWidget() const
{
return static_cast<QCheckBox*>(widget());
}
void CheckBox::resizeEvent(QGraphicsSceneResizeEvent *event)
{
d->setPixmap();
QGraphicsProxyWidget::resizeEvent(event);
}
void CheckBox::setChecked(bool checked)
{
static_cast<QCheckBox*>(widget())->setChecked(checked);
}
bool CheckBox::isChecked() const
{
return static_cast<QCheckBox*>(widget())->isChecked();
}
void CheckBox::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
} // namespace Plasma
-#include <checkbox.moc>
+
+
+#include "moc_checkbox.cpp"
diff --git a/plasma/widgets/combobox.cpp b/plasma/widgets/combobox.cpp
index d52eb0ab75..733ea8d0c7 100644
--- a/plasma/widgets/combobox.cpp
+++ b/plasma/widgets/combobox.cpp
@@ -1,355 +1,357 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "combobox.h"
#include <QPainter>
#include <QGraphicsView>
#include <kcombobox.h>
#include <kiconeffect.h>
#include <kiconloader.h>
#include <kmimetype.h>
#include "applet.h"
#include "framesvg.h"
#include "private/style_p.h"
#include "private/focusindicator_p.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
namespace Plasma
{
class ComboBoxPrivate : public ThemedWidgetInterface<ComboBox>
{
public:
ComboBoxPrivate(ComboBox *comboBox)
: ThemedWidgetInterface<ComboBox>(comboBox),
background(0),
underMouse(false)
{
}
~ComboBoxPrivate()
{
}
void syncActiveRect();
void syncBorders();
FrameSvg *background;
FrameSvg *lineEditBackground;
FocusIndicator *focusIndicator;
int animId;
qreal opacity;
QRectF activeRect;
Style::Ptr style;
bool underMouse;
};
void ComboBoxPrivate::syncActiveRect()
{
background->setElementPrefix("normal");
qreal left, top, right, bottom;
background->getMargins(left, top, right, bottom);
background->setElementPrefix("active");
qreal activeLeft, activeTop, activeRight, activeBottom;
background->getMargins(activeLeft, activeTop, activeRight, activeBottom);
activeRect = QRectF(QPointF(0, 0), q->size());
activeRect.adjust(left - activeLeft, top - activeTop,
-(right - activeRight), -(bottom - activeBottom));
background->setElementPrefix("normal");
}
void ComboBoxPrivate::syncBorders()
{
//set margins from the normal element
qreal left, top, right, bottom;
background->setElementPrefix("normal");
background->getMargins(left, top, right, bottom);
q->setContentsMargins(left, top, right, bottom);
//calc the rect for the over effect
syncActiveRect();
if (customFont) {
q->setFont(q->font());
} else {
q->setFont(Theme::defaultTheme()->font(Theme::DefaultFont));
customFont = false;
}
if (q->nativeWidget()->isEditable()) {
focusIndicator->setFrameSvg(lineEditBackground);
} else {
focusIndicator->setFrameSvg(background);
}
focusIndicator->setFlag(QGraphicsItem::ItemStacksBehindParent, !q->nativeWidget()->isEditable() || !lineEditBackground->hasElement("hint-focus-over-base"));
}
ComboBox::ComboBox(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new ComboBoxPrivate(this))
{
d->background = new FrameSvg(this);
d->background->setImagePath("widgets/button");
d->background->setCacheAllRenderedFrames(true);
d->background->setElementPrefix("normal");
d->lineEditBackground = new FrameSvg(this);
d->lineEditBackground->setImagePath("widgets/lineedit");
d->lineEditBackground->setCacheAllRenderedFrames(true);
setZValue(900);
setAcceptHoverEvents(true);
d->style = Style::sharedStyle();
d->focusIndicator = new FocusIndicator(this, d->background);
setNativeWidget(new KComboBox);
connect(d->background, SIGNAL(repaintNeeded()), SLOT(syncBorders()));
d->initTheming();
}
ComboBox::~ComboBox()
{
delete d;
Style::doneWithSharedStyle();
}
QString ComboBox::text() const
{
return static_cast<KComboBox*>(widget())->currentText();
}
void ComboBox::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString ComboBox::styleSheet()
{
return widget()->styleSheet();
}
void ComboBox::setNativeWidget(KComboBox *nativeWidget)
{
if (widget()) {
widget()->deleteLater();
}
connect(nativeWidget, SIGNAL(activated(const QString &)), this, SIGNAL(activated(const QString &)));
connect(nativeWidget, SIGNAL(currentIndexChanged(int)),
this, SIGNAL(currentIndexChanged(int)));
connect(nativeWidget, SIGNAL(currentIndexChanged(const QString &)),
this, SIGNAL(textChanged(const QString &)));
d->setWidget(nativeWidget);
nativeWidget->setWindowIcon(QIcon());
nativeWidget->setAttribute(Qt::WA_NoSystemBackground);
nativeWidget->setStyle(d->style.data());
d->syncBorders();
}
KComboBox *ComboBox::nativeWidget() const
{
return static_cast<KComboBox*>(widget());
}
void ComboBox::addItem(const QString &text)
{
static_cast<KComboBox*>(widget())->addItem(text);
}
void ComboBox::clear()
{
static_cast<KComboBox*>(widget())->clear();
}
void ComboBox::resizeEvent(QGraphicsSceneResizeEvent *event)
{
if (d->background) {
//resize needed panels
d->syncActiveRect();
d->background->setElementPrefix("focus");
d->background->resizeFrame(size());
d->background->setElementPrefix("active");
d->background->resizeFrame(d->activeRect.size());
d->background->setElementPrefix("normal");
d->background->resizeFrame(size());
}
QGraphicsProxyWidget::resizeEvent(event);
}
void ComboBox::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
if (!styleSheet().isNull() ||
Theme::defaultTheme()->useNativeWidgetStyle()) {
QGraphicsProxyWidget::paint(painter, option, widget);
return;
}
if (nativeWidget()->isEditable()) {
QGraphicsProxyWidget::paint(painter, option, widget);
return;
}
QPixmap bufferPixmap;
//normal button
if (isEnabled()) {
d->background->setElementPrefix("normal");
d->background->paintFrame(painter);
//disabled widget
} else {
bufferPixmap = QPixmap(rect().size().toSize());
bufferPixmap.fill(Qt::transparent);
QPainter buffPainter(&bufferPixmap);
d->background->paintFrame(&buffPainter);
buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
buffPainter.fillRect(bufferPixmap.rect(), QColor(0, 0, 0, 128));
painter->drawPixmap(0, 0, bufferPixmap);
}
painter->setPen(Theme::defaultTheme()->color(Theme::ButtonTextColor));
QStyleOptionComboBox comboOpt;
comboOpt.initFrom(nativeWidget());
comboOpt.palette.setColor(
QPalette::ButtonText, Theme::defaultTheme()->color(Theme::ButtonTextColor));
comboOpt.currentIcon = nativeWidget()->itemIcon(
nativeWidget()->currentIndex());
comboOpt.currentText = nativeWidget()->itemText(
nativeWidget()->currentIndex());
comboOpt.editable = false;
nativeWidget()->style()->drawControl(
QStyle::CE_ComboBoxLabel, &comboOpt, painter, nativeWidget());
comboOpt.rect = nativeWidget()->style()->subControlRect(
QStyle::CC_ComboBox, &comboOpt, QStyle::SC_ComboBoxArrow, nativeWidget());
nativeWidget()->style()->drawPrimitive(
QStyle::PE_IndicatorArrowDown, &comboOpt, painter, nativeWidget());
}
void ComboBox::focusInEvent(QFocusEvent *event)
{
QGraphicsProxyWidget::focusInEvent(event);
}
void ComboBox::focusOutEvent(QFocusEvent *event)
{
QGraphicsWidget *widget = parentWidget();
Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(widget);
while (!applet && widget) {
widget = widget->parentWidget();
applet = qobject_cast<Plasma::Applet *>(widget);
}
if (applet) {
applet->setStatus(Plasma::UnknownStatus);
}
if (nativeWidget()->isEditable()) {
QEvent closeEvent(QEvent::CloseSoftwareInputPanel);
if (qApp) {
if (QGraphicsView *view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
if (view->scene() && view->scene() == scene()) {
QApplication::sendEvent(view, &closeEvent);
}
}
}
}
QGraphicsProxyWidget::focusOutEvent(event);
}
void ComboBox::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
d->underMouse = true;
QGraphicsProxyWidget::hoverEnterEvent(event);
}
void ComboBox::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
d->underMouse = false;
QGraphicsProxyWidget::hoverLeaveEvent(event);
}
void ComboBox::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
void ComboBox::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget *widget = parentWidget();
Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(widget);
while (!applet && widget) {
widget = widget->parentWidget();
applet = qobject_cast<Plasma::Applet *>(widget);
}
if (applet) {
applet->setStatus(Plasma::AcceptingInputStatus);
}
QGraphicsProxyWidget::mousePressEvent(event);
}
int ComboBox::count() const
{
return nativeWidget()->count();
}
int ComboBox::currentIndex() const
{
return nativeWidget()->currentIndex();
}
void ComboBox::setCurrentIndex(int index)
{
nativeWidget()->setCurrentIndex(index);
}
} // namespace Plasma
-#include <combobox.moc>
+
+
+#include "moc_combobox.cpp"
diff --git a/plasma/widgets/declarativewidget.cpp b/plasma/widgets/declarativewidget.cpp
index 59c653d9db..9f4a8325c4 100644
--- a/plasma/widgets/declarativewidget.cpp
+++ b/plasma/widgets/declarativewidget.cpp
@@ -1,269 +1,271 @@
/*
* Copyright 2010 Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "declarativewidget.h"
#include <QtDeclarative/QDeclarativeComponent>
#include <QtDeclarative/QDeclarativeItem>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeContext>
#include <QScriptEngine>
#include <QGraphicsLinearLayout>
#include <QGraphicsScene>
#include <QTimer>
#include <kdebug.h>
#include <kdeclarative.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include "private/declarative/declarativenetworkaccessmanagerfactory_p.h"
#include "private/dataenginebindings_p.h"
namespace Plasma
{
class DeclarativeWidgetPrivate
{
public:
DeclarativeWidgetPrivate(DeclarativeWidget *parent)
: q(parent),
engine(0),
component(0),
root(0),
delay(false)
{
}
~DeclarativeWidgetPrivate()
{
}
void errorPrint();
void execute(const QString &fileName);
void finishExecute();
void scheduleExecutionEnd();
void minimumWidthChanged();
void minimumHeightChanged();
DeclarativeWidget *q;
QString qmlPath;
QDeclarativeEngine* engine;
QScriptEngine *scriptEngine;
QDeclarativeComponent* component;
QObject *root;
bool delay : 1;
};
void DeclarativeWidgetPrivate::errorPrint()
{
QString errorStr = "Error loading QML file.\n";
if(component->isError()){
QList<QDeclarativeError> errors = component->errors();
foreach (const QDeclarativeError &error, errors) {
errorStr += (error.line()>0?QString(QString::number(error.line()) + QLatin1String(": ")):QLatin1String(""))
+ error.description() + '\n';
}
}
kWarning() << component->url().toString() + '\n' + errorStr;
}
void DeclarativeWidgetPrivate::execute(const QString &fileName)
{
if (fileName.isEmpty()) {
#ifndef NDEBUG
kDebug() << "File name empty!";
#endif
return;
}
KDeclarative kdeclarative;
kdeclarative.setDeclarativeEngine(engine);
kdeclarative.initialize();
//binds things like kconfig and icons
kdeclarative.setupBindings();
component->loadUrl(fileName);
scriptEngine = kdeclarative.scriptEngine();
registerDataEngineMetaTypes(scriptEngine);
if (delay) {
QTimer::singleShot(0, q, SLOT(scheduleExecutionEnd()));
} else {
scheduleExecutionEnd();
}
}
void DeclarativeWidgetPrivate::scheduleExecutionEnd()
{
if (component->isReady() || component->isError()) {
finishExecute();
} else {
QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), q, SLOT(finishExecute()));
}
}
void DeclarativeWidgetPrivate::finishExecute()
{
if (component->isError()) {
errorPrint();
}
root = component->create();
if (!root) {
errorPrint();
}
#ifndef NDEBUG
kDebug() << "Execution of QML done!";
#endif
QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget*>(root);
QGraphicsObject *object = dynamic_cast<QGraphicsObject *>(root);
if (object) {
static_cast<QGraphicsItem *>(object)->setParentItem(q);
if (q->scene()) {
q->scene()->addItem(object);
}
}
if (widget) {
q->setPreferredSize(-1,-1);
QGraphicsLinearLayout *lay = static_cast<QGraphicsLinearLayout *>(q->layout());
if (!lay) {
lay = new QGraphicsLinearLayout(q);
lay->setContentsMargins(0, 0, 0, 0);
}
lay->addItem(widget);
} else {
q->setLayout(0);
qreal minimumWidth = 0;
qreal minimumHeight = 0;
if (object) {
minimumWidth = object->property("minimumWidth").toReal();
minimumHeight = object->property("minimumHeight").toReal();
object->setProperty("width", q->size().width());
object->setProperty("height", q->size().height());
QObject::connect(object, SIGNAL(minimumWidthChanged()), q, SLOT(minimumWidthChanged()));
QObject::connect(object, SIGNAL(minimumHeightChanged()), q, SLOT(minimumHeightChanged()));
}
if (minimumWidth > 0 && minimumHeight > 0) {
q->setMinimumSize(minimumWidth, minimumHeight);
} else {
q->setMinimumSize(-1, -1);
}
}
emit q->finished();
}
void DeclarativeWidgetPrivate::minimumWidthChanged()
{
qreal minimumWidth = root->property("minimumWidth").toReal();
q->setMinimumWidth(minimumWidth);
}
void DeclarativeWidgetPrivate::minimumHeightChanged()
{
qreal minimumHeight = root->property("minimumHeight").toReal();
q->setMinimumHeight(minimumHeight);
}
DeclarativeWidget::DeclarativeWidget(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new DeclarativeWidgetPrivate(this))
{
setFlag(QGraphicsItem::ItemHasNoContents);
d->engine = new QDeclarativeEngine(this);
d->engine->setNetworkAccessManagerFactory(new DeclarativeNetworkAccessManagerFactory);
d->component = new QDeclarativeComponent(d->engine, this);
}
DeclarativeWidget::~DeclarativeWidget()
{
QDeclarativeNetworkAccessManagerFactory *factory = d->engine->networkAccessManagerFactory();
d->engine->setNetworkAccessManagerFactory(0);
delete factory;
delete d;
}
void DeclarativeWidget::setQmlPath(const QString &path)
{
d->qmlPath = path;
d->execute(path);
}
QString DeclarativeWidget::qmlPath() const
{
return d->qmlPath;
}
void DeclarativeWidget::setInitializationDelayed(const bool delay)
{
d->delay = delay;
}
bool DeclarativeWidget::isInitializationDelayed() const
{
return d->delay;
}
QDeclarativeEngine* DeclarativeWidget::engine()
{
return d->engine;
}
QScriptEngine *DeclarativeWidget::scriptEngine() const
{
return d->scriptEngine;
}
QObject *DeclarativeWidget::rootObject() const
{
return d->root;
}
QDeclarativeComponent *DeclarativeWidget::mainComponent() const
{
return d->component;
}
void DeclarativeWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
{
QGraphicsWidget::resizeEvent(event);
if (d->root) {
d->root->setProperty("width", size().width());
d->root->setProperty("height", size().height());
}
}
} // namespace Plasma
-#include <declarativewidget.moc>
+
+
+#include "moc_declarativewidget.cpp"
diff --git a/plasma/widgets/flashinglabel.cpp b/plasma/widgets/flashinglabel.cpp
index e79f4bd936..36f1b08de4 100644
--- a/plasma/widgets/flashinglabel.cpp
+++ b/plasma/widgets/flashinglabel.cpp
@@ -1,330 +1,333 @@
/*
* Copyright 2007 by Andrテゥ Duffeck <duffeck@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 Stre
* et, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "flashinglabel.h"
#include <QtCore/QString>
#include <QtCore/QTimeLine>
#include <QtCore/QTimer>
#include <QtCore/QWeakPointer>
#include <QPainter>
#include <QPixmap>
#include <QColor>
#include <kdebug.h>
#include <plasma/animator.h>
#include <plasma/animations/animation.h>
#include <plasma/theme.h>
using namespace Plasma;
class Plasma::FlashingLabelPrivate
{
public:
enum FlashingLabelType {
Text,
Pixmap
};
enum State {
Visible,
Invisible
};
FlashingLabelPrivate(FlashingLabel *flash)
: q(flash),
defaultDuration(3000),
type(FlashingLabelPrivate::Text),
color(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor)),
state(FlashingLabelPrivate::Invisible),
autohide(false)
{
fadeOutTimer.setInterval(defaultDuration);
fadeOutTimer.setSingleShot(true);
fadeInTimer.setInterval(0);
fadeInTimer.setSingleShot(true);
QObject::connect(Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(setPalette()));
}
~FlashingLabelPrivate() { }
void renderPixmap(const QSize &size);
void setupFlash(int duration);
void elementAnimationFinished();
void setPalette();
FlashingLabel *q;
int defaultDuration;
FlashingLabelType type;
QTimer fadeInTimer;
QTimer fadeOutTimer;
QString text;
QColor color;
QFont font;
QPixmap pixmap;
QWeakPointer<Plasma::Animation> anim;
QPixmap renderedPixmap;
QTextOption textOption;
Qt::Alignment alignment;
State state;
bool autohide;
};
FlashingLabel::FlashingLabel(QGraphicsItem *parent)
: QGraphicsWidget(parent),
d(new FlashingLabelPrivate(this))
{
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
setCacheMode(NoCache);
connect(&d->fadeOutTimer, SIGNAL(timeout()), this, SLOT(fadeOut()));
connect(&d->fadeInTimer, SIGNAL(timeout()), this, SLOT(fadeIn()));
}
FlashingLabel::~FlashingLabel()
{
delete d;
}
int FlashingLabel::duration() const
{
return d->defaultDuration;
}
void FlashingLabel::setDuration(int duration)
{
if (duration < 1) {
return;
}
d->defaultDuration = duration;
}
QColor FlashingLabel::color() const
{
return d->color;
}
void FlashingLabel::setColor(const QColor &color)
{
d->color = color;
}
QFont FlashingLabel::font() const
{
return d->font;
}
void FlashingLabel::setFont(const QFont &font)
{
d->font = font;
}
void FlashingLabel::flash(const QString &text, int duration, const QTextOption &option)
{
if (text.isEmpty()) {
return;
}
//kDebug() << duration << text;
d->type = FlashingLabelPrivate::Text;
d->text = text;
d->textOption = option;
d->setupFlash(duration);
}
void FlashingLabel::flash(const QPixmap &pixmap, int duration, Qt::Alignment align)
{
if (pixmap.isNull()) {
return;
}
d->type = FlashingLabelPrivate::Pixmap;
d->pixmap = pixmap;
d->alignment = align;
d->setupFlash(duration);
}
void FlashingLabel::setAutohide(bool autohide)
{
d->autohide = autohide;
if (autohide) {
if (d->anim.data()) {
connect(d->anim.data(), SIGNAL(finished()), this, SLOT(elementAnimationFinished()));
}
} else if (d->anim.data()) {
disconnect(d->anim.data(), SIGNAL(finished()), this, SLOT(elementAnimationFinished()));
}
}
bool FlashingLabel::autohide() const
{
return d->autohide;
}
void FlashingLabel::kill()
{
d->fadeInTimer.stop();
if (d->state == FlashingLabelPrivate::Visible) {
fadeOut();
}
}
void FlashingLabel::fadeIn()
{
//kDebug();
if (d->autohide) {
show();
}
d->state = FlashingLabelPrivate::Visible;
if (!d->anim.data()) {
d->anim = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation);
Plasma::Animation *animation = d->anim.data();
animation->setProperty("startPixmap", d->renderedPixmap);
animation->setTargetWidget(this);
animation->start();
} else {
Plasma::Animation *animation = d->anim.data();
if (animation->state() == QAbstractAnimation::Running) {
animation->stop();
animation->start();
}
}
}
void FlashingLabel::fadeOut()
{
if (d->state == FlashingLabelPrivate::Invisible) {
return; // FlashingLabel was already killed - do not animate again
}
d->state = FlashingLabelPrivate::Invisible;
if (d->anim.data()) {
Plasma::Animation *animation = d->anim.data();
animation->setProperty("direction", QAbstractAnimation::Backward);
animation->start(QAbstractAnimation::DeleteWhenStopped);
} else {
d->anim = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation);
Plasma::Animation *animation = d->anim.data();
animation->setProperty("direction", QAbstractAnimation::Backward);
animation->setProperty("startPixmap", d->renderedPixmap);
animation->setTargetWidget(this);
animation->start(QAbstractAnimation::DeleteWhenStopped);
}
}
void FlashingLabel::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (d->anim.data() && d->anim.data()->state() == QAbstractAnimation::Running) {
Plasma::Animation *animation = d->anim.data();
painter->drawPixmap(0, 0, qvariant_cast<QPixmap>(animation->property("currentPixmap")));
} else if (d->state == FlashingLabelPrivate::Visible) {
painter->drawPixmap(0, 0, d->renderedPixmap);
}
}
QSizeF FlashingLabel::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
if (which == Qt::PreferredSize) {
QFontMetrics fm(d->font);
return fm.boundingRect(d->text).size();
}
return QGraphicsWidget::sizeHint(which, constraint);
}
void FlashingLabelPrivate::renderPixmap(const QSize &size)
{
if (renderedPixmap.size() != size) {
renderedPixmap = QPixmap(size);
}
renderedPixmap.fill(Qt::transparent);
QPainter painter(&renderedPixmap);
if (type == FlashingLabelPrivate::Text) {
painter.setPen(color);
painter.setFont(font);
painter.drawText(QRect(QPoint(0, 0), size), text, textOption);
} else if (type == FlashingLabelPrivate::Pixmap) {
QPoint p;
if(alignment & Qt::AlignLeft) {
p.setX(0);
} else if (alignment & Qt::AlignRight) {
p.setX(size.width() - pixmap.width());
} else {
p.setX((size.width() - pixmap.width()) / 2);
}
if (alignment & Qt::AlignTop) {
p.setY(0);
} else if (alignment & Qt::AlignRight) {
p.setY(size.height() - pixmap.height());
} else {
p.setY((size.height() - pixmap.height()) / 2);
}
painter.drawPixmap(p, pixmap);
}
painter.end();
if (anim.data()) {
Plasma::Animation *animation = anim.data();
animation->setProperty("startPixmap", renderedPixmap);
}
}
void FlashingLabelPrivate::setupFlash(int duration)
{
fadeOutTimer.stop();
fadeOutTimer.setInterval(duration > 0 ? duration : defaultDuration);
renderPixmap(q->size().toSize());
if (state != FlashingLabelPrivate::Visible) {
fadeInTimer.start();
} else {
q->update();
}
if (fadeOutTimer.interval() > 0) {
fadeOutTimer.start();
}
}
void FlashingLabelPrivate::elementAnimationFinished()
{
if (autohide && state == FlashingLabelPrivate::Invisible && anim.data()) {
q->hide();
}
}
void FlashingLabelPrivate::setPalette()
{
color = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
q->update();
}
+
+
+#include "moc_flashinglabel.cpp"
diff --git a/plasma/widgets/frame.cpp b/plasma/widgets/frame.cpp
index 7ce7178e5f..0cf51eba77 100644
--- a/plasma/widgets/frame.cpp
+++ b/plasma/widgets/frame.cpp
@@ -1,279 +1,281 @@
/*
* 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 "frame.h"
//Qt
#include <QGraphicsSceneResizeEvent>
#include <QWidget>
#include <QDir>
#include <QPainter>
//KDE
#include <kmimetype.h>
//Plasma
#include "framesvg.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
namespace Plasma
{
class FramePrivate : public ThemedWidgetInterface<Frame>
{
public:
FramePrivate(Frame *parent)
: ThemedWidgetInterface<Frame>(parent),
svg(0),
image(0),
pixmap(0)
{
}
~FramePrivate()
{
delete pixmap;
}
void syncBorders();
FrameSvg *svg;
Frame::Shadow shadow;
QString text;
QString styleSheet;
QString imagePath;
QString absImagePath;
Svg *image;
QPixmap *pixmap;
};
void FramePrivate::syncBorders()
{
//set margins from the normal element
qreal left, top, right, bottom;
svg->getMargins(left, top, right, bottom);
if (!text.isNull()) {
QFontMetricsF fm(q->font());
top += fm.height();
}
q->setContentsMargins(left, top, right, bottom);
}
Frame::Frame(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new FramePrivate(this))
{
d->svg = new Plasma::FrameSvg(this);
d->svg->setImagePath("widgets/frame");
d->svg->setElementPrefix("plain");
d->syncBorders();
connect(d->svg, SIGNAL(repaintNeeded()), SLOT(syncBorders()));
d->initTheming();
}
Frame::~Frame()
{
delete d;
}
void Frame::setFrameShadow(Shadow shadow)
{
d->shadow = shadow;
switch (d->shadow) {
case Raised:
d->svg->setElementPrefix("raised");
break;
case Sunken:
d->svg->setElementPrefix("sunken");
break;
case Plain:
default:
d->svg->setElementPrefix("plain");
break;
}
d->syncBorders();
}
Frame::Shadow Frame::frameShadow() const
{
return d->shadow;
}
void Frame::setEnabledBorders(const FrameSvg::EnabledBorders borders)
{
if (borders != d->svg->enabledBorders()) {
d->svg->setEnabledBorders(borders);
d->syncBorders();
update();
}
}
FrameSvg::EnabledBorders Frame::enabledBorders() const
{
return d->svg->enabledBorders();
}
void Frame::setText(QString text)
{
d->text = text;
d->syncBorders();
updateGeometry();
update();
}
QString Frame::text() const
{
return d->text;
}
void Frame::setImage(const QString &path)
{
if (d->imagePath == path) {
return;
}
delete d->image;
d->image = 0;
d->imagePath = path;
delete d->pixmap;
d->pixmap = 0;
bool absolutePath = !path.isEmpty() &&
#ifdef Q_WS_WIN
!QDir::isRelativePath(path)
#else
(path[0] == '/' || path.startsWith(QLatin1String(":/")))
#endif
;
if (absolutePath) {
d->absImagePath = path;
} else {
//TODO: package support
d->absImagePath = Theme::defaultTheme()->imagePath(path);
}
if (path.isEmpty()) {
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(d->absImagePath);
if (!mime->is("image/svg+xml") && !mime->is("application/x-gzip")) {
d->pixmap = new QPixmap(d->absImagePath);
} else {
d->image = new Plasma::Svg(this);
d->image->setImagePath(path);
}
}
QString Frame::image() const
{
return d->imagePath;
}
void Frame::setStyleSheet(const QString &styleSheet)
{
//TODO: implement stylesheets painting
d->styleSheet = styleSheet;
}
QString Frame::styleSheet() const
{
return d->styleSheet;
}
QWidget *Frame::nativeWidget() const
{
return 0;
}
void Frame::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
d->svg->paintFrame(painter);
if (!d->text.isNull()) {
QFontMetricsF fm(font());
QRectF textRect = d->svg->contentsRect();
textRect.setHeight(fm.height());
painter->setFont(font());
painter->setPen(Plasma::Theme::defaultTheme()->color(Theme::TextColor));
painter->drawText(textRect, Qt::AlignHCenter|Qt::AlignTop, d->text);
}
if (!d->imagePath.isNull()) {
if (d->pixmap && !d->pixmap->isNull()) {
painter->drawPixmap(contentsRect(), *d->pixmap, d->pixmap->rect());
} else if (d->image) {
d->image->paint(painter, contentsRect());
}
}
}
void Frame::resizeEvent(QGraphicsSceneResizeEvent *event)
{
d->svg->resizeFrame(event->newSize());
if (d->image) {
d->image->resize(contentsRect().size());
}
QGraphicsWidget::resizeEvent(event);
}
QSizeF Frame::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
QSizeF hint = QGraphicsWidget::sizeHint(which, constraint);
if (!d->image && !layout()) {
QFontMetricsF fm(font());
qreal left, top, right, bottom;
d->svg->getMargins(left, top, right, bottom);
hint.setHeight(fm.height() + top + bottom);
if (which == Qt::MinimumSize || which == Qt::PreferredSize) {
QRectF rect = fm.boundingRect(d->text);
hint.setWidth(rect.width() + left + right);
}
}
return hint;
}
void Frame::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsWidget::changeEvent(event);
}
} // namespace Plasma
-#include <frame.moc>
+
+
+#include "moc_frame.cpp"
diff --git a/plasma/widgets/groupbox.cpp b/plasma/widgets/groupbox.cpp
index 0abc2ca61e..d862223836 100644
--- a/plasma/widgets/groupbox.cpp
+++ b/plasma/widgets/groupbox.cpp
@@ -1,103 +1,105 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "groupbox.h"
#include <QGroupBox>
#include <QIcon>
#include <QPainter>
#include <kmimetype.h>
#include "svg.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
namespace Plasma
{
class GroupBoxPrivate : public ThemedWidgetInterface<GroupBox>
{
public:
GroupBoxPrivate(GroupBox *groupBox)
:ThemedWidgetInterface<GroupBox>(groupBox)
{
}
~GroupBoxPrivate()
{
}
};
GroupBox::GroupBox(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new GroupBoxPrivate(this))
{
QGroupBox *native = new QGroupBox;
d->setWidget(native);
native->setWindowIcon(QIcon());
native->setAttribute(Qt::WA_NoSystemBackground);
d->initTheming();
}
GroupBox::~GroupBox()
{
delete d;
}
void GroupBox::setText(const QString &text)
{
static_cast<QGroupBox*>(widget())->setTitle(text);
}
QString GroupBox::text() const
{
return static_cast<QGroupBox*>(widget())->title();
}
void GroupBox::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString GroupBox::styleSheet()
{
return widget()->styleSheet();
}
QGroupBox *GroupBox::nativeWidget() const
{
return static_cast<QGroupBox*>(widget());
}
void GroupBox::resizeEvent(QGraphicsSceneResizeEvent *event)
{
QGraphicsProxyWidget::resizeEvent(event);
}
void GroupBox::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
} // namespace Plasma
-#include <groupbox.moc>
+
+
+#include "moc_groupbox.cpp"
diff --git a/plasma/widgets/iconwidget.cpp b/plasma/widgets/iconwidget.cpp
index cb03821cfa..8f14dd327c 100644
--- a/plasma/widgets/iconwidget.cpp
+++ b/plasma/widgets/iconwidget.cpp
@@ -1,1625 +1,1627 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
* Copyright 2007 by Matt Broadstone <mbroadst@gmail.com>
* Copyright 2006-2007 Fredrik Hテカglund <fredrik@kde.org>
* Copyright 2007 by Marco Martin <notmart@gmail.com>
* Copyright 2008 by 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 "iconwidget.h"
#include "iconwidget_p.h"
#include <QAction>
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QMenu>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QTextLayout>
#include <QTimer>
#include <kcolorscheme.h>
#include <kdebug.h>
#include <kglobalsettings.h>
#include <kicon.h>
#include <kiconeffect.h>
#include <kiconloader.h>
#include <kmimetype.h>
#include <kurl.h>
#include "animator.h"
#include "animations/animation.h"
#include "paintutils.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
#include "svg.h"
/*
TODO:
Add these to a UrlIcon class
void setUrl(const KUrl& url);
KUrl url() const;
*/
namespace Plasma
{
IconHoverAnimation::IconHoverAnimation(QObject *parent)
: QObject(parent), m_value(0), m_fadeIn(false)
{
}
qreal IconHoverAnimation::value() const
{
return m_value;
}
bool IconHoverAnimation::fadeIn() const
{
return m_fadeIn;
}
QPropertyAnimation *IconHoverAnimation::animation() const
{
return m_animation.data();
}
void IconHoverAnimation::setValue(qreal value)
{
m_value = value;
QGraphicsWidget *item = static_cast<QGraphicsWidget*>(parent());
item->update();
}
void IconHoverAnimation::setFadeIn(bool fadeIn)
{
m_fadeIn = fadeIn;
}
void IconHoverAnimation::setAnimation(QPropertyAnimation *animation)
{
m_animation = animation;
}
IconWidgetPrivate::IconWidgetPrivate(IconWidget *i)
: ActionWidgetInterface<IconWidget>(i),
iconSvg(0),
hoverAnimation(new IconHoverAnimation(q)),
iconSize(48, 48),
preferredIconSize(-1, -1),
minimumIconSize(-1, -1),
maximumIconSize(-1, -1),
states(IconWidgetPrivate::NoState),
orientation(Qt::Vertical),
numDisplayLines(2),
activeMargins(0),
iconSvgElementChanged(false),
invertLayout(false),
drawBg(false),
textBgCustomized(false)
{
}
IconWidgetPrivate::~IconWidgetPrivate()
{
qDeleteAll(cornerActions);
delete hoverAnimation;
}
void IconWidgetPrivate::readColors()
{
textColor = Plasma::Theme::defaultTheme()->color(Theme::TextColor);
if (qGray(textColor.rgb()) > 192) {
shadowColor = Qt::black;
} else {
shadowColor = Qt::white;
}
if (!textBgCustomized) {
textBgColor = QColor();
}
}
void IconWidgetPrivate::colorConfigChanged()
{
readColors();
if (drawBg) {
qreal left, top, right, bottom;
background->getMargins(left, top, right, bottom);
setVerticalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
setHorizontalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
}
q->update();
}
void IconWidgetPrivate::iconConfigChanged()
{
if (!icon.isNull()) {
q->update();
}
}
IconAction::IconAction(IconWidget *icon, QAction *action)
: m_icon(icon),
m_action(action),
m_hovered(false),
m_pressed(false),
m_selected(false),
m_visible(false)
{
}
void IconAction::show()
{
rebuildPixmap();
m_visible = true;
/*
FIXME: place this animation back when the icon widget is in the qgv library
Animation *animation = m_animation.data();
if (!animation) {
animation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation, m_icon);
animation->setTargetWidget(m_icon);
m_animation = animation;
} else if (animation->state() == QAbstractAnimation::Running) {
animation->pause();
}
animation->setProperty("targetPixmap", m_pixmap);
animation->setDirection(QAbstractAnimation::Forward);
animation->start();
*/
}
void IconAction::hide()
{
if (!m_animation) {
return;
}
Animation *animation = m_animation.data();
if (animation->state() == QAbstractAnimation::Running) {
animation->pause();
}
m_visible = false;
animation->setDirection(QAbstractAnimation::Backward);
animation->start(QAbstractAnimation::DeleteWhenStopped);
}
bool IconAction::isVisible() const
{
return m_visible;
}
bool IconAction::isAnimating() const
{
return !m_animation.isNull();
}
bool IconAction::isPressed() const
{
return m_pressed;
}
bool IconAction::isHovered() const
{
return m_hovered;
}
void IconAction::setSelected(bool selected)
{
m_selected = selected;
}
bool IconAction::isSelected() const
{
return m_selected;
}
void IconAction::setRect(const QRectF &rect)
{
m_rect = rect;
}
QRectF IconAction::rect() const
{
return m_rect;
}
void IconAction::rebuildPixmap()
{
// Determine proper QIcon mode based on selection status
QIcon::Mode mode = m_selected ? QIcon::Selected : QIcon::Normal;
// Draw everything
m_pixmap = QPixmap(26, 26);
m_pixmap.fill(Qt::transparent);
int element = IconWidgetPrivate::Minibutton;
if (m_pressed) {
element = IconWidgetPrivate::MinibuttonPressed;
} else if (m_hovered) {
element = IconWidgetPrivate::MinibuttonHover;
}
QPainter painter(&m_pixmap);
m_icon->drawActionButtonBase(&painter, m_pixmap.size(), element);
m_action->icon().paint(&painter, 2, 2, 22, 22, Qt::AlignCenter, mode);
}
bool IconAction::event(QEvent::Type type, const QPointF &pos)
{
if (!m_action->isVisible() || !m_action->isEnabled()) {
return false;
}
if (m_icon->size().width() < m_rect.width() * 2.0 ||
m_icon->size().height() < m_rect.height() * 2.0) {
return false;
}
switch (type) {
case QEvent::GraphicsSceneMousePress:
{
setSelected(m_rect.contains(pos));
return isSelected();
}
break;
case QEvent::GraphicsSceneMouseMove:
{
bool wasSelected = isSelected();
bool active = m_rect.contains(pos);
setSelected(wasSelected && active);
return (wasSelected != isSelected()) || active;
}
break;
case QEvent::GraphicsSceneMouseRelease:
{
// kDebug() << "IconAction::event got a QEvent::MouseButtonRelease, " << isSelected();
bool wasSelected = isSelected();
setSelected(false);
if (wasSelected) {
m_action->trigger();
}
return wasSelected;
}
break;
case QEvent::GraphicsSceneHoverEnter:
m_pressed = false;
m_hovered = true;
break;
case QEvent::GraphicsSceneHoverLeave:
m_pressed = false;
m_hovered = false;
break;
default:
break;
}
return false;
}
QAction *IconAction::action() const
{
return m_action;
}
void IconAction::paint(QPainter *painter) const
{
if (!m_action->isVisible() || !m_action->isEnabled()) {
return;
}
if (m_icon->size().width() < m_rect.width() * 2.0 ||
m_icon->size().height() < m_rect.height() * 2.0) {
return;
}
Animation *animation = m_animation.data();
if (m_visible && !animation) {
painter->drawPixmap(m_rect.toRect(), m_pixmap);
} else if (animation) {
painter->drawPixmap(m_rect.toRect(),
animation->property("currentPixmap").value<QPixmap>());
}
}
IconWidget::IconWidget(QGraphicsItem *parent)
: QGraphicsWidget(parent),
d(new IconWidgetPrivate(this))
{
d->init();
}
IconWidget::IconWidget(const QString &text, QGraphicsItem *parent)
: QGraphicsWidget(parent),
d(new IconWidgetPrivate(this))
{
d->init();
setText(text);
}
IconWidget::IconWidget(const QIcon &icon, const QString &text, QGraphicsItem *parent)
: QGraphicsWidget(parent),
d(new IconWidgetPrivate(this))
{
d->init();
setText(text);
setIcon(icon);
}
IconWidget::~IconWidget()
{
delete d;
}
void IconWidgetPrivate::init()
{
readColors();
iconChangeTimer = new QTimer(q);
iconChangeTimer->setSingleShot(true);
QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(colorConfigChanged()));
QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorConfigChanged()));
QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconConfigChanged()));
// setAcceptedMouseButtons(Qt::LeftButton);
q->setAcceptsHoverEvents(true);
q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
background = new Plasma::FrameSvg(q);
background->setImagePath("widgets/viewitem");
background->setCacheAllRenderedFrames(true);
background->setElementPrefix("hover");
// Margins for horizontal mode (list views, tree views, table views)
setHorizontalMargin(IconWidgetPrivate::TextMargin, 1, 1);
setHorizontalMargin(IconWidgetPrivate::IconMargin, 1, 1);
setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
// Margins for vertical mode (icon views)
setVerticalMargin(IconWidgetPrivate::TextMargin, 6, 2);
setVerticalMargin(IconWidgetPrivate::IconMargin, 1, 1);
setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
setActiveMargins();
currentSize = QSizeF(-1, -1);
initTheming();
}
void IconWidget::addIconAction(QAction *action)
{
int count = d->cornerActions.count();
if (count >= IconWidgetPrivate::LastIconPosition) {
#ifndef NDEBUG
kDebug() << "no more room for more actions!";
#endif
// just overlap it with the last item for now. ugly, but there you go.
}
IconAction *iconAction = new IconAction(this, action);
d->cornerActions.append(iconAction);
connect(action, SIGNAL(destroyed(QObject*)), this, SLOT(actionDestroyed(QObject*)));
iconAction->setRect(d->actionRect(qMin((IconWidgetPrivate::ActionPosition)count, IconWidgetPrivate::LastIconPosition)));
}
void IconWidget::removeIconAction(QAction *action)
{
//WARNING: do NOT access the action pointer passed in, as it may already be
//be destroyed. see IconWidgetPrivate::actionDestroyed(QObject*)
int count = 0;
bool found = false;
foreach (IconAction *iconAction, d->cornerActions) {
if (found) {
iconAction->setRect(d->actionRect((IconWidgetPrivate::ActionPosition)count));
} else if (!action || iconAction->action() == action) {
delete iconAction;
d->cornerActions.removeAll(iconAction);
}
if (count < IconWidgetPrivate::LastIconPosition) {
++count;
}
}
// redraw since an action has been deleted.
update();
}
void IconWidgetPrivate::actionDestroyed(QObject *action)
{
q->removeIconAction(static_cast<QAction*>(action));
}
void IconWidget::setAction(QAction *action)
{
d->setAction(action);
}
QAction *IconWidget::action() const
{
return d->action;
}
int IconWidget::numDisplayLines()
{
return d->numDisplayLines;
}
void IconWidget::setNumDisplayLines(int numLines)
{
if (numLines > d->maxDisplayLines) {
d->numDisplayLines = d->maxDisplayLines;
} else {
d->numDisplayLines = numLines;
}
}
void IconWidget::setDrawBackground(bool draw)
{
if (d->drawBg != draw) {
d->drawBg = draw;
QStyle *style = QApplication::style();
int focusHMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameHMargin) : 1;
int focusVMargin = draw ? style->pixelMetric(QStyle::PM_FocusFrameVMargin) : 1;
d->setHorizontalMargin(IconWidgetPrivate::TextMargin, focusHMargin, focusVMargin);
d->setHorizontalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin);
d->setVerticalMargin(IconWidgetPrivate::IconMargin, focusHMargin, focusVMargin);
d->currentSize = QSizeF(-1, -1);
if (draw) {
qreal left, top, right, bottom;
d->background->getMargins(left, top, right, bottom);
d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
d->setVerticalMargin(IconWidgetPrivate::ItemMargin, left, top, right, bottom);
} else {
d->setHorizontalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
d->setVerticalMargin(IconWidgetPrivate::ItemMargin, 0, 0);
}
update();
updateGeometry();
}
}
bool IconWidget::drawBackground() const
{
return d->drawBg;
}
QPainterPath IconWidget::shape() const
{
if (!d->drawBg || d->currentSize.width() < 1) {
return QGraphicsItem::shape();
}
return PaintUtils::roundedRectangle(
QRectF(QPointF(0.0, 0.0), d->currentSize).adjusted(-2, -2, 2, 2), 10.0);
}
QSizeF IconWidgetPrivate::displaySizeHint(const QStyleOptionGraphicsItem *option, const qreal width) const
{
if (text.isEmpty() && infoText.isEmpty()) {
return QSizeF(.0, .0);
}
QString label = text;
// const qreal maxWidth = (orientation == Qt::Vertical) ? iconSize.width() + 10 : 32757;
// NOTE: find a way to use the other layoutText, it currently returns nominal width, when
// we actually need the actual width.
qreal textWidth = width -
horizontalMargin[IconWidgetPrivate::TextMargin].left -
horizontalMargin[IconWidgetPrivate::TextMargin].right;
//allow only five lines of text
const qreal maxHeight =
numDisplayLines * QFontMetrics(q->font()).lineSpacing();
// To compute the nominal size for the label + info, we'll just append
// the information string to the label
if (!infoText.isEmpty()) {
label += QString(QChar::LineSeparator) + infoText;
}
QTextLayout layout;
setLayoutOptions(layout, option, q->orientation());
layout.setFont(q->font());
QSizeF size = layoutText(layout, label, QSizeF(textWidth, maxHeight));
return addMargin(size, TextMargin);
}
void IconWidgetPrivate::layoutIcons(const QStyleOptionGraphicsItem *option)
{
if (option->rect.size() == currentSize) {
return;
}
currentSize = option->rect.size();
iconSize = iconSizeForWidgetSize(option, currentSize);
int count = 0;
foreach (IconAction *iconAction, cornerActions) {
iconAction->setRect(actionRect((IconWidgetPrivate::ActionPosition)count));
++count;
}
}
QSizeF IconWidgetPrivate::iconSizeForWidgetSize(const QStyleOptionGraphicsItem *option, const QSizeF &rect)
{
setActiveMargins();
//calculate icon size based on the available space
qreal iconWidth;
if (orientation == Qt::Vertical) {
qreal heightAvail;
//if there is text resize the icon in order to make room for the text
if (text.isEmpty() && infoText.isEmpty()) {
heightAvail = rect.height();
} else {
heightAvail = rect.height() -
displaySizeHint(option, rect.width()).height() -
verticalMargin[IconWidgetPrivate::TextMargin].top -
verticalMargin[IconWidgetPrivate::TextMargin].bottom;
//never make a label higher than half the total height
heightAvail = qMax(heightAvail, rect.height() / 2);
}
//aspect ratio very "tall"
if (!text.isEmpty() || !infoText.isEmpty()) {
if (rect.width() < heightAvail) {
iconWidth = rect.width() -
verticalMargin[IconWidgetPrivate::IconMargin].left -
verticalMargin[IconWidgetPrivate::IconMargin].right;
} else {
iconWidth = heightAvail -
verticalMargin[IconWidgetPrivate::IconMargin].top -
verticalMargin[IconWidgetPrivate::IconMargin].bottom;
}
} else {
iconWidth = qMin(heightAvail, rect.width());
}
iconWidth -= verticalMargin[IconWidgetPrivate::ItemMargin].left + verticalMargin[IconWidgetPrivate::ItemMargin].right;
} else {
//Horizontal layout
//if there is text resize the icon in order to make room for the text
if (text.isEmpty() && infoText.isEmpty()) {
// with no text, we just take up the whole geometry
iconWidth = qMin(rect.height(), rect.width());
} else {
iconWidth = rect.height() -
horizontalMargin[IconWidgetPrivate::IconMargin].top -
horizontalMargin[IconWidgetPrivate::IconMargin].bottom;
}
iconWidth -= horizontalMargin[IconWidgetPrivate::ItemMargin].top + horizontalMargin[IconWidgetPrivate::ItemMargin].bottom;
}
QSizeF iconRect(iconWidth, iconWidth);
if (maximumIconSize.isValid()) {
iconRect = iconRect.boundedTo(maximumIconSize);
}
return iconRect;
}
void IconWidget::setSvg(const QString &svgFilePath, const QString &elementId)
{
if (svgFilePath.isEmpty()) {
if (d->iconSvg) {
d->iconSvg->deleteLater();
d->iconSvg = 0;
}
return;
}
if (!d->iconSvg) {
d->iconSvg = new Plasma::Svg(this);
connect(d->iconSvg, SIGNAL(repaintNeeded()), this, SLOT(svgChanged()));
d->oldIcon = d->icon;
} else {
d->oldIcon = d->iconSvg->pixmap(d->iconSvgElement);
}
d->iconSvg->setImagePath(svgFilePath);
d->iconSvg->setContainsMultipleImages(!elementId.isNull());
d->iconSvgElement = elementId;
d->iconSvgElementChanged = true;
updateGeometry();
if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && !d->oldIcon.isNull()) {
d->animateMainIcon(true, d->states);
} else {
d->oldIcon = QIcon();
update();
}
d->iconChangeTimer->start(300);
d->icon = QIcon();
}
QString IconWidget::svg() const
{
if (d->iconSvg) {
if (d->iconSvg->isValid() && (d->iconSvgElement.isEmpty() || d->iconSvg->hasElement(d->iconSvgElement))) {
return d->iconSvg->imagePath();
} else {
return QString();
}
}
return QString();
}
QSizeF IconWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
if (which == Qt::PreferredSize) {
int iconSize;
if (d->preferredIconSize.isValid()) {
iconSize = qMax(d->preferredIconSize.height(), d->preferredIconSize.width());
} else if (d->iconSvg) {
QSizeF oldSize = d->iconSvg->size();
d->iconSvg->resize();
if (d->iconSvgElement.isNull()) {
iconSize = qMax(d->iconSvg->size().width(), d->iconSvg->size().height());
} else {
iconSize = qMax(d->iconSvg->elementSize(d->iconSvgElement).width(), d->iconSvg->elementSize(d->iconSvgElement).height());
}
d->iconSvg->resize(oldSize);
} else {
iconSize = KIconLoader::SizeMedium;
}
if (constraint.width() > 0 || constraint.height() > 0) {
QSizeF constrainedWidgetSize(constraint);
QSizeF maximumWidgetSize;
if (d->maximumIconSize.isValid()) {
maximumWidgetSize =
sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width()));
} else {
maximumWidgetSize =
QGraphicsWidget::sizeHint(Qt::MaximumSize);
}
if (constrainedWidgetSize.width() <= 0) {
constrainedWidgetSize.setWidth(maximumWidgetSize.width());
}
if (constrainedWidgetSize.height() <= 0) {
constrainedWidgetSize.setHeight(maximumWidgetSize.height());
}
QStyleOptionGraphicsItem option;
QSizeF iconRect =
d->iconSizeForWidgetSize(&option, constrainedWidgetSize);
iconSize =
qMin(iconSize, qMax<int>(iconRect.width(), iconRect.height()));
}
return sizeFromIconSize(iconSize);
} else if (which == Qt::MinimumSize) {
if (d->minimumIconSize.isValid()) {
return sizeFromIconSize(qMax(d->minimumIconSize.height(), d->minimumIconSize.width()));
}
return sizeFromIconSize(KIconLoader::SizeSmall);
} else {
if (d->maximumIconSize.isValid()) {
return sizeFromIconSize(qMax(d->maximumIconSize.height(), d->maximumIconSize.width()));
}
return QGraphicsWidget::sizeHint(which, constraint);
}
}
void IconWidgetPrivate::animateMainIcon(bool show, const IconWidgetStates state)
{
if (show) {
states = state;
}
hoverAnimation->setFadeIn(show);
QPropertyAnimation *animation = hoverAnimation->animation();
if (!animation) {
animation = new QPropertyAnimation(hoverAnimation, "value");
animation->setDuration(150);
animation->setEasingCurve(QEasingCurve::OutQuad);
animation->setStartValue(0.0);
animation->setEndValue(1.0);
hoverAnimation->setAnimation(animation);
q->connect(animation, SIGNAL(finished()), q, SLOT(hoverAnimationFinished()));
} else if (animation->state() == QAbstractAnimation::Running) {
animation->pause();
}
animation->setDirection(show ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
animation->start(show ? QAbstractAnimation::KeepWhenStopped : QAbstractAnimation::DeleteWhenStopped);
q->update();
}
void IconWidgetPrivate::hoverAnimationFinished()
{
if (!hoverAnimation->fadeIn()) {
states &= ~IconWidgetPrivate::HoverState;
}
}
void IconWidgetPrivate::drawBackground(QPainter *painter, IconWidgetState state)
{
if (!drawBg) {
return;
}
if (!(states & IconWidgetPrivate::HoverState) && !(states & IconWidgetPrivate::PressedState)) {
return;
}
if (state == IconWidgetPrivate::PressedState) {
background->setElementPrefix("selected");
} else {
background->setElementPrefix("hover");
}
if (qFuzzyCompare(hoverAnimation->value(), 1)) {
background->resizeFrame(currentSize);
background->paintFrame(painter);
} else if (!qFuzzyCompare(hoverAnimation->value()+1, 1)) {
background->resizeFrame(currentSize);
QPixmap frame = background->framePixmap();
QPainter bufferPainter(&frame);
bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
bufferPainter.fillRect(frame.rect(), QColor(0,0,0, 255*hoverAnimation->value()));
bufferPainter.end();
painter->drawPixmap(QPoint(0,0), frame);
}
}
QPixmap IconWidgetPrivate::decoration(const QStyleOptionGraphicsItem *option, bool useHoverEffect, bool usePressedEffect)
{
QPixmap result;
QIcon::Mode mode = option->state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled;
QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
if (iconSvg) {
if (iconSvgElementChanged || iconSvgPixmap.size() != iconSize.toSize()) {
iconSvg->resize(iconSize);
iconSvgPixmap = iconSvg->pixmap(iconSvgElement);
iconSvgElementChanged = false;
}
result = iconSvgPixmap;
} else {
const QSize size = icon.actualSize(iconSize.toSize(), mode, state);
result = icon.pixmap(size, mode, state);
}
if (usePressedEffect) {
result = result.scaled(result.size() * 0.9, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
if (!result.isNull() && useHoverEffect) {
KIconEffect *effect = KIconLoader::global()->iconEffect();
// Note that in KIconLoader terminology, active = hover.
// We're assuming that the icon group is desktop/filemanager, since this
// is KFileItemDelegate.
if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
} else {
result = PaintUtils::transition(
result,
effect->apply(result, KIconLoader::Desktop,
KIconLoader::ActiveState), hoverAnimation->value());
}
}
} else if (!result.isNull() && !oldIcon.isNull()) {
if (qFuzzyCompare(qreal(1.0), hoverAnimation->value())) {
oldIcon = QIcon();
} else {
result = PaintUtils::transition(
oldIcon.pixmap(result.size(), mode, state),
result, hoverAnimation->value());
}
}
return result;
}
QPointF IconWidgetPrivate::iconPosition(const QStyleOptionGraphicsItem *option,
const QPixmap &pixmap) const
{
const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
// Compute the nominal decoration rectangle
const QSizeF size = addMargin(iconSize, IconWidgetPrivate::IconMargin);
Qt::LayoutDirection direction = iconDirection(option);
//alignment depends from orientation and option->direction
Qt::Alignment alignment;
if (text.isEmpty() && infoText.isEmpty()) {
alignment = Qt::AlignCenter;
} else if (orientation == Qt::Vertical) {
alignment = Qt::Alignment(Qt::AlignHCenter | Qt::AlignTop);
//Horizontal
} else {
alignment = QStyle::visualAlignment(
direction, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter));
}
const QRect iconRect =
QStyle::alignedRect(direction, alignment, size.toSize(), itemRect.toRect());
// Position the pixmap in the center of the rectangle
QRect pixmapRect = pixmap.rect();
pixmapRect.moveCenter(iconRect.center());
// add a gimmicky margin of 5px to y, TEMP TEMP TEMP
// pixmapRect = pixmapRect.adjusted(0, 5, 0, 0);
return QPointF(pixmapRect.topLeft());
}
QRectF IconWidgetPrivate::labelRectangle(const QStyleOptionGraphicsItem *option,
const QPixmap &icon,
const QString &string) const
{
Q_UNUSED(string)
if (icon.isNull()) {
return option->rect;
}
const QSizeF decoSize = addMargin(iconSize, IconWidgetPrivate::IconMargin);
const QRectF itemRect = subtractMargin(option->rect, IconWidgetPrivate::ItemMargin);
QRectF textArea(QPointF(0, 0), itemRect.size());
if (orientation == Qt::Vertical) {
textArea.setTop(decoSize.height() + 1);
} else {
//Horizontal
textArea.setLeft(decoSize.width() + 1);
}
textArea.translate(itemRect.topLeft());
return QRectF(QStyle::visualRect(iconDirection(option), option->rect, textArea.toRect()));
}
// Lays the text out in a rectangle no larger than constraints, eliding it as necessary
QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout,
const QString &text,
const QSizeF &constraints) const
{
const QSizeF size = layoutText(layout, text, constraints.width());
if (size.width() > constraints.width() || size.height() > constraints.height()) {
if (action) {
q->setToolTip(action->toolTip());
}
const QString elided = elidedText(layout, constraints);
return layoutText(layout, elided, constraints.width());
}
q->setToolTip(QString());
return size;
}
// Lays the text out in a rectangle no wider than maxWidth
QSizeF IconWidgetPrivate::layoutText(QTextLayout &layout, const QString &text, qreal maxWidth) const
{
QFontMetricsF metrics(layout.font());
qreal leading = metrics.leading();
qreal height = 0.0;
qreal widthUsed = 0.0;
QTextLine line;
layout.setText(text);
layout.beginLayout();
while ((line = layout.createLine()).isValid()) {
line.setLineWidth(maxWidth);
height += leading;
line.setPosition(QPointF(0.0, height));
height += line.height();
widthUsed = qMax(widthUsed, line.naturalTextWidth());
}
layout.endLayout();
return QSizeF(widthUsed, height);
}
// Elides the text in the layout, by iterating over each line in the layout, eliding
// or word breaking the line if it's wider than the max width, and finally adding an
// ellipses at the end of the last line, if there are more lines than will fit within
// the vertical size constraints.
QString IconWidgetPrivate::elidedText(QTextLayout &layout, const QSizeF &size) const
{
QFontMetricsF metrics(layout.font());
const QString text = layout.text();
qreal maxWidth = size.width();
qreal maxHeight = size.height();
qreal height = 0;
// Elide each line that has already been laid out in the layout.
QString elided;
elided.reserve(text.length());
for (int i = 0; i < layout.lineCount(); i++) {
QTextLine line = layout.lineAt(i);
int start = line.textStart();
int length = line.textLength();
height += metrics.leading();
if (height + line.height() + metrics.lineSpacing() > maxHeight) {
// Unfortunately, if the line ends because of a line separator,
// elidedText() will be too clever and keep adding lines until
// it finds one that's too wide.
if (line.naturalTextWidth() < maxWidth &&
start + length > 0 &&
text[start + length - 1] == QChar::LineSeparator) {
elided += text.mid(start, length - 1);
} else {
elided += metrics.elidedText(text.mid(start), Qt::ElideRight, maxWidth);
}
break;
} else if (line.naturalTextWidth() > maxWidth) {
elided += metrics.elidedText(text.mid(start, length), Qt::ElideRight, maxWidth);
} else {
elided += text.mid(start, length);
}
height += line.height();
}
return elided;
}
void IconWidgetPrivate::layoutTextItems(const QStyleOptionGraphicsItem *option,
const QPixmap &icon, QTextLayout *labelLayout,
QTextLayout *infoLayout, QRectF *textBoundingRect) const
{
bool showInformation = false;
setLayoutOptions(*labelLayout, option, q->orientation());
QFontMetricsF fm(labelLayout->font());
const QRectF textArea = labelRectangle(option, icon, text);
QRectF textRect = subtractMargin(textArea, IconWidgetPrivate::TextMargin);
//kDebug() << this << "text area" << textArea << "text rect" << textRect;
// Sizes and constraints for the different text parts
QSizeF maxLabelSize = textRect.size();
QSizeF maxInfoSize = textRect.size();
QSizeF labelSize;
QSizeF infoSize;
// If we have additional info text, and there's space for at least two lines of text,
// adjust the max label size to make room for at least one line of the info text
if (!infoText.isEmpty() && textRect.height() >= fm.lineSpacing() * 2) {
infoLayout->setFont(labelLayout->font());
infoLayout->setTextOption(labelLayout->textOption());
maxLabelSize.rheight() -= fm.lineSpacing();
showInformation = true;
}
// Lay out the label text, and adjust the max info size based on the label size
labelSize = layoutText(*labelLayout, text, maxLabelSize);
maxInfoSize.rheight() -= labelSize.height();
// Lay out the info text
if (showInformation) {
infoSize = layoutText(*infoLayout, infoText, maxInfoSize);
} else {
infoSize = QSizeF(0, 0);
}
// Compute the bounding rect of the text
const Qt::Alignment alignment = labelLayout->textOption().alignment();
const QSizeF size(qMax(labelSize.width(), infoSize.width()),
labelSize.height() + infoSize.height());
*textBoundingRect =
QStyle::alignedRect(iconDirection(option), alignment, size.toSize(), textRect.toRect());
// Compute the positions where we should draw the layouts
haloRects.clear();
labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
QTextLine line;
for (int i = 0; i < labelLayout->lineCount(); ++i) {
line = labelLayout->lineAt(i);
haloRects.append(line.naturalTextRect().translated(labelLayout->position().toPoint()).toRect());
}
infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height()));
for (int i = 0; i < infoLayout->lineCount(); ++i) {
line = infoLayout->lineAt(i);
haloRects.append(line.naturalTextRect().translated(infoLayout->position().toPoint()).toRect());
}
//kDebug() << "final position is" << labelLayout->position();
}
QBrush IconWidgetPrivate::foregroundBrush(const QStyleOptionGraphicsItem *option) const
{
const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
QPalette::Normal : QPalette::Disabled;
// Always use the highlight color for selected items
if (option->state & QStyle::State_Selected) {
return option->palette.brush(group, QPalette::HighlightedText);
}
return option->palette.brush(group, QPalette::Text);
}
QBrush IconWidgetPrivate::backgroundBrush(const QStyleOptionGraphicsItem *option) const
{
const QPalette::ColorGroup group = option->state & QStyle::State_Enabled ?
QPalette::Normal : QPalette::Disabled;
QBrush background(Qt::NoBrush);
// Always use the highlight color for selected items
if (option->state & QStyle::State_Selected) {
background = option->palette.brush(group, QPalette::Highlight);
}
return background;
}
void IconWidgetPrivate::drawTextItems(QPainter *painter,
const QStyleOptionGraphicsItem *option,
const QTextLayout &labelLayout,
const QTextLayout &infoLayout) const
{
Q_UNUSED(option)
painter->save();
painter->setPen(textColor);
// the translation prevents odd rounding errors in labelLayout.position()
// when applied to the canvas
painter->translate(0.5, 0.5);
labelLayout.draw(painter, QPointF());
if (!infoLayout.text().isEmpty()) {
painter->setPen(textColor);
infoLayout.draw(painter, QPointF());
}
painter->restore();
}
void IconWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);
//Lay out the main icon and action icons
d->layoutIcons(option);
// Compute the metrics, and lay out the text items
// ========================================================================
IconWidgetPrivate::IconWidgetState state = IconWidgetPrivate::NoState;
if (d->states & IconWidgetPrivate::ManualPressedState) {
state = IconWidgetPrivate::PressedState;
} else if (d->states & IconWidgetPrivate::PressedState) {
if (d->states & IconWidgetPrivate::HoverState) {
state = IconWidgetPrivate::PressedState;
}
} else if (d->states & IconWidgetPrivate::HoverState) {
state = IconWidgetPrivate::HoverState;
}
QPixmap icon = d->decoration(option, state != IconWidgetPrivate::NoState, state & IconWidgetPrivate::PressedState);
const QPointF iconPos = d->iconPosition(option, icon);
d->drawBackground(painter, state);
// draw icon
if (!icon.isNull()) {
painter->drawPixmap(iconPos, icon);
}
// Draw corner actions
foreach (const IconAction *action, d->cornerActions) {
if (action->isAnimating()) {
action->paint(painter);
}
}
// Draw text last because it is overlayed
QTextLayout labelLayout, infoLayout;
QRectF textBoundingRect;
d->layoutTextItems(option, icon, &labelLayout, &infoLayout, &textBoundingRect);
if (d->textBgColor != QColor() && d->textBgColor.alpha() > 0 &&
!(d->text.isEmpty() && d->infoText.isEmpty()) &&
!textBoundingRect.isEmpty() &&
!qFuzzyCompare(d->hoverAnimation->value(), (qreal)1.0)) {
QRectF rect = textBoundingRect.adjusted(-2, -2, 4, 4).toAlignedRect();
painter->setPen(Qt::transparent);
QColor color = d->textBgColor;
color.setAlpha(60 * (1.0 - d->hoverAnimation->value()));
QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
gradient.setColorAt(0, color.lighter(120));
gradient.setColorAt(1, color.darker(120));
painter->setBrush(gradient);
gradient.setColorAt(0, color.lighter(130));
gradient.setColorAt(1, color.darker(130));
painter->setPen(QPen(gradient, 0));
painter->setRenderHint(QPainter::Antialiasing);
painter->drawPath(PaintUtils::roundedRectangle(rect.translated(0.5, 0.5), 4));
}
if (d->shadowColor.value() < 128 || textBackgroundColor() != QColor()) {
QPoint shadowPos;
if (d->shadowColor.value() < 128) {
shadowPos = QPoint(1, 2);
} else {
shadowPos = QPoint(0, 0);
}
QImage shadow(textBoundingRect.size().toSize() + QSize(4, 4),
QImage::Format_ARGB32_Premultiplied);
shadow.fill(Qt::transparent);
{
QPainter buffPainter(&shadow);
buffPainter.translate(-textBoundingRect.x(), -textBoundingRect.y());
d->drawTextItems(&buffPainter, option, labelLayout, infoLayout);
}
PaintUtils::shadowBlur(shadow, 2, d->shadowColor);
painter->drawImage(textBoundingRect.topLeft() + shadowPos, shadow);
} else if (!(d->text.isEmpty() && d->infoText.isEmpty()) &&
!textBoundingRect.isEmpty()) {
QRect labelRect = d->labelRectangle(option, icon, d->text).toRect();
foreach (const QRect &rect, d->haloRects) {
Plasma::PaintUtils::drawHalo(painter, rect);
}
}
d->drawTextItems(painter, option, labelLayout, infoLayout);
}
void IconWidget::setTextBackgroundColor(const QColor &color)
{
d->textBgCustomized = true;
d->textBgColor = color;
update();
}
QColor IconWidget::textBackgroundColor() const
{
return d->textBgColor;
}
void IconWidget::drawActionButtonBase(QPainter *painter, const QSize &size, int element)
{
qreal radius = size.width() / 2;
QRadialGradient gradient(radius, radius, radius, radius, radius);
int alpha;
if (element == IconWidgetPrivate::MinibuttonPressed) {
alpha = 255;
} else if (element == IconWidgetPrivate::MinibuttonHover) {
alpha = 200;
} else {
alpha = 160;
}
gradient.setColorAt(0, QColor::fromRgb(d->textColor.red(),
d->textColor.green(),
d->textColor.blue(), alpha));
gradient.setColorAt(1, QColor::fromRgb(d->textColor.red(),
d->textColor.green(),
d->textColor.blue(), 0));
painter->setBrush(gradient);
painter->setPen(Qt::NoPen);
painter->drawEllipse(QRectF(QPointF(.0, .0), size));
}
void IconWidget::setText(const QString &text)
{
d->text = KGlobal::locale()->removeAcceleratorMarker(text);
// cause a relayout
d->currentSize = QSizeF(-1, -1);
//try to relayout, needed if an icon was never shown before
if (!isVisible()) {
QStyleOptionGraphicsItem styleoption;
d->layoutIcons(&styleoption);
}
updateGeometry();
if (!parentWidget() || !parentWidget()->layout()) {
resize(preferredSize());
}
}
QString IconWidget::text() const
{
return d->text;
}
void IconWidget::setInfoText(const QString &text)
{
d->infoText = text;
// cause a relayout
d->currentSize = QSizeF(-1, -1);
//try to relayout, needed if an icon was never shown before
if (!isVisible()) {
QStyleOptionGraphicsItem styleoption;
d->layoutIcons(&styleoption);
}
updateGeometry();
if (!parentWidget() || !parentWidget()->layout()) {
resize(preferredSize());
}
}
QString IconWidget::infoText() const
{
return d->infoText;
}
QIcon IconWidget::icon() const
{
return d->icon;
}
void IconWidget::setIcon(const QString &icon)
{
if (icon.isEmpty()) {
setIcon(QIcon());
return;
}
setIcon(KIcon(icon));
}
void IconWidget::setIcon(const QIcon &icon)
{
setSvg(QString());
/*fade to the new icon, but to not bee a too big hog, not do that when:
- the fade animation is already running
- the icon is under mouse
- one betwen the old and new icon is null*/
if (!(d->states & IconWidgetPrivate::HoverState) && !d->iconChangeTimer->isActive() && d->oldIcon.isNull() && !d->icon.isNull() && !icon.isNull()) {
d->oldIcon = d->icon;
d->animateMainIcon(true, d->states);
} else {
d->oldIcon = QIcon();
}
d->iconChangeTimer->start(300);
d->icon = icon;
update();
}
QSizeF IconWidget::iconSize() const
{
return d->iconSize;
}
void IconWidget::setPreferredIconSize(const QSizeF &size)
{
d->preferredIconSize = size;
updateGeometry();
}
QSizeF IconWidget::preferredIconSize() const
{
return d->preferredIconSize;
}
void IconWidget::setMinimumIconSize(const QSizeF &size)
{
d->minimumIconSize = size;
updateGeometry();
}
QSizeF IconWidget::minimumIconSize() const
{
return d->minimumIconSize;
}
void IconWidget::setMaximumIconSize(const QSizeF &size)
{
d->maximumIconSize = size;
updateGeometry();
}
QSizeF IconWidget::maximumIconSize() const
{
return d->maximumIconSize;
}
bool IconWidget::isDown()
{
return d->states & IconWidgetPrivate::PressedState;
}
void IconWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() != Qt::LeftButton) {
QGraphicsWidget::mousePressEvent(event);
return;
}
if (KGlobalSettings::singleClick() || (receivers(SIGNAL(clicked()))) > 0) {
d->states |= IconWidgetPrivate::PressedState;
}
d->clickStartPos = scenePos();
bool handled = false;
foreach (IconAction *action, d->cornerActions) {
handled = action->event(event->type(), event->pos());
if (handled) {
break;
}
}
if (!handled && boundingRect().contains(event->pos())) {
emit pressed(true);
}
update();
}
void IconWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (~d->states & IconWidgetPrivate::PressedState) {
QGraphicsWidget::mouseMoveEvent(event);
return;
}
if (boundingRect().contains(event->pos())) {
if (~d->states & IconWidgetPrivate::HoverState) {
d->states |= IconWidgetPrivate::HoverState;
update();
}
} else {
if (d->states & IconWidgetPrivate::HoverState) {
d->states &= ~IconWidgetPrivate::HoverState;
update();
}
}
}
void IconWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (~d->states & IconWidgetPrivate::PressedState) {
QGraphicsWidget::mouseMoveEvent(event);
return;
}
d->states &= ~IconWidgetPrivate::PressedState;
//don't pass click when the mouse was moved
bool handled = d->clickStartPos != scenePos();
if (!handled) {
foreach (IconAction *action, d->cornerActions) {
if (action->event(event->type(), event->pos())) {
handled = true;
break;
}
}
}
if (!handled) {
if (boundingRect().contains(event->pos())) {
emit clicked();
if (KGlobalSettings::singleClick()) {
emit activated();
}
if (d->action && d->action->menu()) {
d->action->menu()->popup(event->screenPos());
}
}
emit pressed(false);
}
update();
}
void IconWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event)
d->states |= IconWidgetPrivate::PressedState;
emit doubleClicked();
if (!KGlobalSettings::singleClick()) {
emit activated();
}
update();
}
void IconWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
//kDebug();
foreach (IconAction *action, d->cornerActions) {
action->show();
action->event(event->type(), event->pos());
}
d->oldIcon = QIcon();
d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
QGraphicsWidget::hoverEnterEvent(event);
}
void IconWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
//kDebug() << d->cornerActions;
foreach (IconAction *action, d->cornerActions) {
action->hide();
action->event(event->type(), event->pos());
}
// d->states &= ~IconWidgetPrivate::HoverState; // Will be set once progress is zero again ...
//if an eventfilter stolen the mousereleaseevent remove the pressed state here
d->states &= ~IconWidgetPrivate::PressedState;
d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
QGraphicsWidget::hoverLeaveEvent(event);
}
bool IconWidget::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
{
Q_UNUSED(watched)
if (event->type() == QEvent::GraphicsSceneDragEnter) {
d->animateMainIcon(true, d->states|IconWidgetPrivate::HoverState);
} else if (event->type() == QEvent::GraphicsSceneDragLeave) {
d->animateMainIcon(false, d->states|IconWidgetPrivate::HoverState);
}
return false;
}
void IconWidget::setPressed(bool pressed)
{
if (pressed) {
d->states |= IconWidgetPrivate::ManualPressedState;
d->states |= IconWidgetPrivate::PressedState;
} else {
d->states &= ~IconWidgetPrivate::ManualPressedState;
d->states &= ~IconWidgetPrivate::PressedState;
}
update();
}
void IconWidget::setUnpressed()
{
setPressed(false);
}
void IconWidgetPrivate::svgChanged()
{
iconSvgElementChanged = true;
q->update();
}
void IconWidget::setOrientation(Qt::Orientation orientation)
{
d->orientation = orientation;
resize(sizeFromIconSize(d->iconSize.width()));
}
Qt::Orientation IconWidget::orientation() const
{
return d->orientation;
}
void IconWidget::invertLayout(bool invert)
{
d->invertLayout = invert;
}
bool IconWidget::invertedLayout() const
{
return d->invertLayout;
}
QSizeF IconWidget::sizeFromIconSize(const qreal iconWidth) const
{
d->setActiveMargins();
if (d->text.isEmpty() && d->infoText.isEmpty()) {
//no text, just the icon size
return d->addMargin(QSizeF(iconWidth, iconWidth), IconWidgetPrivate::ItemMargin);
}
QFontMetricsF fm(font());
qreal width = 0;
if (d->orientation == Qt::Vertical) {
width = qMax(d->maxWordWidth(d->text),
d->maxWordWidth(d->infoText)) +
fm.width("xxx") +
d->verticalMargin[IconWidgetPrivate::TextMargin].left +
d->verticalMargin[IconWidgetPrivate::TextMargin].right;
width = qMax(width,
iconWidth +
d->verticalMargin[IconWidgetPrivate::IconMargin].left +
d->verticalMargin[IconWidgetPrivate::IconMargin].right);
} else {
width = iconWidth +
d->horizontalMargin[IconWidgetPrivate::IconMargin].left +
d->horizontalMargin[IconWidgetPrivate::IconMargin].right +
qMax(fm.width(d->text), fm.width(d->infoText)) + fm.width("xxx") +
d->horizontalMargin[IconWidgetPrivate::TextMargin].left +
d->horizontalMargin[IconWidgetPrivate::TextMargin].right;
}
qreal height;
qreal textHeight;
QStyleOptionGraphicsItem option;
option.state = QStyle::State_None;
option.rect = QRect(0, 0, width, QWIDGETSIZE_MAX);
textHeight = d->displaySizeHint(&option, width).height();
if (d->orientation == Qt::Vertical) {
height = iconWidth + textHeight +
d->verticalMargin[IconWidgetPrivate::TextMargin].top +
d->verticalMargin[IconWidgetPrivate::TextMargin].bottom +
d->verticalMargin[IconWidgetPrivate::IconMargin].top +
d->verticalMargin[IconWidgetPrivate::IconMargin].bottom;
} else {
//Horizontal
height = qMax(iconWidth +
d->verticalMargin[IconWidgetPrivate::IconMargin].top +
d->verticalMargin[IconWidgetPrivate::IconMargin].bottom,
textHeight +
d->verticalMargin[IconWidgetPrivate::TextMargin].top +
d->verticalMargin[IconWidgetPrivate::TextMargin].bottom);
}
return d->addMargin(QSizeF(width, height), IconWidgetPrivate::ItemMargin);
}
void IconWidget::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsWidget::changeEvent(event);
}
} // namespace Plasma
+
+#include "moc_iconwidget.cpp"
#include "moc_iconwidget_p.cpp"
diff --git a/plasma/widgets/itembackground.cpp b/plasma/widgets/itembackground.cpp
index 75ed506b60..8af7b430c4 100644
--- a/plasma/widgets/itembackground.cpp
+++ b/plasma/widgets/itembackground.cpp
@@ -1,344 +1,347 @@
/***************************************************************************
* Copyright 2009 by Alessandro Diaferia <alediaferia@gmail.com> *
* Copyright 2009 by 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 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 "itembackground.h"
#include <QPainter>
#include <QTimer>
#include <QStyleOptionGraphicsItem>
#include <QPropertyAnimation>
#include <kdebug.h>
#include <plasma/framesvg.h>
#include <plasma/animator.h>
#include <plasma/theme.h>
namespace Plasma
{
class ItemBackgroundPrivate
{
public:
ItemBackgroundPrivate(ItemBackground *parent)
: q(parent),
target(0)
{}
void animationUpdate(qreal progress);
void targetDestroyed(QObject*);
void frameSvgChanged();
void refreshCurrentTarget();
ItemBackground * const q;
QGraphicsItem *target;
Plasma::FrameSvg *frameSvg;
QRectF oldGeometry;
QRectF newGeometry;
QPropertyAnimation *anim;
qreal opacity;
bool fading;
bool fadeIn;
bool immediate;
};
ItemBackground::ItemBackground(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new ItemBackgroundPrivate(this))
{
d->frameSvg = new Plasma::FrameSvg(this);
d->anim = new QPropertyAnimation(this, "animationUpdate", this);
d->anim->setStartValue(0);
d->anim->setEndValue(1);
d->opacity = 1;
d->fading = false;
d->fadeIn = false;
d->immediate = false;
d->frameSvg->setImagePath("widgets/viewitem");
d->frameSvg->setEnabledBorders(Plasma::FrameSvg::AllBorders);
d->frameSvg->setCacheAllRenderedFrames(true);
d->frameSvg->setElementPrefix("hover");
setCacheMode(DeviceCoordinateCache);
setFlag(ItemIsMovable, false);
setFlag(ItemIsSelectable, false);
setFlag(ItemIsFocusable, false);
setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
qreal l, t, r, b;
d->frameSvg->getMargins(l, t, r, b);
setContentsMargins(l, t, r, b);
connect(d->frameSvg, SIGNAL(repaintNeeded()), this, SLOT(frameSvgChanged()));
setAcceptedMouseButtons(0);
setZValue(-800);
}
ItemBackground::~ItemBackground()
{
delete d;
}
QRectF ItemBackground::target() const
{
return d->newGeometry;
}
void ItemBackground::setTarget(const QRectF &newGeometry)
{
d->oldGeometry = geometry();
d->newGeometry = newGeometry;
if (!isVisible() && (!d->target || !d->target->isVisible())) {
setGeometry(d->newGeometry);
targetReached(newGeometry);
if (d->target) {
emit targetItemReached(d->target);
}
return;
}
QGraphicsWidget *pw = parentWidget();
if (pw) {
d->newGeometry = d->newGeometry.intersected(QRectF(QPointF(0,0), pw->size()));
}
if (d->anim->state() != QAbstractAnimation::Stopped) {
d->anim->stop();
}
if (d->target && d->target->isVisible() && !isVisible()) {
setZValue(d->target->zValue()-1);
setGeometry(newGeometry);
d->oldGeometry = newGeometry;
show();
} else {
d->fading = false;
d->opacity = 1;
d->anim->start();
}
}
void ItemBackground::setTargetItem(QGraphicsItem *target)
{
if (d->target && d->target != target) {
QObject *obj = 0;
if (d->target->isWidget()) {
obj = static_cast<QGraphicsWidget*>(d->target);
obj->removeEventFilter(this);
} else {
d->target->removeSceneEventFilter(this);
obj = dynamic_cast<QObject *>(d->target);
}
if (obj) {
disconnect(obj, 0, this, 0);
}
}
if (!target) {
hide();
}
bool newTarget = (d->target != target);
d->target = target;
if (target) {
setZValue(target->zValue() - 1);
if (parentItem() != target->parentItem()) {
QTransform t = transform();
setTransform(QTransform());
QRectF geom = mapToScene(geometry()).boundingRect();
setGeometry(mapFromScene(geom).boundingRect());
setTransform(t);
}
QRectF rect = target->boundingRect();
rect.moveTopLeft(mapToParent(mapFromScene(target->mapToScene(QPointF(0, 0)))));
setTarget(rect);
if (newTarget) {
QObject *obj = 0;
if (target->isWidget()) {
obj = static_cast<QGraphicsWidget*>(target);
obj->installEventFilter(this);
} else {
d->target->installSceneEventFilter(this);
obj = dynamic_cast<QObject *>(target);
}
if (obj) {
connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(targetDestroyed(QObject*)));
}
}
}
}
QGraphicsItem *ItemBackground::targetItem() const
{
return d->target;
}
bool ItemBackground::eventFilter(QObject *watched, QEvent *event)
{
QGraphicsWidget *targetWidget = static_cast<QGraphicsWidget *>(d->target);
if (watched == targetWidget) {
if (event->type() == QEvent::GraphicsSceneResize ||
event->type() == QEvent::GraphicsSceneMove) {
// We need to wait for the parent widget to resize...
QTimer::singleShot(0, this, SLOT(refreshCurrentTarget()) );
} else if (event->type() == QEvent::Show) {
setTargetItem(targetWidget);
}
}
return false;
}
bool ItemBackground::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
{
if (watched == d->target) {
if (event->type() == QEvent::GraphicsSceneMove) {
QTimer::singleShot(0, this, SLOT(refreshCurrentTarget()) );
}
}
return false;
}
void ItemBackground::resizeEvent(QGraphicsSceneResizeEvent *)
{
d->frameSvg->resizeFrame(size());
}
QVariant ItemBackground::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (d->immediate) {
return value;
}
if (change == ItemVisibleChange) {
bool visible = value.toBool();
bool retVisible = visible;
if (visible == isVisible() || d->anim->state() == QAbstractAnimation::Stopped) {
retVisible = true;
}
d->fading = true;
d->fadeIn = visible;
if (d->anim->state() != QAbstractAnimation::Stopped) {
d->anim->stop();
}
d->anim->setDuration(100);
d->anim->start();
return retVisible;
}
return value;
}
void ItemBackground::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget)
if (qFuzzyCompare(d->opacity, (qreal)1.0)) {
d->frameSvg->paintFrame(painter, option->rect.topLeft());
} else if (qFuzzyCompare(d->opacity+1, (qreal)1.0)) {
return;
} else {
QPixmap framePix = d->frameSvg->framePixmap();
QPainter bufferPainter(&framePix);
bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
bufferPainter.fillRect(framePix.rect(), QColor(0, 0, 0, 255 * d->opacity));
bufferPainter.end();
painter->drawPixmap(framePix.rect(), framePix, framePix.rect());
}
}
void ItemBackground::setAnimationUpdate(qreal progress)
{
d->animationUpdate(progress);
}
qreal ItemBackground::animationUpdate() const
{
return d->opacity;
}
void ItemBackgroundPrivate::animationUpdate(qreal progress)
{
if (progress == 1) {
if ((!fading) || (fadeIn)) {
emit q->targetReached(newGeometry);
if (target) {
emit q->targetItemReached(target);
}
}
}
if (fading) {
opacity = fadeIn?progress:1-progress;
if (!fadeIn && qFuzzyCompare(opacity+1, (qreal)1.0)) {
immediate = true;
q->hide();
immediate = false;
}
} else if (oldGeometry != newGeometry) {
q->setGeometry(oldGeometry.x() + (newGeometry.x() - oldGeometry.x()) * progress,
oldGeometry.y() + (newGeometry.y() - oldGeometry.y()) * progress,
oldGeometry.width() + (newGeometry.width() - oldGeometry.width()) * progress,
oldGeometry.height() + (newGeometry.height() - oldGeometry.height()) * progress);
}
q->update();
emit q->animationStep(progress);
}
void ItemBackgroundPrivate::targetDestroyed(QObject*)
{
target = 0;
q->setTargetItem(0);
}
void ItemBackgroundPrivate::frameSvgChanged()
{
qreal l, t, r, b;
frameSvg->getMargins(l, t, r, b);
q->setContentsMargins(l, t, r, b);
q->update();
emit q->appearanceChanged();
}
void ItemBackgroundPrivate::refreshCurrentTarget()
{
q->setTargetItem(target);
}
} // Plasma namespace
+
+
+#include "moc_itembackground.cpp"
diff --git a/plasma/widgets/label.cpp b/plasma/widgets/label.cpp
index a216c6bd79..ebadcf1bd7 100644
--- a/plasma/widgets/label.cpp
+++ b/plasma/widgets/label.cpp
@@ -1,351 +1,353 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "label.h"
#include <QApplication>
#include <QDir>
#include <QGraphicsSceneMouseEvent>
#include <QLabel>
#include <QMenu>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <kcolorscheme.h>
#include <kglobalsettings.h>
#include <kmimetype.h>
#include "private/themedwidgetinterface_p.h"
#include "svg.h"
#include "theme.h"
namespace Plasma
{
class LabelPrivate : public ThemedWidgetInterface<Label>
{
public:
LabelPrivate(Label *label)
: ThemedWidgetInterface<Label>(label),
svg(0),
textSelectable(false),
hasLinks(false)
{
}
~LabelPrivate()
{
delete svg;
}
void setPixmap()
{
if (imagePath.isEmpty()) {
delete svg;
svg = 0;
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
QPixmap pm(q->size().toSize());
if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {
if (!svg || svg->imagePath() != absImagePath) {
delete svg;
svg = new Svg();
svg->setImagePath(imagePath);
QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap()));
}
QPainter p(&pm);
svg->paint(&p, pm.rect());
} else {
delete svg;
svg = 0;
pm = QPixmap(absImagePath);
}
static_cast<QLabel*>(q->widget())->setPixmap(pm);
}
QString imagePath;
QString absImagePath;
Svg *svg;
bool textSelectable : 1;
bool hasLinks : 1;
};
Label::Label(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new LabelPrivate(this))
{
QLabel *native = new QLabel;
native->setWindowFlags(native->windowFlags()|Qt::BypassGraphicsProxyWidget);
native->setAttribute(Qt::WA_NoSystemBackground);
native->setWordWrap(true);
native->setWindowIcon(QIcon());
connect(native, SIGNAL(linkActivated(QString)), this, SIGNAL(linkActivated(QString)));
connect(native, SIGNAL(linkHovered(QString)), this, SIGNAL(linkHovered(QString)));
d->setWidget(native);
d->initTheming();
}
Label::~Label()
{
delete d;
}
void Label::setText(const QString &text)
{
d->hasLinks = text.contains("<a ", Qt::CaseInsensitive);
static_cast<QLabel*>(widget())->setText(text);
updateGeometry();
}
QString Label::text() const
{
return static_cast<QLabel*>(widget())->text();
}
void Label::setImage(const QString &path)
{
if (d->imagePath == path) {
return;
}
delete d->svg;
d->svg = 0;
d->imagePath = path;
bool absolutePath = !path.isEmpty() &&
#ifdef Q_WS_WIN
!QDir::isRelativePath(path)
#else
(path[0] == '/' || path.startsWith(QLatin1String(":/")))
#endif
;
if (absolutePath) {
d->absImagePath = path;
} else {
//TODO: package support
d->absImagePath = Theme::defaultTheme()->imagePath(path);
}
d->setPixmap();
}
QString Label::image() const
{
return d->imagePath;
}
void Label::setScaledContents(bool scaled)
{
static_cast<QLabel*>(widget())->setScaledContents(scaled);
}
bool Label::hasScaledContents() const
{
return static_cast<QLabel*>(widget())->hasScaledContents();
}
void Label::setTextSelectable(bool enable)
{
if (enable) {
nativeWidget()->setTextInteractionFlags(Qt::TextBrowserInteraction);
} else {
nativeWidget()->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
}
d->textSelectable = enable;
}
bool Label::textSelectable() const
{
return d->textSelectable;
}
void Label::setAlignment(Qt::Alignment alignment)
{
nativeWidget()->setAlignment(alignment);
}
Qt::Alignment Label::alignment() const
{
return nativeWidget()->alignment();
}
void Label::setWordWrap(bool wrap)
{
nativeWidget()->setWordWrap(wrap);
}
bool Label::wordWrap() const
{
return nativeWidget()->wordWrap();
}
void Label::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString Label::styleSheet()
{
return widget()->styleSheet();
}
QLabel *Label::nativeWidget() const
{
return static_cast<QLabel*>(widget());
}
void Label::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
{
Q_UNUSED(sourceName);
QStringList texts;
foreach (const QVariant &v, data) {
if (v.canConvert(QVariant::String)) {
texts << v.toString();
}
}
setText(texts.join(" "));
}
void Label::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
if (d->textSelectable || d->hasLinks){
QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
event->pos().toPoint(), event->screenPos(), event->modifiers());
QApplication::sendEvent(nativeWidget(), &contextMenuEvent);
}else{
event->ignore();
}
}
void Label::resizeEvent(QGraphicsSceneResizeEvent *event)
{
d->setPixmap();
QGraphicsProxyWidget::resizeEvent(event);
}
void Label::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsProxyWidget::mousePressEvent(event);
//FIXME: when QTextControl accept()s mouse press events (as of Qt 4.6.2, it processes them
//but never marks them as accepted) the following event->accept() can be removed
if (d->textSelectable || d->hasLinks) {
event->accept();
}
}
void Label::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (d->textSelectable) {
QGraphicsProxyWidget::mouseMoveEvent(event);
}
}
void Label::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
QLabel *native = nativeWidget();
QFontMetrics fm = native->font();
//indirect painting still used for fade out
if (native->wordWrap() || native->text().isEmpty() || size().width() >= fm.width(native->text())) {
QGraphicsProxyWidget::paint(painter, option, widget);
} else {
const int gradientLength = 25;
QPixmap buffer(contentsRect().size().toSize());
buffer.fill(Qt::transparent);
QPainter buffPainter(&buffer);
QGraphicsProxyWidget::paint(&buffPainter, option, widget);
QLinearGradient gr;
buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
buffPainter.setPen(Qt::NoPen);
if (option->direction == Qt::LeftToRight) {
gr.setStart(size().width()-gradientLength, 0);
gr.setFinalStop(size().width(), 0);
gr.setColorAt(0, Qt::black);
gr.setColorAt(1, Qt::transparent);
buffPainter.setBrush(gr);
buffPainter.drawRect(QRect(gr.start().toPoint(), QSize(gradientLength, size().height())));
} else {
gr.setStart(0, 0);
gr.setFinalStop(gradientLength, 0);
gr.setColorAt(0, Qt::transparent);
gr.setColorAt(1, Qt::black);
buffPainter.setBrush(gr);
buffPainter.drawRect(QRect(0, 0, gradientLength, size().height()));
}
buffPainter.end();
painter->drawPixmap(contentsRect(), buffer, buffer.rect());
}
}
void Label::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
bool Label::event(QEvent *event)
{
d->event(event);
return QGraphicsProxyWidget::event(event);
}
QVariant Label::itemChange(GraphicsItemChange change, const QVariant & value)
{
if (change == QGraphicsItem::ItemCursorHasChanged) {
nativeWidget()->setCursor(cursor());
}
return QGraphicsWidget::itemChange(change, value);
}
QSizeF Label::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
if (sizePolicy().verticalPolicy() == QSizePolicy::Fixed) {
return QGraphicsProxyWidget::sizeHint(Qt::PreferredSize, constraint);
} else {
return QGraphicsProxyWidget::sizeHint(which, constraint);
}
}
} // namespace Plasma
-#include <label.moc>
+
+
+#include "moc_label.cpp"
diff --git a/plasma/widgets/lineedit.cpp b/plasma/widgets/lineedit.cpp
index d000439bf5..2a53b2a6da 100644
--- a/plasma/widgets/lineedit.cpp
+++ b/plasma/widgets/lineedit.cpp
@@ -1,230 +1,232 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "lineedit.h"
#include <QGraphicsSceneResizeEvent>
#include <QIcon>
#include <QPainter>
#include <QGraphicsView>
#include <klineedit.h>
#include <kmimetype.h>
#include "applet.h"
#include "framesvg.h"
#include "private/style_p.h"
#include "private/focusindicator_p.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
namespace Plasma
{
class LineEditPrivate : public ThemedWidgetInterface<LineEdit>
{
public:
LineEditPrivate(LineEdit *lineEdit)
: ThemedWidgetInterface<LineEdit>(lineEdit)
{
buttonColorForText = true;
}
~LineEditPrivate()
{
}
LineEdit *q;
Plasma::Style::Ptr style;
Plasma::FrameSvg *background;
};
LineEdit::LineEdit(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new LineEditPrivate(this))
{
d->style = Plasma::Style::sharedStyle();
d->background = new Plasma::FrameSvg(this);
d->background->setImagePath("widgets/lineedit");
d->background->setCacheAllRenderedFrames(true);
FocusIndicator *indicator = new FocusIndicator(this, d->background);
if (d->background->hasElement("hint-focus-over-base")) {
indicator->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
}
setNativeWidget(new KLineEdit);
}
LineEdit::~LineEdit()
{
delete d;
Plasma::Style::doneWithSharedStyle();
}
void LineEdit::setText(const QString &text)
{
static_cast<KLineEdit*>(widget())->setText(text);
}
QString LineEdit::text() const
{
return static_cast<KLineEdit*>(widget())->text();
}
void LineEdit::setClearButtonShown(bool show)
{
nativeWidget()->setClearButtonShown(show);
}
bool LineEdit::isClearButtonShown() const
{
return nativeWidget()->isClearButtonShown();
}
void LineEdit::setClickMessage(const QString &message)
{
nativeWidget()->setClickMessage(message);
}
QString LineEdit::clickMessage() const
{
return nativeWidget()->clickMessage();
}
void LineEdit::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString LineEdit::styleSheet()
{
return widget()->styleSheet();
}
void LineEdit::setNativeWidget(KLineEdit *nativeWidget)
{
if (widget()) {
widget()->deleteLater();
}
connect(nativeWidget, SIGNAL(editingFinished()), this, SIGNAL(editingFinished()));
connect(nativeWidget, SIGNAL(returnPressed()), this, SIGNAL(returnPressed()));
connect(nativeWidget, SIGNAL(textEdited(const QString&)), this, SIGNAL(textEdited(const QString&)));
connect(nativeWidget, SIGNAL(textChanged(const QString&)), this, SIGNAL(textChanged(const QString&)));
nativeWidget->setWindowFlags(nativeWidget->windowFlags()|Qt::BypassGraphicsProxyWidget);
d->setWidget(nativeWidget);
nativeWidget->setWindowIcon(QIcon());
nativeWidget->setAttribute(Qt::WA_NoSystemBackground);
nativeWidget->setStyle(d->style.data());
d->initTheming();
}
KLineEdit *LineEdit::nativeWidget() const
{
return static_cast<KLineEdit*>(widget());
}
void LineEdit::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
update();
}
void LineEdit::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
update();
}
void LineEdit::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
nativeWidget()->render(painter, QPoint(0, 0), QRegion(), QWidget::DrawChildren|QWidget::IgnoreMask);
}
void LineEdit::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
void LineEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget *widget = parentWidget();
Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(widget);
while (!applet && widget) {
widget = widget->parentWidget();
applet = qobject_cast<Plasma::Applet *>(widget);
}
if (applet) {
applet->setStatus(Plasma::AcceptingInputStatus);
}
QGraphicsProxyWidget::mousePressEvent(event);
}
void LineEdit::focusInEvent(QFocusEvent *event)
{
QGraphicsProxyWidget::focusInEvent(event);
if (!nativeWidget()->hasFocus()) {
// as of Qt 4.7, apparently we have a bug here in QGraphicsProxyWidget
nativeWidget()->setFocus(event->reason());
}
emit focusChanged(true);
}
void LineEdit::focusOutEvent(QFocusEvent *event)
{
QGraphicsWidget *widget = parentWidget();
Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(widget);
while (!applet && widget) {
widget = widget->parentWidget();
applet = qobject_cast<Plasma::Applet *>(widget);
}
if (applet) {
applet->setStatus(Plasma::UnknownStatus);
}
QEvent closeEvent(QEvent::CloseSoftwareInputPanel);
if (qApp) {
if (QGraphicsView *view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
if (view->scene() && view->scene() == scene()) {
QApplication::sendEvent(view, &closeEvent);
}
}
}
QGraphicsProxyWidget::focusOutEvent(event);
emit focusChanged(false);
}
} // namespace Plasma
-#include <lineedit.moc>
+
+
+#include "moc_lineedit.cpp"
diff --git a/plasma/widgets/meter.cpp b/plasma/widgets/meter.cpp
index 4e45a38345..8bb335d646 100644
--- a/plasma/widgets/meter.cpp
+++ b/plasma/widgets/meter.cpp
@@ -1,556 +1,558 @@
/*
* Copyright (C) 2007 Petri Damsten <damu@iki.fi>
*
* 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 "meter.h"
#include "private/meter_p.h"
#include <cmath>
#include <QPainter>
#include <QTimeLine>
#include <QPropertyAnimation>
#include <kdebug.h>
#include <kglobalsettings.h>
#include "plasma/animator.h"
#include "plasma/framesvg.h"
#include "plasma/theme.h"
namespace Plasma {
MeterPrivate::MeterPrivate(Meter *m)
: QObject(m),
minimum(0),
maximum(100),
value(0),
targetValue(0),
meterType(Meter::AnalogMeter),
image(0),
minrotate(0),
maxrotate(360),
meter(m)
{
}
void MeterPrivate::progressChanged(int progress)
{
value = progress;
meter->update();
}
void MeterPrivate::paint(QPainter *p, const QString &elementID)
{
if (image->hasElement(elementID)) {
QRectF elementRect = image->elementRect(elementID);
image->paint(p, elementRect, elementID);
}
}
void MeterPrivate::text(QPainter *p, int index)
{
QString elementID = QString("label%1").arg(index);
QString text = labels[index];
if (image->hasElement(elementID)) {
QRectF elementRect = image->elementRect(elementID);
Qt::Alignment align = Qt::AlignCenter;
if (colors.count() > index) {
p->setPen(QPen(colors[index]));
} else {
p->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
}
if (fonts.count() > index) {
p->setFont(fonts[index]);
}
QFontMetricsF fm(p->font());
// If the height is too small increase the Height of the button to shall the whole text #192988
if (elementRect.height() < fm.height()) {
QPointF oldCenter = elementRect.center();
elementRect.setHeight(fm.height());
elementRect.moveCenter(oldCenter);
}
if (alignments.count() > index) {
align = alignments[index];
}
if (elementRect.width() > elementRect.height()) {
if (align&Qt::AlignLeft) {
p->drawText(elementRect.bottomLeft(), text);
} else {
p->drawText(elementRect, align, text);
}
} else {
p->save();
QPointF rotateCenter(
elementRect.left() + elementRect.width() / 2,
elementRect.top() + elementRect.height() / 2);
p->translate(rotateCenter);
p->rotate(-90);
p->translate(elementRect.height() / -2,
elementRect.width() / -2);
QRectF r(0, 0, elementRect.height(), elementRect.width());
p->drawText(r, align, text);
p->restore();
}
}
}
QRectF MeterPrivate::barRect()
{
QRectF elementRect;
if (labels.count() > 0) {
elementRect = image->elementRect("background");
} else {
elementRect = QRectF(QPoint(0,0), meter->size());
}
if (image->hasElement("hint-bar-stretch") || !image->hasElement("bar-active-center")) {
return elementRect;
}
QSize imageSize = image->size();
image->resize();
QSize tileSize = image->elementSize("bar-active-center");
image->resize(imageSize);
if (elementRect.width() > elementRect.height()) {
qreal ratio = qMax(1, tileSize.height() / tileSize.width());
int numTiles = qMax(qreal(1.0), qreal(elementRect.width())/(qreal(elementRect.height())/ratio));
tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
QPoint center = elementRect.center().toPoint();
elementRect.setWidth(tileSize.width()*numTiles);
elementRect.moveCenter(center);
} else {
qreal ratio = qMax(1, tileSize.width() / tileSize.height());
int numTiles = qMax(qreal(1.0), qreal(elementRect.height())/(qreal(elementRect.width())/ratio));
tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
QPoint center = elementRect.center().toPoint();
elementRect.setHeight(tileSize.height()*numTiles);
elementRect.moveCenter(center);
}
return elementRect;
}
void MeterPrivate::paintBackground(QPainter *p)
{
//be retrocompatible with themes for kde <= 4.1
if (image->hasElement("background-center")) {
QRectF elementRect = barRect();
if (elementRect.isEmpty()) {
return; // nothing to be done
}
QSize imageSize = image->size();
image->resize();
image->setElementPrefix("background");
image->resizeFrame(elementRect.size());
image->paintFrame(p, elementRect.topLeft());
image->resize(imageSize);
paintBar(p, "bar-inactive");
} else {
paint(p, "background");
}
}
void MeterPrivate::paintBar(QPainter *p, const QString &prefix)
{
QRectF elementRect = barRect();
image->setUsingRenderingCache(false);
if (image->hasElement("hint-bar-stretch")) {
image->resizeFrame(elementRect.size());
image->paintFrame(p);
} else {
QSize imageSize = image->size();
image->resize();
QSize tileSize = image->elementSize("bar-active-center");
if (elementRect.width() > elementRect.height()) {
qreal ratio = tileSize.height() / tileSize.width();
int numTiles = elementRect.width()/(elementRect.height()/ratio);
tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
} else {
qreal ratio = tileSize.width() / tileSize.height();
int numTiles = elementRect.height()/(elementRect.width()/ratio);
tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
}
image->setElementPrefix(prefix);
image->resizeFrame(tileSize);
p->drawTiledPixmap(elementRect, image->framePixmap());
image->resize(imageSize);
}
image->setUsingRenderingCache(true);
}
void MeterPrivate::paintForeground(QPainter *p)
{
for (int i = 0; i < labels.count(); ++i) {
text(p, i);
}
paint(p, "foreground");
}
void MeterPrivate::setSizePolicyAndPreferredSize()
{
switch (meterType) {
case Meter::BarMeterHorizontal:
meter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
break;
case Meter::BarMeterVertical:
meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
break;
case Meter::AnalogMeter:
default:
meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
break;
}
if (image) {
//set a sane preferredSize. We can't just use the svg's native size, since that way
//letters get cut off if the user uses a font larger then usual. Check how many rows of
//labels we have, add 1 (the progress bar), and multiply by the font height to get a
//somewhat sane size height. This is not perfect but work well enough for 4.2. I suggest
//we look into alternatives for 4.3.
uint i = 0;
uint rows = 0;
qreal prevY = -1;
QString labelName = "label0";
while (image->hasElement(labelName)) {
if (image->elementRect(labelName).y() > prevY) {
prevY = image->elementRect(labelName).y();
rows++;
}
i++;
labelName = QString("label%0").arg(i);
}
Plasma::Theme *theme = Plasma::Theme::defaultTheme();
QFont font = theme->font(Plasma::Theme::DefaultFont);
QFontMetrics fm(font);
meter->setPreferredHeight((rows + 1) * fm.height());
} else {
meter->setPreferredSize(QSizeF(30, 30));
}
}
Meter::Meter(QGraphicsItem *parent) :
QGraphicsWidget(parent),
d(new MeterPrivate(this))
{
d->setSizePolicyAndPreferredSize();
d->animation = new QPropertyAnimation(d, "meterValue");
}
Meter::~Meter()
{
delete d->animation;
delete d;
}
void Meter::setMaximum(int maximum)
{
d->maximum = maximum;
}
int Meter::maximum() const
{
return d->maximum;
}
void Meter::setMinimum(int minimum)
{
d->minimum = minimum;
}
int Meter::minimum() const
{
return d->minimum;
}
int Meter::value() const
{
return d->value;
}
void Meter::setValue(int value)
{
if (value == d->targetValue) {
return;
}
d->targetValue = qBound(d->minimum, value, d->maximum);
int delta = abs(d->value - d->targetValue);
if (d->animation->state() != QAbstractAnimation::Running) {
d->animation->stop();
}
//kDebug() << d->targetValue << d->value << delta;
if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ||
delta / qreal(d->maximum) < 0.1) {
d->value = value;
update();
} else {
d->animation->setStartValue(d->value);
d->animation->setEndValue(value);
d->animation->start();
}
emit valueChanged(value);
}
int MeterPrivate::meterValue() const
{
return value;
}
void MeterPrivate::setMeterValue(int value)
{
progressChanged(value);
}
void Meter::setLabel(int index, const QString &text)
{
while (d->labels.count() <= index) {
d->labels << QString();
}
d->labels[index] = text;
}
QString Meter::label(int index) const
{
return d->labels[index];
}
void Meter::setLabelColor(int index, const QColor &color)
{
while (d->colors.count() <= index) {
d->colors << color;
}
d->colors[index] = color;
}
QColor Meter::labelColor(int index) const
{
return d->colors[index];
}
void Meter::setLabelFont(int index, const QFont &font)
{
while (d->fonts.count() <= index) {
d->fonts << font;
}
d->fonts[index] = font;
}
QFont Meter::labelFont(int index) const
{
return d->fonts[index];
}
void Meter::setLabelAlignment(int index, const Qt::Alignment alignment)
{
while (d->alignments.count() <= index) {
d->alignments << alignment;
}
d->alignments[index] = alignment;
}
Qt::Alignment Meter::labelAlignment(int index) const
{
return d->alignments[index];
}
QRectF Meter::labelRect(int index) const
{
QString elementID = QString("label%1").arg(index);
return d->image->elementRect(elementID);
}
void Meter::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
{
Q_UNUSED(sourceName)
foreach (const QVariant &v, data) {
if (v.type() == QVariant::Int ||
v.type() == QVariant::UInt ||
v.type() == QVariant::LongLong ||
v.type() == QVariant::ULongLong) {
setValue(v.toInt());
return;
}
}
}
void Meter::setSvg(const QString &svg)
{
if (d->svg == svg) {
return;
}
d->svg = svg;
delete d->image;
d->image = new Plasma::FrameSvg(this);
d->image->setImagePath(svg);
// To create renderer and get default size
d->image->resize();
d->setSizePolicyAndPreferredSize();
if (d->image->hasElement("rotateminmax")) {
QRectF r = d->image->elementRect("rotateminmax");
d->minrotate = (int)r.height();
d->maxrotate = (int)r.width();
}
}
QString Meter::svg() const
{
return d->svg;
}
void Meter::setMeterType(MeterType meterType)
{
d->meterType = meterType;
if (d->svg.isEmpty()) {
if (meterType == BarMeterHorizontal) {
setSvg("widgets/bar_meter_horizontal");
} else if (meterType == BarMeterVertical) {
setSvg("widgets/bar_meter_vertical");
} else if (meterType == AnalogMeter) {
setSvg("widgets/analog_meter");
}
}
d->setSizePolicyAndPreferredSize();
}
Meter::MeterType Meter::meterType() const
{
return d->meterType;
}
void Meter::paint(QPainter *p,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (d->svg.isEmpty()) {
setMeterType(d->meterType);
}
if (!d->image) {
return;
}
QRectF rect(QPointF(0, 0), size());
QRectF clipRect;
qreal percentage = 0.0;
qreal angle = 0.0;
QPointF rotateCenter;
QSize intSize = QSize((int)size().width(), (int)size().height());
if (intSize != d->image->size()) {
d->image->resize(intSize);
}
if (d->maximum != d->minimum) {
percentage = (qreal)(d->value - d->minimum) / (d->maximum - d->minimum);
}
p->setRenderHint(QPainter::SmoothPixmapTransform);
switch (d->meterType) {
case BarMeterHorizontal:
case BarMeterVertical:
d->paintBackground(p);
p->save();
clipRect = d->barRect();
if (clipRect.width() > clipRect.height()) {
clipRect.setWidth(clipRect.width() * percentage);
} else {
qreal bottom = clipRect.bottom();
clipRect.setHeight(clipRect.height() * percentage);
clipRect.moveBottom(bottom);
}
p->setClipRect(clipRect, Qt::IntersectClip);
//be retrocompatible
if (d->image->hasElement("bar-active-center")) {
d->paintBar(p, "bar-active");
} else {
d->paint(p, "bar");
}
p->restore();
d->paintForeground(p);
break;
case AnalogMeter:
d->paintBackground(p);
p->save();
if (d->image->hasElement("rotatecenter")) {
QRectF r = d->image->elementRect("rotatecenter");
rotateCenter = QPointF(r.left() + r.width() / 2,
r.top() + r.height() / 2);
} else {
rotateCenter = QPointF(rect.width() / 2, rect.height() / 2);
}
angle = percentage * (d->maxrotate - d->minrotate) + d->minrotate;
if (d->image->hasElement("pointer-shadow")) {
p->save();
p->translate(rotateCenter+QPoint(2,3));
p->rotate(angle);
p->translate(-1 * rotateCenter);
d->paint(p, "pointer-shadow");
p->restore();
}
p->translate(rotateCenter);
p->rotate(angle);
p->translate(-1 * rotateCenter);
d->paint(p, "pointer");
p->restore();
d->paintForeground(p);
break;
}
}
QSizeF Meter::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
return QGraphicsWidget::sizeHint(which, constraint);
}
} // End of namepace
-#include "moc_meter_p.cpp"
+
+#include "moc_meter.cpp"
+#include "../private/moc_meter_p.cpp"
diff --git a/plasma/widgets/pushbutton.cpp b/plasma/widgets/pushbutton.cpp
index e67937b5f5..0609428114 100644
--- a/plasma/widgets/pushbutton.cpp
+++ b/plasma/widgets/pushbutton.cpp
@@ -1,540 +1,542 @@
/*
* Copyright 2008 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 "pushbutton.h"
#include <QDir>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QWeakPointer>
#include <kicon.h>
#include <kiconeffect.h>
#include <kmimetype.h>
#include <kpushbutton.h>
#include "animator.h"
#include "animations/animation.h"
#include "framesvg.h"
#include "paintutils.h"
#include "private/actionwidgetinterface_p.h"
#include "private/focusindicator_p.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
namespace Plasma
{
class PushButtonPrivate : public ActionWidgetInterface<PushButton>
{
public:
PushButtonPrivate(PushButton *pushButton)
: ActionWidgetInterface<PushButton>(pushButton),
background(0),
fadeIn(false),
svg(0)
{
}
~PushButtonPrivate()
{
delete svg;
}
void setPixmap()
{
if (imagePath.isEmpty()) {
delete svg;
svg = 0;
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
QPixmap pm;
if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {
if (!svg || svg->imagePath() != absImagePath) {
delete svg;
svg = new Svg();
svg->setImagePath(imagePath);
QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap()));
if (!svgElement.isNull()) {
svg->setContainsMultipleImages(true);
}
}
//QPainter p(&pm);
if (!svgElement.isEmpty() && svg->hasElement(svgElement)) {
svg->resize();
QSizeF elementSize = svg->elementSize(svgElement);
float scale = q->nativeWidget()->iconSize().width() / qMax(elementSize.width(), elementSize.height());
svg->resize(elementSize * scale);
pm = svg->pixmap(svgElement);
} else {
svg->resize(q->nativeWidget()->iconSize());
pm = svg->pixmap();
}
} else {
delete svg;
svg = 0;
pm = QPixmap(absImagePath);
}
static_cast<KPushButton*>(q->widget())->setIcon(KIcon(pm));
}
void pressedChanged()
{
if (q->nativeWidget()->isDown() || q->nativeWidget()->isChecked()) {
focusIndicator->animateVisibility(false);
} else {
focusIndicator->animateVisibility(true);
}
}
void syncFrame()
{
if (background) {
//resize all panels
background->setElementPrefix("pressed");
background->resizeFrame(q->size());
syncActiveRect();
background->setElementPrefix("normal");
background->resizeFrame(q->size());
hoverAnimation->setProperty("startPixmap", background->framePixmap());
background->setElementPrefix("active");
background->resizeFrame(activeRect.size());
hoverAnimation->setProperty("targetPixmap", background->framePixmap());
}
}
void syncActiveRect();
void syncBorders();
FrameSvg *background;
bool fadeIn;
qreal opacity;
QRectF activeRect;
Animation *hoverAnimation;
FocusIndicator *focusIndicator;
QString imagePath;
QString absImagePath;
Svg *svg;
QString svgElement;
};
void PushButtonPrivate::syncActiveRect()
{
background->setElementPrefix("normal");
qreal left, top, right, bottom;
background->getMargins(left, top, right, bottom);
background->setElementPrefix("active");
qreal activeLeft, activeTop, activeRight, activeBottom;
background->getMargins(activeLeft, activeTop, activeRight, activeBottom);
activeRect = QRectF(QPointF(0, 0), q->size());
activeRect.adjust(left - activeLeft, top - activeTop,
-(right - activeRight), -(bottom - activeBottom));
background->setElementPrefix("normal");
}
void PushButtonPrivate::syncBorders()
{
//set margins from the normal element
qreal left, top, right, bottom;
background->setElementPrefix("normal");
background->getMargins(left, top, right, bottom);
q->setContentsMargins(left, top, right, bottom);
//calc the rect for the over effect
syncActiveRect();
}
PushButton::PushButton(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new PushButtonPrivate(this))
{
d->background = new FrameSvg(this);
d->background->setImagePath("widgets/button");
d->background->setCacheAllRenderedFrames(true);
d->background->setElementPrefix("normal");
d->hoverAnimation = Animator::create(Animator::PixmapTransitionAnimation);
d->hoverAnimation->setTargetWidget(this);
KPushButton *native = new KPushButton;
connect(native, SIGNAL(pressed()), this, SIGNAL(pressed()));
connect(native, SIGNAL(pressed()), this, SLOT(pressedChanged()));
connect(native, SIGNAL(released()), this, SIGNAL(released()));
connect(native, SIGNAL(released()), this, SLOT(pressedChanged()));
connect(native, SIGNAL(clicked()), this, SIGNAL(clicked()));
connect(native, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
setWidget(native);
native->setAttribute(Qt::WA_NoSystemBackground);
native->setWindowIcon(QIcon());
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
d->focusIndicator = new FocusIndicator(this, d->background);
d->syncBorders();
setAcceptHoverEvents(true);
connect(d->background, SIGNAL(repaintNeeded()), SLOT(syncBorders()));
d->initTheming();
d->syncFrame();
}
PushButton::~PushButton()
{
delete d;
}
void PushButton::setText(const QString &text)
{
static_cast<KPushButton*>(widget())->setText(text);
updateGeometry();
}
QString PushButton::text() const
{
return static_cast<KPushButton*>(widget())->text();
}
void PushButton::setImage(const QString &path)
{
if (d->imagePath == path) {
return;
}
delete d->svg;
d->svg = 0;
d->imagePath = path;
bool absolutePath = !path.isEmpty() &&
#ifdef Q_WS_WIN
!QDir::isRelativePath(path)
#else
(path[0] == '/' || path.startsWith(QLatin1String(":/")))
#endif
;
if (absolutePath) {
d->absImagePath = path;
} else {
//TODO: package support
d->absImagePath = Theme::defaultTheme()->imagePath(path);
}
d->setPixmap();
}
void PushButton::setImage(const QString &path, const QString &elementid)
{
d->svgElement = elementid;
setImage(path);
}
QString PushButton::image() const
{
return d->imagePath;
}
void PushButton::setStyleSheet(const QString &stylesheet)
{
d->focusIndicator->setVisible(stylesheet.isEmpty());
widget()->setStyleSheet(stylesheet);
}
QString PushButton::styleSheet()
{
return widget()->styleSheet();
}
void PushButton::setAction(QAction *action)
{
d->setAction(action);
}
QAction *PushButton::action() const
{
return d->action;
}
void PushButton::setIcon(const KIcon &icon)
{
nativeWidget()->setIcon(icon);
}
void PushButton::setIcon(const QIcon &icon)
{
setIcon(KIcon(icon));
}
QIcon PushButton::icon() const
{
return nativeWidget()->icon();
}
void PushButton::setCheckable(bool checkable)
{
nativeWidget()->setCheckable(checkable);
}
bool PushButton::isCheckable() const
{
return nativeWidget()->isCheckable();
}
void PushButton::setChecked(bool checked)
{
nativeWidget()->setChecked(checked);
}
void PushButton::click()
{
nativeWidget()->animateClick();
}
bool PushButton::isChecked() const
{
return nativeWidget()->isChecked();
}
bool PushButton::isDown() const
{
return nativeWidget()->isDown();
}
KPushButton *PushButton::nativeWidget() const
{
return static_cast<KPushButton*>(widget());
}
void PushButton::resizeEvent(QGraphicsSceneResizeEvent *event)
{
d->setPixmap();
d->syncFrame();
QGraphicsProxyWidget::resizeEvent(event);
}
void PushButton::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
if (!styleSheet().isNull() || Theme::defaultTheme()->useNativeWidgetStyle()) {
QGraphicsProxyWidget::paint(painter, option, widget);
return;
}
QPixmap bufferPixmap;
//Normal button, pressed or not
if (isEnabled()) {
if (nativeWidget()->isDown() || nativeWidget()->isChecked()) {
d->background->setElementPrefix("pressed");
} else {
d->background->setElementPrefix("normal");
}
//flat or disabled
} else if (!isEnabled() || nativeWidget()->isFlat()) {
bufferPixmap = QPixmap(rect().size().toSize());
bufferPixmap.fill(Qt::transparent);
QPainter buffPainter(&bufferPixmap);
d->background->paintFrame(&buffPainter);
buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
buffPainter.fillRect(bufferPixmap.rect(), QColor(0, 0, 0, 128));
painter->drawPixmap(0, 0, bufferPixmap);
}
//if is under mouse draw the animated glow overlay
if (!nativeWidget()->isDown() && !nativeWidget()->isChecked() && isEnabled() && acceptHoverEvents() && d->background->hasElementPrefix("active")) {
if (d->hoverAnimation->state() == QAbstractAnimation::Running && !isUnderMouse() && !nativeWidget()->isDefault()) {
d->background->setElementPrefix("active");
d->background->paintFrame(painter, d->activeRect.topLeft());
} else {
painter->drawPixmap(
d->activeRect.topLeft(),
d->hoverAnimation->property("currentPixmap").value<QPixmap>());
}
} else if (isEnabled()) {
d->background->paintFrame(painter);
}
painter->setPen(Plasma::Theme::defaultTheme()->color(Theme::ButtonTextColor));
if (nativeWidget()->isDown()) {
painter->translate(QPoint(1, 1));
}
QRectF rect = contentsRect();
if (!nativeWidget()->icon().isNull()) {
const qreal iconSize = qMin(rect.width(), rect.height());
QPixmap iconPix = nativeWidget()->icon().pixmap(iconSize);
if (!isEnabled()) {
KIconEffect *effect = KIconLoader::global()->iconEffect();
iconPix = effect->apply(iconPix, KIconLoader::Toolbar, KIconLoader::DisabledState);
}
QRect pixmapRect;
if (nativeWidget()->text().isEmpty()) {
pixmapRect = nativeWidget()->style()->alignedRect(option->direction, Qt::AlignCenter, iconPix.size(), rect.toRect());
} else {
pixmapRect = nativeWidget()->style()->alignedRect(option->direction, Qt::AlignLeft|Qt::AlignVCenter, iconPix.size(), rect.toRect());
}
painter->drawPixmap(pixmapRect.topLeft(), iconPix);
if (option->direction == Qt::LeftToRight) {
rect.adjust(rect.height(), 0, 0, 0);
} else {
rect.adjust(0, 0, -rect.height(), 0);
}
}
QFontMetricsF fm(font());
// If the height is too small increase the Height of the button to shall the whole text #192988
if (rect.height() < fm.height()) {
rect.setHeight(fm.height());
rect.moveTop(boundingRect().center().y() - rect.height() / 2);
}
// If there is not enough room for the text make it to fade out
if (rect.width() < fm.width(nativeWidget()->text())) {
if (bufferPixmap.isNull()) {
bufferPixmap = QPixmap(rect.size().toSize());
}
bufferPixmap.fill(Qt::transparent);
QPainter p(&bufferPixmap);
p.setPen(painter->pen());
p.setFont(font());
// Create the alpha gradient for the fade out effect
QLinearGradient alphaGradient(0, 0, 1, 0);
alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
if (option->direction == Qt::LeftToRight) {
alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
p.drawText(bufferPixmap.rect(), Qt::AlignLeft|Qt::AlignVCenter|Qt::TextShowMnemonic,
nativeWidget()->text());
} else {
alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
alphaGradient.setColorAt(1, QColor(0, 0, 0, 255));
p.drawText(bufferPixmap.rect(), Qt::AlignRight|Qt::AlignVCenter|Qt::TextShowMnemonic,
nativeWidget()->text());
}
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.fillRect(bufferPixmap.rect(), alphaGradient);
painter->drawPixmap(rect.topLeft(), bufferPixmap);
} else {
painter->setFont(font());
painter->drawText(rect, Qt::AlignCenter|Qt::TextShowMnemonic, nativeWidget()->text());
}
}
void PushButton::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
if (nativeWidget()->isDown() || d->background->hasElementPrefix("hover")) {
return;
}
d->hoverAnimation->setProperty("duration", 75);
d->background->setElementPrefix("normal");
d->hoverAnimation->setProperty("startPixmap", d->background->framePixmap());
d->background->setElementPrefix("active");
d->hoverAnimation->setProperty("targetPixmap", d->background->framePixmap());
d->hoverAnimation->start();
QGraphicsProxyWidget::hoverEnterEvent(event);
}
void PushButton::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
void PushButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
if (nativeWidget()->isDown() || d->background->hasElementPrefix("hover")) {
return;
}
d->hoverAnimation->setProperty("duration", 150);
d->background->setElementPrefix("active");
d->hoverAnimation->setProperty("startPixmap", d->background->framePixmap());
d->background->setElementPrefix("normal");
d->hoverAnimation->setProperty("targetPixmap", d->background->framePixmap());
d->hoverAnimation->start();
QGraphicsProxyWidget::hoverLeaveEvent(event);
}
QSizeF PushButton::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
QSizeF hint = QGraphicsProxyWidget::sizeHint(which, constraint);
if (hint.isEmpty()) {
return hint;
}
//replace the native margin with the Svg one
QStyleOption option;
option.initFrom(nativeWidget());
int nativeMargin = nativeWidget()->style()->pixelMetric(QStyle::PM_ButtonMargin, &option, nativeWidget());
qreal left, top, right, bottom;
d->background->getMargins(left, top, right, bottom);
hint = hint - QSize(nativeMargin, nativeMargin) + QSize(left+right, top+bottom);
return hint;
}
} // namespace Plasma
-#include <pushbutton.moc>
+
+
+#include "moc_pushbutton.cpp"
diff --git a/plasma/widgets/radiobutton.cpp b/plasma/widgets/radiobutton.cpp
index 67e08288c9..6f300c530a 100644
--- a/plasma/widgets/radiobutton.cpp
+++ b/plasma/widgets/radiobutton.cpp
@@ -1,174 +1,176 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "radiobutton.h"
#include <QDir>
#include <QPainter>
#include <QRadioButton>
#include <kmimetype.h>
#include "private/themedwidgetinterface_p.h"
#include "svg.h"
#include "theme.h"
namespace Plasma
{
class RadioButtonPrivate : public ThemedWidgetInterface<RadioButton>
{
public:
RadioButtonPrivate(RadioButton *radio)
: ThemedWidgetInterface<RadioButton>(radio),
svg(0)
{
}
~RadioButtonPrivate()
{
delete svg;
}
void setPixmap(RadioButton *q)
{
if (imagePath.isEmpty()) {
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
QPixmap pm(q->size().toSize());
if (mime->is("image/svg+xml")) {
svg = new Svg();
QPainter p(&pm);
svg->paint(&p, pm.rect());
} else {
pm = QPixmap(absImagePath);
}
static_cast<QRadioButton*>(q->widget())->setIcon(QIcon(pm));
}
QString imagePath;
QString absImagePath;
Svg *svg;
};
RadioButton::RadioButton(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new RadioButtonPrivate(this))
{
QRadioButton *native = new QRadioButton;
connect(native, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
d->setWidget(native);
native->setWindowIcon(QIcon());
native->setAttribute(Qt::WA_NoSystemBackground);
d->initTheming();
}
RadioButton::~RadioButton()
{
delete d;
}
void RadioButton::setText(const QString &text)
{
static_cast<QRadioButton*>(widget())->setText(text);
}
QString RadioButton::text() const
{
return static_cast<QRadioButton*>(widget())->text();
}
void RadioButton::setImage(const QString &path)
{
if (d->imagePath == path) {
return;
}
delete d->svg;
d->svg = 0;
d->imagePath = path;
bool absolutePath = !path.isEmpty() &&
#ifdef Q_WS_WIN
!QDir::isRelativePath(path)
#else
(path[0] == '/' || path.startsWith(QLatin1String(":/")))
#endif
;
if (absolutePath) {
d->absImagePath = path;
} else {
//TODO: package support
d->absImagePath = Theme::defaultTheme()->imagePath(path);
}
d->setPixmap(this);
}
QString RadioButton::image() const
{
return d->imagePath;
}
void RadioButton::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString RadioButton::styleSheet()
{
return widget()->styleSheet();
}
QRadioButton *RadioButton::nativeWidget() const
{
return static_cast<QRadioButton*>(widget());
}
void RadioButton::resizeEvent(QGraphicsSceneResizeEvent *event)
{
d->setPixmap(this);
QGraphicsProxyWidget::resizeEvent(event);
}
void RadioButton::setChecked(bool checked)
{
static_cast<QRadioButton*>(widget())->setChecked(checked);
}
bool RadioButton::isChecked() const
{
return static_cast<QRadioButton*>(widget())->isChecked();
}
void RadioButton::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
} // namespace Plasma
-#include <radiobutton.moc>
+
+
+#include "moc_radiobutton.cpp"
diff --git a/plasma/widgets/scrollbar.cpp b/plasma/widgets/scrollbar.cpp
index 1426f0dc2d..73c6a81887 100644
--- a/plasma/widgets/scrollbar.cpp
+++ b/plasma/widgets/scrollbar.cpp
@@ -1,152 +1,154 @@
/*
* Copyright ツゥ 2008 Fredrik Hテカglund <fredrik@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 "scrollbar.h"
#include <QApplication>
#include <QContextMenuEvent>
#include <QGraphicsSceneContextMenuEvent>
#include <plasma/private/style_p.h>
namespace Plasma
{
class ScrollBarPrivate
{
public:
Plasma::Style::Ptr style;
};
ScrollBar::ScrollBar(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new ScrollBarPrivate)
{
QScrollBar *scrollbar = new QScrollBar();
scrollbar->setWindowFlags(scrollbar->windowFlags()|Qt::BypassGraphicsProxyWidget);
scrollbar->setAttribute(Qt::WA_NoSystemBackground);
setWidget(scrollbar);
scrollbar->setWindowIcon(QIcon());
d->style = Plasma::Style::sharedStyle();
scrollbar->setStyle(d->style.data());
scrollbar->resize(scrollbar->sizeHint());
connect(scrollbar, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
connect(scrollbar, SIGNAL(sliderMoved(int)), this, SIGNAL(sliderMoved(int)));
}
ScrollBar::~ScrollBar()
{
delete d;
Plasma::Style::doneWithSharedStyle();
}
void ScrollBar::setRange(int min, int max)
{
static_cast<QScrollBar*>(widget())->setRange(min, max);
}
void ScrollBar::setSingleStep(int val)
{
static_cast<QScrollBar*>(widget())->setSingleStep(val);
}
int ScrollBar::singleStep()
{
return static_cast<QScrollBar*>(widget())->singleStep();
}
void ScrollBar::setPageStep(int val)
{
static_cast<QScrollBar*>(widget())->setPageStep(val);
}
int ScrollBar::pageStep()
{
return static_cast<QScrollBar*>(widget())->pageStep();
}
void ScrollBar::setValue(int val)
{
static_cast<QScrollBar*>(widget())->setValue(val);
}
int ScrollBar::value() const
{
return static_cast<QScrollBar*>(widget())->value();
}
int ScrollBar::minimum() const
{
return static_cast<QScrollBar*>(widget())->minimum();
}
int ScrollBar::maximum() const
{
return static_cast<QScrollBar*>(widget())->maximum();
}
void ScrollBar::setMinimum(const int min) const
{
static_cast<QScrollBar*>(widget())->setMinimum(min);
}
void ScrollBar::setMaximum(const int max) const
{
static_cast<QScrollBar*>(widget())->setMaximum(max);
}
void ScrollBar::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString ScrollBar::styleSheet()
{
return widget()->styleSheet();
}
QScrollBar *ScrollBar::nativeWidget() const
{
return static_cast<QScrollBar *>(widget());
}
Qt::Orientation ScrollBar::orientation() const
{
return nativeWidget()->orientation();
}
void ScrollBar::setOrientation(Qt::Orientation orientation)
{
QScrollBar *native = static_cast<QScrollBar *>(widget());
native->setOrientation(orientation);
resize(native->sizeHint());
}
void ScrollBar::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
event->pos().toPoint(), event->screenPos(), event->modifiers());
QApplication::sendEvent(nativeWidget(), &contextMenuEvent);
}
}
-#include <scrollbar.moc>
+
+
+#include "moc_scrollbar.cpp"
diff --git a/plasma/widgets/scrollwidget.cpp b/plasma/widgets/scrollwidget.cpp
index fea9e10a33..241645ee52 100644
--- a/plasma/widgets/scrollwidget.cpp
+++ b/plasma/widgets/scrollwidget.cpp
@@ -1,1589 +1,1591 @@
/*
* Copyright 2009 Marco Martin <notmart@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "scrollwidget.h"
#include <cmath>
//Qt
#include <QGraphicsSceneResizeEvent>
#include <QGraphicsGridLayout>
#include <QGraphicsScene>
#include <QApplication>
#include <QKeyEvent>
#include <QWidget>
#include <QTimer>
#include <QTime>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include <QLabel>
//KDE
#include <kmimetype.h>
#include <kdebug.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <ktextedit.h>
#include <ktextbrowser.h>
//Plasma
#include <plasma/widgets/scrollbar.h>
#include <plasma/widgets/svgwidget.h>
#include <plasma/widgets/label.h>
#include <plasma/widgets/textedit.h>
#include <plasma/widgets/textbrowser.h>
#include <plasma/animator.h>
#include <plasma/svg.h>
#define DEBUG 0
/*
The flicking code is largely based on the behavior of
the flickable widget in QDeclerative so porting between
the two should preserve the behavior.
The code that figures out velocity could use some
improvements, in particular IGNORE_SUSPICIOUS_MOVES
is a hack that shouldn't be necessary.
*/
//XXX fixme
// we use a timer between move events to figure out
// the velocity of a move, but sometimes we're getting move
// events with big positional changes with no break
// in between them, which causes us to compute
// huge velocities. this define just filters out
// events which come at insanly small time intervals.
// at some point we need to figure out how to do it properly
#define IGNORE_SUSPICIOUS_MOVES 1
// FlickThreshold determines how far the "mouse" must have moved
// before we perform a flick.
static const int FlickThreshold = 20;
static const qreal MinimumFlickVelocity = 200;
static const qreal MaxVelocity = 2000;
// time it takes the widget to flick back to its
// bounds when overshot
static const qreal FixupDuration = 600;
namespace Plasma
{
class ScrollWidgetPrivate
{
public:
enum Gesture {
GestureNone = 0,
GestureUndefined,
GestureScroll,
GestureZoom
};
ScrollWidgetPrivate(ScrollWidget *parent)
: q(parent),
topBorder(0),
bottomBorder(0),
leftBorder(0),
rightBorder(0),
dragging(false),
overflowBordersVisible(true),
multitouchGesture(GestureNone)
{
}
~ScrollWidgetPrivate()
{
}
void commonConstructor()
{
q->setFocusPolicy(Qt::StrongFocus);
q->setFiltersChildEvents(true);
layout = new QGraphicsGridLayout(q);
q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->setContentsMargins(0, 0, 0, 0);
scrollingWidget = new QGraphicsWidget(q);
scrollingWidget->setFlag(QGraphicsItem::ItemHasNoContents);
scrollingWidget->installEventFilter(q);
layout->addItem(scrollingWidget, 0, 0);
borderSvg = new Plasma::Svg(q);
borderSvg->setImagePath("widgets/scrollwidget");
adjustScrollbarsTimer = new QTimer(q);
adjustScrollbarsTimer->setSingleShot(true);
QObject::connect(adjustScrollbarsTimer, SIGNAL(timeout()), q, SLOT(adjustScrollbars()));
wheelTimer = new QTimer(q);
wheelTimer->setSingleShot(true);
verticalScrollBarPolicy = Qt::ScrollBarAsNeeded;
verticalScrollBar = new Plasma::ScrollBar(q);
verticalScrollBar->setFocusPolicy(Qt::NoFocus);
layout->addItem(verticalScrollBar, 0, 1);
verticalScrollBar->nativeWidget()->setMinimum(0);
verticalScrollBar->nativeWidget()->setMaximum(100);
QObject::connect(verticalScrollBar, SIGNAL(valueChanged(int)), q, SLOT(verticalScroll(int)));
horizontalScrollBarPolicy = Qt::ScrollBarAsNeeded;
horizontalScrollBar = new Plasma::ScrollBar(q);
verticalScrollBar->setFocusPolicy(Qt::NoFocus);
horizontalScrollBar->setOrientation(Qt::Horizontal);
layout->addItem(horizontalScrollBar, 1, 0);
horizontalScrollBar->nativeWidget()->setMinimum(0);
horizontalScrollBar->nativeWidget()->setMaximum(100);
QObject::connect(horizontalScrollBar, SIGNAL(valueChanged(int)), q, SLOT(horizontalScroll(int)));
layout->setColumnSpacing(0, 0);
layout->setColumnSpacing(1, 0);
layout->setRowSpacing(0, 0);
layout->setRowSpacing(1, 0);
flickAnimationX = 0;
flickAnimationY = 0;
fixupAnimation.groupX = 0;
fixupAnimation.startX = 0;
fixupAnimation.endX = 0;
fixupAnimation.groupY = 0;
fixupAnimation.startY = 0;
fixupAnimation.endY = 0;
fixupAnimation.snapX = 0;
fixupAnimation.snapY = 0;
directMoveAnimation = 0;
stealEvent = false;
hasOvershoot = true;
alignment = Qt::AlignLeft | Qt::AlignTop;
hasContentsProperty = false;
hasOffsetProperty = false;
hasXProperty = false;
hasYProperty = false;
}
void adjustScrollbars()
{
if (!widget) {
return;
}
const bool verticalVisible = widget.data()->size().height() > q->size().height();
const bool horizontalVisible = widget.data()->size().width() > q->size().width();
verticalScrollBar->nativeWidget()->setMaximum(qMax(0, int((widget.data()->size().height() - scrollingWidget->size().height())/10)));
verticalScrollBar->nativeWidget()->setPageStep(int(scrollingWidget->size().height())/10);
if (verticalScrollBarPolicy == Qt::ScrollBarAlwaysOff ||
!verticalVisible) {
if (layout->count() > 2 && layout->itemAt(2) == verticalScrollBar) {
layout->removeAt(2);
} else if (layout->count() > 1 && layout->itemAt(1) == verticalScrollBar) {
layout->removeAt(1);
}
verticalScrollBar->hide();
} else if (!verticalScrollBar->isVisible()) {
layout->addItem(verticalScrollBar, 0, 1);
verticalScrollBar->show();
}
horizontalScrollBar->nativeWidget()->setMaximum(qMax(0, int((widget.data()->size().width() - scrollingWidget->size().width())/10)));
horizontalScrollBar->nativeWidget()->setPageStep(int(scrollingWidget->size().width())/10);
if (horizontalScrollBarPolicy == Qt::ScrollBarAlwaysOff ||
!horizontalVisible) {
if (layout->count() > 2 && layout->itemAt(2) == horizontalScrollBar) {
layout->removeAt(2);
} else if (layout->count() > 1 && layout->itemAt(1) == horizontalScrollBar) {
layout->removeAt(1);
}
horizontalScrollBar->hide();
} else if (!horizontalScrollBar->isVisible()) {
layout->addItem(horizontalScrollBar, 1, 0);
horizontalScrollBar->show();
}
if (widget && !topBorder && verticalVisible) {
topBorder = new Plasma::SvgWidget(q);
topBorder->setSvg(borderSvg);
topBorder->setElementID("border-top");
topBorder->setZValue(900);
topBorder->resize(topBorder->effectiveSizeHint(Qt::PreferredSize));
topBorder->setVisible(overflowBordersVisible);
bottomBorder = new Plasma::SvgWidget(q);
bottomBorder->setSvg(borderSvg);
bottomBorder->setElementID("border-bottom");
bottomBorder->setZValue(900);
bottomBorder->resize(bottomBorder->effectiveSizeHint(Qt::PreferredSize));
bottomBorder->setVisible(overflowBordersVisible);
} else if (topBorder && widget && !verticalVisible) {
//FIXME: in some cases topBorder->deleteLater() is deleteNever(), why?
topBorder->hide();
bottomBorder->hide();
topBorder->deleteLater();
bottomBorder->deleteLater();
topBorder = 0;
bottomBorder = 0;
}
if (widget && !leftBorder && horizontalVisible) {
leftBorder = new Plasma::SvgWidget(q);
leftBorder->setSvg(borderSvg);
leftBorder->setElementID("border-left");
leftBorder->setZValue(900);
leftBorder->resize(leftBorder->effectiveSizeHint(Qt::PreferredSize));
leftBorder->setVisible(overflowBordersVisible);
rightBorder = new Plasma::SvgWidget(q);
rightBorder->setSvg(borderSvg);
rightBorder->setElementID("border-right");
rightBorder->setZValue(900);
rightBorder->resize(rightBorder->effectiveSizeHint(Qt::PreferredSize));
rightBorder->setVisible(overflowBordersVisible);
} else if (leftBorder && widget && !horizontalVisible) {
leftBorder->hide();
rightBorder->hide();
leftBorder->deleteLater();
rightBorder->deleteLater();
leftBorder = 0;
rightBorder = 0;
}
layout->activate();
if (topBorder) {
topBorder->resize(q->size().width(), topBorder->size().height());
bottomBorder->resize(q->size().width(), bottomBorder->size().height());
bottomBorder->setPos(0, q->size().height() - topBorder->size().height());
}
if (leftBorder) {
leftBorder->resize(leftBorder->size().width(), q->size().height());
rightBorder->resize(rightBorder->size().width(), q->size().height());
rightBorder->setPos(q->size().width() - rightBorder->size().width(), 0);
}
QSizeF widgetSize = widget.data()->size();
if (widget.data()->sizePolicy().expandingDirections() & Qt::Horizontal) {
//keep a 1 pixel border
widgetSize.setWidth(scrollingWidget->size().width());
}
if (widget.data()->sizePolicy().expandingDirections() & Qt::Vertical) {
widgetSize.setHeight(scrollingWidget->size().height());
}
widget.data()->resize(widgetSize);
adjustClipping();
}
void verticalScroll(int value)
{
if (!widget) {
return;
}
if (!dragging) {
widget.data()->setPos(QPoint(widget.data()->pos().x(), -value*10));
}
}
void horizontalScroll(int value)
{
if (!widget) {
return;
}
if (!dragging) {
widget.data()->setPos(QPoint(-value*10, widget.data()->pos().y()));
}
}
void adjustClipping()
{
if (!widget) {
return;
}
const bool clip = widget.data()->size().width() > scrollingWidget->size().width() || widget.data()->size().height() > scrollingWidget->size().height();
scrollingWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, clip);
}
qreal overShootDistance(qreal velocity, qreal size) const
{
if (MaxVelocity <= 0)
return 0.0;
velocity = qAbs(velocity);
if (velocity > MaxVelocity)
velocity = MaxVelocity;
qreal dist = size / 4 * velocity / MaxVelocity;
return dist;
}
void animateMoveTo(const QPointF &pos)
{
qreal duration = 800;
QPointF start = q->scrollPosition();
QSizeF threshold = q->viewportGeometry().size();
QPointF diff = pos - start;
//reduce if it's within the viewport
if (qAbs(diff.x()) < threshold.width() ||
qAbs(diff.y()) < threshold.height())
duration /= 2;
fixupAnimation.groupX->stop();
fixupAnimation.groupY->stop();
fixupAnimation.snapX->stop();
fixupAnimation.snapY->stop();
directMoveAnimation->setStartValue(start);
directMoveAnimation->setEndValue(pos);
directMoveAnimation->setDuration(duration);
directMoveAnimation->start();
}
void flick(QPropertyAnimation *anim,
qreal velocity,
qreal val,
qreal minExtent,
qreal maxExtent,
qreal size)
{
qreal deceleration = 500;
qreal maxDistance = -1;
qreal target = 0;
// -ve velocity means list is moving up
if (velocity > 0) {
if (val < minExtent)
maxDistance = qAbs(minExtent - val + (hasOvershoot?overShootDistance(velocity,size):0));
target = minExtent;
deceleration = -deceleration;
} else {
if (val > maxExtent)
maxDistance = qAbs(maxExtent - val) + (hasOvershoot?overShootDistance(velocity,size):0);
target = maxExtent;
}
if (maxDistance > 0) {
qreal v = velocity;
if (MaxVelocity != -1 && MaxVelocity < qAbs(v)) {
if (v < 0)
v = -MaxVelocity;
else
v = MaxVelocity;
}
qreal duration = qAbs(v / deceleration);
qreal diffY = v * duration + (0.5 * deceleration * duration * duration);
qreal startY = val;
qreal endY = startY + diffY;
if (velocity > 0) {
if (endY > target)
endY = startY + maxDistance;
} else {
if (endY < target)
endY = startY - maxDistance;
}
duration = qAbs((endY-startY)/ (-v/2));
if (hasYProperty) {
startY = -startY;
endY = -endY;
}
#if DEBUG
qDebug()<<"XXX velocity = "<<v <<", target = "<< target
<<", maxDist = "<<maxDistance;
qDebug()<<"duration = "<<duration<<" secs, ("
<< (duration * 1000) <<" msecs)";
qDebug()<<"startY = "<<startY;
qDebug()<<"endY = "<<endY;
qDebug()<<"overshoot = "<<overShootDistance(v, size);
qDebug()<<"avg velocity = "<< ((endY-startY)/duration);
#endif
anim->setStartValue(startY);
anim->setEndValue(endY);
anim->setDuration(duration * 1000);
anim->start();
} else {
if (anim == flickAnimationX)
fixupX();
else
fixupY();
}
}
void flickX(qreal velocity)
{
flick(flickAnimationX, velocity, widgetX(), minXExtent(), maxXExtent(),
q->viewportGeometry().width());
}
void flickY(qreal velocity)
{
flick(flickAnimationY, velocity, widgetY(),minYExtent(), maxYExtent(),
q->viewportGeometry().height());
}
void fixup(QAnimationGroup *group,
QPropertyAnimation *start, QPropertyAnimation *end,
qreal val, qreal minExtent, qreal maxExtent)
{
if (val > minExtent || maxExtent > minExtent) {
if (!qFuzzyCompare(val, minExtent)) {
if (FixupDuration) {
//TODO: we should consider the case where there is one axis available not the other
if (hasXProperty && hasYProperty) {
val = -val;
minExtent = -minExtent;
}
qreal dist = minExtent - val;
start->setStartValue(val);
start->setEndValue(minExtent - dist/2);
end->setStartValue(minExtent - dist/2);
end->setEndValue(minExtent);
start->setDuration(FixupDuration/4);
end->setDuration(3*FixupDuration/4);
group->start();
} else {
QObject *obj = start->targetObject();
obj->setProperty(start->propertyName(), minExtent);
}
}
} else if (val < maxExtent) {
if (FixupDuration) {
if (hasXProperty && hasYProperty) {
val = -val;
maxExtent = -maxExtent;
}
qreal dist = maxExtent - val;
start->setStartValue(val);
start->setEndValue(maxExtent - dist/2);
end->setStartValue(maxExtent - dist/2);
end->setEndValue(maxExtent);
start->setDuration(FixupDuration/4);
end->setDuration(3*FixupDuration/4);
group->start();
} else {
QObject *obj = start->targetObject();
obj->setProperty(start->propertyName(), maxExtent);
}
} else if (end == fixupAnimation.endX && snapSize.width() > 1 &&
q->contentsSize().width() > q->viewportGeometry().width()) {
int target = snapSize.width() * round(val/snapSize.width());
fixupAnimation.snapX->setStartValue(val);
fixupAnimation.snapX->setEndValue(target);
fixupAnimation.snapX->setDuration(FixupDuration);
fixupAnimation.snapX->start();
} else if (end == fixupAnimation.endY && snapSize.height() > 1 &&
q->contentsSize().height() > q->viewportGeometry().height()) {
int target = snapSize.height() * round(val/snapSize.height());
fixupAnimation.snapY->setStartValue(val);
fixupAnimation.snapY->setEndValue(target);
fixupAnimation.snapY->setDuration(FixupDuration);
fixupAnimation.snapY->start();
}
}
void fixupX()
{
fixup(fixupAnimation.groupX, fixupAnimation.startX, fixupAnimation.endX,
widgetX(), minXExtent(), maxXExtent());
}
void fixupY()
{
fixup(fixupAnimation.groupY, fixupAnimation.startY, fixupAnimation.endY,
widgetY(), minYExtent(), maxYExtent());
}
void makeRectVisible()
{
if (!widget) {
return;
}
QRectF viewRect = scrollingWidget->boundingRect();
//ensure the rect is not outside the widget bounding rect
QRectF mappedRect = QRectF(QPointF(qBound((qreal)0.0, rectToBeVisible.x(), widget.data()->size().width() - rectToBeVisible.width()),
qBound((qreal)0.0, rectToBeVisible.y(), widget.data()->size().height() - rectToBeVisible.height())),
rectToBeVisible.size());
mappedRect = widget.data()->mapToItem(scrollingWidget, mappedRect).boundingRect();
if (viewRect.contains(mappedRect)) {
return;
}
QPointF delta(0, 0);
if (mappedRect.top() < 0) {
delta.setY(-mappedRect.top());
} else if (mappedRect.bottom() > viewRect.bottom()) {
delta.setY(viewRect.bottom() - mappedRect.bottom());
}
if (mappedRect.left() < 0) {
delta.setX(-mappedRect.left());
} else if (mappedRect.right() > viewRect.right()) {
delta.setX(viewRect.right() - mappedRect.right());
}
animateMoveTo(q->scrollPosition() - delta);
}
void makeItemVisible(QGraphicsItem *itemToBeVisible)
{
if (!widget) {
return;
}
QRectF rect(widget.data()->mapFromScene(itemToBeVisible->scenePos()), itemToBeVisible->boundingRect().size());
rectToBeVisible = rect;
makeRectVisible();
}
void makeItemVisible()
{
if (widgetToBeVisible) {
makeItemVisible(widgetToBeVisible.data());
}
}
void stopAnimations()
{
flickAnimationX->stop();
flickAnimationY->stop();
fixupAnimation.groupX->stop();
fixupAnimation.groupY->stop();
}
void setWidgetX(qreal x)
{
if (hasXProperty) {
widget.data()->setProperty("scrollPositionX", -x);
} else
widget.data()->setX(x);
}
void setWidgetY(qreal y)
{
if (hasYProperty) {
widget.data()->setProperty("scrollPositionY", -y);
} else
widget.data()->setY(y);
}
qreal widgetX() const
{
if (hasXProperty) {
return -widget.data()->property("scrollPositionX").toReal();
} else
return widget.data()->x();
}
qreal widgetY() const
{
if (hasYProperty) {
return -widget.data()->property("scrollPositionY").toReal();
} else
return widget.data()->y();
}
void handleKeyPressEvent(QKeyEvent *event)
{
if (!widget.data()) {
event->ignore();
return;
}
QPointF start = q->scrollPosition();
QPointF end = start;
qreal step = 100;
switch (event->key()) {
case Qt::Key_Left:
if (canXFlick()) {
end += QPointF(-step, 0);
}
break;
case Qt::Key_Right:
if (canXFlick()) {
end += QPointF(step, 0);
}
break;
case Qt::Key_Up:
if (canYFlick()) {
end += QPointF(0, -step);
}
break;
case Qt::Key_Down:
if (canYFlick()) {
end += QPointF(0, step);
}
break;
default:
event->ignore();
return;
}
fixupAnimation.groupX->stop();
fixupAnimation.groupY->stop();
fixupAnimation.snapX->stop();
fixupAnimation.snapY->stop();
directMoveAnimation->setStartValue(start);
directMoveAnimation->setEndValue(end);
directMoveAnimation->setDuration(200);
directMoveAnimation->start();
}
void handleMousePressEvent(QGraphicsSceneMouseEvent *event)
{
lastPos = QPoint();
lastPosTime = QTime::currentTime();
pressPos = event->scenePos();
pressScrollPos = -q->scrollPosition();
pressTime = QTime::currentTime();
velocity = QPointF();
stopAnimations();
}
void handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (lastPosTime.isNull())
return;
bool rejectY = false;
bool rejectX = false;
bool moved = false;
if (canYFlick()) {
int dy = int(event->scenePos().y() - pressPos.y());
if (qAbs(dy) > KGlobalSettings::dndEventDelay() || elapsed(pressTime) > 200) {
qreal newY = dy + pressScrollPos.y();
const qreal minY = minYExtent();
const qreal maxY = maxYExtent();
if (newY > minY)
newY = minY + (newY - minY) / 2;
if (newY < maxY && maxY - minY <= 0)
newY = maxY + (newY - maxY) / 2;
if (!hasOvershoot && (newY > minY || newY < maxY)) {
if (newY > minY)
newY = minY;
else if (newY < maxY)
newY = maxY;
else
rejectY = true;
}
if (!rejectY && stealEvent) {
setWidgetY(qRound(newY));
moved = true;
}
if (qAbs(dy) > KGlobalSettings::dndEventDelay())
stealEvent = true;
}
}
if (canXFlick()) {
int dx = int(event->scenePos().x() - pressPos.x());
if (qAbs(dx) > KGlobalSettings::dndEventDelay() || elapsed(pressTime) > 200) {
qreal newX = dx + pressScrollPos.x();
const qreal minX = minXExtent();
const qreal maxX = maxXExtent();
if (newX > minX)
newX = minX + (newX - minX) / 2;
if (newX < maxX && maxX - minX <= 0)
newX = maxX + (newX - maxX) / 2;
if (!hasOvershoot && (newX > minX || newX < maxX)) {
if (newX > minX)
newX = minX;
else if (newX < maxX)
newX = maxX;
else
rejectX = true;
}
if (!rejectX && stealEvent) {
setWidgetX(qRound(newX));
moved = true;
}
if (qAbs(dx) > KGlobalSettings::dndEventDelay())
stealEvent = true;
}
}
if (!lastPos.isNull()) {
qreal msecs = qreal(restart(lastPosTime));
qreal elapsed = msecs / 1000.;
#if IGNORE_SUSPICIOUS_MOVES
if (msecs > 3) {
#endif
if (elapsed <= 0)
elapsed = 1;
if (canYFlick()) {
qreal diff = event->scenePos().y() - lastPos.y();
// average to reduce the effect of spurious moves
velocity.setY( velocity.y() + (diff / elapsed) );
velocity.setY( velocity.y() / 2 );
}
if (canXFlick()) {
qreal diff = event->scenePos().x() - lastPos.x();
// average to reduce the effect of spurious moves
velocity.setX( velocity.x() + (diff / elapsed) );
velocity.setX( velocity.x() / 2 );
}
#if IGNORE_SUSPICIOUS_MOVES
}
#endif
}
if (rejectX) velocity.setX(0);
if (rejectY) velocity.setY(0);
lastPos = event->scenePos();
}
void handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
stealEvent = false;
if (lastPosTime.isNull())
return;
if (elapsed(lastPosTime) > 100) {
// if we drag then pause before release we should not cause a flick.
velocity = QPointF();
}
if (qAbs(velocity.y()) > 10 &&
qAbs(event->scenePos().y() - pressPos.y()) > FlickThreshold) {
qreal vVelocity = velocity.y();
// Minimum velocity to avoid annoyingly slow flicks.
if (qAbs(vVelocity) < MinimumFlickVelocity)
vVelocity = vVelocity < 0 ? -MinimumFlickVelocity : MinimumFlickVelocity;
flickY(vVelocity);
} else {
fixupY();
}
if (qAbs(velocity.x()) > 10 &&
qAbs(event->scenePos().x() - pressPos.x()) > FlickThreshold) {
qreal hVelocity = velocity.x();
// Minimum velocity to avoid annoyingly slow flicks.
if (qAbs(hVelocity) < MinimumFlickVelocity)
hVelocity = hVelocity < 0 ? -MinimumFlickVelocity : MinimumFlickVelocity;
flickX(hVelocity);
} else {
fixupX();
}
lastPosTime = QTime();
}
void handleWheelEvent(QGraphicsSceneWheelEvent *event)
{
//only scroll when the animation is done, this avoids to receive too many events and getting mad when they arrive from a touchpad
if (!widget.data() || wheelTimer->isActive()) {
return;
}
QPointF start = q->scrollPosition();
QPointF end = start;
//At some point we should switch to
// step = QApplication::wheelScrollLines() *
// (event->delta()/120) *
// scrollBar->singleStep();
// which gives us exactly the number of lines to scroll but the issue
// is that at this point we don't have any clue what a "line" is and if
// we make it a pixel then scrolling by 3 (default) pixels will be
// very painful
qreal step = -event->delta()/3;
//ifthe widget can scroll in a single axis and the wheel is the other one, scroll the other one
Qt::Orientation orientation = event->orientation();
if (orientation == Qt::Vertical) {
if (!canYFlick() && canXFlick()) {
end += QPointF(step, 0);
} else if (canYFlick()) {
end += QPointF(0, step);
} else {
return;
}
} else {
if (canYFlick() && !canXFlick()) {
end += QPointF(0, step);
} else if (canXFlick()) {
end += QPointF(step, 0);
} else {
return;
}
}
fixupAnimation.groupX->stop();
fixupAnimation.groupY->stop();
fixupAnimation.snapX->stop();
fixupAnimation.snapY->stop();
directMoveAnimation->setStartValue(start);
directMoveAnimation->setEndValue(end);
directMoveAnimation->setDuration(200);
directMoveAnimation->start();
wheelTimer->start(50);
}
qreal minXExtent() const
{
if (alignment & Qt::AlignLeft)
return 0;
else {
qreal vWidth = q->viewportGeometry().width();
qreal cWidth = q->contentsSize().width();
if (cWidth < vWidth) {
if (alignment & Qt::AlignRight)
return vWidth - cWidth;
else if (alignment & Qt::AlignHCenter)
return vWidth / 2 - cWidth / 2;
}
}
return 0;
}
qreal maxXExtent() const
{
return q->viewportGeometry().width() -
q->contentsSize().width();
}
qreal minYExtent() const
{
if (alignment & Qt::AlignTop)
return 0;
else {
qreal vHeight = q->viewportGeometry().height();
qreal cHeight = q->contentsSize().height();
if (cHeight < vHeight) {
if (alignment & Qt::AlignBottom)
return vHeight - cHeight;
else if (alignment & Qt::AlignVCenter)
return vHeight / 2 - cHeight / 2;
}
}
return 0;
}
qreal maxYExtent() const
{
return q->viewportGeometry().height() -
q->contentsSize().height();
}
bool canXFlick() const
{
//make the thing feel quite "fixed" don't permit to flick when the contents size is less than the viewport
return q->contentsSize().width() > q->viewportGeometry().width();
}
bool canYFlick() const
{
return q->contentsSize().height() > q->viewportGeometry().height();
}
int elapsed(const QTime &t) const
{
int n = t.msecsTo(QTime::currentTime());
if (n < 0) // passed midnight
n += 86400 * 1000;
return n;
}
int restart(QTime &t) const
{
QTime time = QTime::currentTime();
int n = t.msecsTo(time);
if (n < 0) // passed midnight
n += 86400*1000;
t = time;
return n;
}
void createFlickAnimations()
{
if (widget.data()) {
QString xProp = QString::fromLatin1("x");
QString yProp = QString::fromLatin1("y");
if (hasXProperty)
xProp = QString::fromLatin1("scrollPositionX");
if (hasYProperty)
yProp = QString::fromLatin1("scrollPositionY");
flickAnimationX = new QPropertyAnimation(widget.data(),
xProp.toLatin1(), widget.data());
flickAnimationY = new QPropertyAnimation(widget.data(),
yProp.toLatin1(), widget.data());
QObject::connect(flickAnimationX, SIGNAL(finished()),
q, SLOT(fixupX()));
QObject::connect(flickAnimationY, SIGNAL(finished()),
q, SLOT(fixupY()));
QObject::connect(flickAnimationX,
SIGNAL(stateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)),
q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)));
QObject::connect(flickAnimationY,
SIGNAL(stateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)),
q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)));
flickAnimationX->setEasingCurve(QEasingCurve::OutCirc);
flickAnimationY->setEasingCurve(QEasingCurve::OutCirc);
fixupAnimation.groupX = new QSequentialAnimationGroup(widget.data());
fixupAnimation.groupY = new QSequentialAnimationGroup(widget.data());
fixupAnimation.startX = new QPropertyAnimation(widget.data(),
xProp.toLatin1(), widget.data());
fixupAnimation.startY = new QPropertyAnimation(widget.data(),
yProp.toLatin1(), widget.data());
fixupAnimation.endX = new QPropertyAnimation(widget.data(),
xProp.toLatin1(), widget.data());
fixupAnimation.endY = new QPropertyAnimation(widget.data(),
yProp.toLatin1(), widget.data());
fixupAnimation.groupX->addAnimation(
fixupAnimation.startX);
fixupAnimation.groupY->addAnimation(
fixupAnimation.startY);
fixupAnimation.groupX->addAnimation(
fixupAnimation.endX);
fixupAnimation.groupY->addAnimation(
fixupAnimation.endY);
fixupAnimation.startX->setEasingCurve(QEasingCurve::InQuad);
fixupAnimation.endX->setEasingCurve(QEasingCurve::OutQuint);
fixupAnimation.startY->setEasingCurve(QEasingCurve::InQuad);
fixupAnimation.endY->setEasingCurve(QEasingCurve::OutQuint);
fixupAnimation.snapX = new QPropertyAnimation(widget.data(),
xProp.toLatin1(), widget.data());
fixupAnimation.snapY = new QPropertyAnimation(widget.data(),
yProp.toLatin1(), widget.data());
fixupAnimation.snapX->setEasingCurve(QEasingCurve::InOutQuad);
fixupAnimation.snapY->setEasingCurve(QEasingCurve::InOutQuad);
QObject::connect(fixupAnimation.groupX,
SIGNAL(stateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)),
q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)));
QObject::connect(fixupAnimation.groupY,
SIGNAL(stateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)),
q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)));
directMoveAnimation = new QPropertyAnimation(q,
"scrollPosition",
q);
QObject::connect(directMoveAnimation, SIGNAL(finished()),
q, SLOT(fixupX()));
QObject::connect(directMoveAnimation, SIGNAL(finished()),
q, SLOT(fixupY()));
QObject::connect(directMoveAnimation,
SIGNAL(stateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)),
q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
QAbstractAnimation::State)));
directMoveAnimation->setEasingCurve(QEasingCurve::OutCirc);
}
}
void deleteFlickAnimations()
{
if (flickAnimationX)
flickAnimationX->stop();
if (flickAnimationY)
flickAnimationY->stop();
delete flickAnimationX;
delete flickAnimationY;
delete fixupAnimation.groupX;
delete fixupAnimation.groupY;
delete directMoveAnimation;
delete fixupAnimation.snapX;
delete fixupAnimation.snapY;
}
void setScrollX()
{
if (horizontalScrollBarPolicy != Qt::ScrollBarAlwaysOff) {
horizontalScrollBar->blockSignals(true);
horizontalScrollBar->setValue(-widget.data()->pos().x()/10.);
horizontalScrollBar->blockSignals(false);
}
}
void setScrollY()
{
if (verticalScrollBarPolicy != Qt::ScrollBarAlwaysOff) {
verticalScrollBar->blockSignals(true);
verticalScrollBar->setValue(-widget.data()->pos().y()/10.);
verticalScrollBar->blockSignals(false);
}
}
ScrollWidget *q;
QGraphicsWidget *scrollingWidget;
QWeakPointer<QGraphicsWidget> widget;
Plasma::Svg *borderSvg;
Plasma::SvgWidget *topBorder;
Plasma::SvgWidget *bottomBorder;
Plasma::SvgWidget *leftBorder;
Plasma::SvgWidget *rightBorder;
QGraphicsGridLayout *layout;
ScrollBar *verticalScrollBar;
Qt::ScrollBarPolicy verticalScrollBarPolicy;
ScrollBar *horizontalScrollBar;
Qt::ScrollBarPolicy horizontalScrollBarPolicy;
QString styleSheet;
QWeakPointer<QGraphicsWidget> widgetToBeVisible;
QRectF rectToBeVisible;
QPointF dragHandleClicked;
bool dragging;
QTimer *adjustScrollbarsTimer;
QTimer *wheelTimer;
QPointF pressPos;
QPointF pressScrollPos;
QPointF velocity;
QPointF lastPos;
QTime pressTime;
QTime lastPosTime;
QPropertyAnimation *flickAnimationX;
QPropertyAnimation *flickAnimationY;
struct {
QAnimationGroup *groupX;
QPropertyAnimation *startX;
QPropertyAnimation *endX;
QAnimationGroup *groupY;
QPropertyAnimation *startY;
QPropertyAnimation *endY;
QPropertyAnimation *snapX;
QPropertyAnimation *snapY;
} fixupAnimation;
QPropertyAnimation *directMoveAnimation;
QSizeF snapSize;
bool stealEvent;
bool hasOvershoot;
bool overflowBordersVisible;
Qt::Alignment alignment;
Gesture multitouchGesture;
bool hasContentsProperty;
bool hasOffsetProperty;
bool hasXProperty;
bool hasYProperty;
};
ScrollWidget::ScrollWidget(QGraphicsItem *parent)
: QGraphicsWidget(parent),
d(new ScrollWidgetPrivate(this))
{
d->commonConstructor();
}
ScrollWidget::ScrollWidget(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new ScrollWidgetPrivate(this))
{
d->commonConstructor();
}
ScrollWidget::~ScrollWidget()
{
delete d;
}
void ScrollWidget::setWidget(QGraphicsWidget *widget)
{
if (d->widget && d->widget.data() != widget) {
d->deleteFlickAnimations();
d->widget.data()->removeEventFilter(this);
delete d->widget.data();
}
d->widget = widget;
//it's not good it's setting a size policy here, but it's done to be retrocompatible with older applications
if (widget) {
d->hasContentsProperty = widget->property("contentsSize").isValid();
d->hasOffsetProperty = widget->property("scrollPosition").isValid();
d->hasXProperty = widget->property("scrollPositionX").isValid();
d->hasYProperty = widget->property("scrollPositionY").isValid();
d->createFlickAnimations();
connect(widget, SIGNAL(xChanged()), this, SLOT(setScrollX()));
connect(widget, SIGNAL(yChanged()), this, SLOT(setScrollY()));
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
widget->setParentItem(d->scrollingWidget);
widget->setPos(d->minXExtent(), d->minYExtent());
widget->installEventFilter(this);
d->adjustScrollbarsTimer->start(200);
}
}
QGraphicsWidget *ScrollWidget::widget() const
{
return d->widget.data();
}
void ScrollWidget::setHorizontalScrollBarPolicy(const Qt::ScrollBarPolicy policy)
{
d->horizontalScrollBarPolicy = policy;
}
Qt::ScrollBarPolicy ScrollWidget::horizontalScrollBarPolicy() const
{
return d->horizontalScrollBarPolicy;
}
void ScrollWidget::setVerticalScrollBarPolicy(const Qt::ScrollBarPolicy policy)
{
d->verticalScrollBarPolicy = policy;
}
Qt::ScrollBarPolicy ScrollWidget::verticalScrollBarPolicy() const
{
return d->verticalScrollBarPolicy;
}
bool ScrollWidget::overflowBordersVisible() const
{
return d->overflowBordersVisible;
}
void ScrollWidget::setOverflowBordersVisible(const bool visible)
{
if (d->overflowBordersVisible == visible) {
return;
}
d->overflowBordersVisible = visible;
d->adjustScrollbars();
}
void ScrollWidget::ensureRectVisible(const QRectF &rect)
{
if (!d->widget) {
return;
}
d->rectToBeVisible = rect;
d->makeRectVisible();
}
void ScrollWidget::ensureItemVisible(QGraphicsItem *item)
{
if (!d->widget || !item) {
return;
}
QGraphicsItem *parentOfItem = item->parentItem();
while (parentOfItem != d->widget.data()) {
if (!parentOfItem) {
return;
}
parentOfItem = parentOfItem->parentItem();
}
//since we can't ensure it'll stay alive we can delay only if it's a qgraphicswidget
QGraphicsWidget *widget = qgraphicsitem_cast<QGraphicsWidget *>(item);
if (widget) {
d->widgetToBeVisible = widget;
// We need to wait for the parent item to resize...
QTimer::singleShot(0, this, SLOT(makeItemVisible()));
} else {
d->makeItemVisible(item);
}
}
QRectF ScrollWidget::viewportGeometry() const
{
QRectF result;
if (!d->widget) {
return result;
}
return d->scrollingWidget->boundingRect();
}
QSizeF ScrollWidget::contentsSize() const
{
if (d->widget) {
if (d->hasContentsProperty) {
QVariant var = d->widget.data()->property("contentsSize");
return var.toSizeF();
} else
return d->widget.data()->size();
}
return QSizeF();
}
void ScrollWidget::setScrollPosition(const QPointF &position)
{
if (d->widget) {
if (d->hasOffsetProperty)
d->widget.data()->setProperty("scrollPosition", position);
else
d->widget.data()->setPos(-position.toPoint());
}
}
QPointF ScrollWidget::scrollPosition() const
{
if (d->widget) {
if (d->hasOffsetProperty) {
QVariant var = d->widget.data()->property("scrollPosition");
return var.toPointF();
} else {
return -d->widget.data()->pos();
}
}
return QPointF();
}
void ScrollWidget::setSnapSize(const QSizeF &size)
{
d->snapSize = size;
}
QSizeF ScrollWidget::snapSize() const
{
return d->snapSize;
}
void ScrollWidget::setStyleSheet(const QString &styleSheet)
{
d->styleSheet = styleSheet;
d->verticalScrollBar->setStyleSheet(styleSheet);
d->horizontalScrollBar->setStyleSheet(styleSheet);
}
QString ScrollWidget::styleSheet() const
{
return d->styleSheet;
}
QWidget *ScrollWidget::nativeWidget() const
{
return 0;
}
void ScrollWidget::focusInEvent(QFocusEvent *event)
{
Q_UNUSED(event)
if (d->widget) {
d->widget.data()->setFocus();
}
}
void ScrollWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
{
if (!d->widget) {
QGraphicsWidget::resizeEvent(event);
return;
}
d->adjustScrollbarsTimer->start(200);
//if topBorder exists bottomBorder too
if (d->topBorder) {
d->topBorder->resize(event->newSize().width(), d->topBorder->size().height());
d->bottomBorder->resize(event->newSize().width(), d->bottomBorder->size().height());
d->bottomBorder->setPos(0, event->newSize().height() - d->bottomBorder->size().height());
}
if (d->leftBorder) {
d->leftBorder->resize(d->leftBorder->size().width(), event->newSize().height());
d->rightBorder->resize(d->rightBorder->size().width(), event->newSize().height());
d->rightBorder->setPos(event->newSize().width() - d->rightBorder->size().width(), 0);
}
QGraphicsWidget::resizeEvent(event);
}
void ScrollWidget::keyPressEvent(QKeyEvent *event)
{
d->handleKeyPressEvent(event);
}
void ScrollWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (!d->widget) {
return;
}
d->handleMouseMoveEvent(event);
event->accept();
return QGraphicsWidget::mouseMoveEvent(event);
}
void ScrollWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (!d->widget) {
return;
} else if (!d->canYFlick() && !d->canXFlick()) {
event->ignore();
return;
}
d->handleMousePressEvent(event);
if (event->button() == Qt::LeftButton) {
event->accept();
} else {
QGraphicsWidget::mousePressEvent(event);
}
}
void ScrollWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (!d->widget) {
return;
}
d->handleMouseReleaseEvent(event);
event->accept();
}
void ScrollWidget::wheelEvent(QGraphicsSceneWheelEvent *event)
{
if (!d->widget) {
return;
} else if (!d->canYFlick() && !d->canXFlick()) {
event->ignore();
return;
}
d->handleWheelEvent(event);
event->accept();
}
bool ScrollWidget::eventFilter(QObject *watched, QEvent *event)
{
if (!d->widget) {
return false;
}
if (watched == d->scrollingWidget && (event->type() == QEvent::GraphicsSceneResize ||
event->type() == QEvent::Move)) {
emit viewportGeometryChanged(viewportGeometry());
} else if (watched == d->widget.data() && event->type() == QEvent::GraphicsSceneResize) {
d->stopAnimations();
d->adjustScrollbarsTimer->start(200);
updateGeometry();
QPointF newPos = d->widget.data()->pos();
if (d->widget.data()->size().width() <= viewportGeometry().width()) {
newPos.setX(d->minXExtent());
}
if (d->widget.data()->size().height() <= viewportGeometry().height()) {
newPos.setY(d->minYExtent());
}
//check if the content is visible
if (d->widget.data()->geometry().right() < 0) {
newPos.setX(-d->widget.data()->geometry().width()+viewportGeometry().width());
}
if (d->widget.data()->geometry().bottom() < 0) {
newPos.setY(-d->widget.data()->geometry().height()+viewportGeometry().height());
}
d->widget.data()->setPos(newPos);
} else if (watched == d->widget.data() && event->type() == QEvent::GraphicsSceneMove) {
d->horizontalScrollBar->blockSignals(true);
d->verticalScrollBar->blockSignals(true);
d->horizontalScrollBar->setValue(-d->widget.data()->pos().x()/10);
d->verticalScrollBar->setValue(-d->widget.data()->pos().y()/10);
d->horizontalScrollBar->blockSignals(false);
d->verticalScrollBar->blockSignals(false);
}
return false;
}
QSizeF ScrollWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
if (!d->widget || which == Qt::MaximumSize) {
return QGraphicsWidget::sizeHint(which, constraint);
//FIXME: it should ake the minimum hint of the contained widget, but the result is in a ridiculously big widget
} else if (which == Qt::MinimumSize) {
return QSizeF(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous);
}
QSizeF hint = d->widget.data()->effectiveSizeHint(which, constraint);
if (d->horizontalScrollBar && d->horizontalScrollBar->isVisible()) {
hint += QSize(0, d->horizontalScrollBar->size().height());
}
if (d->verticalScrollBar && d->verticalScrollBar->isVisible()) {
hint += QSize(d->verticalScrollBar->size().width(), 0);
}
return hint;
}
bool ScrollWidget::sceneEventFilter(QGraphicsItem *i, QEvent *e)
{
//only the scrolling widget and its children
if (!d->widget.data() ||
(!d->scrollingWidget->isAncestorOf(i) && i != d->scrollingWidget) ||
i == d->horizontalScrollBar || i == d->verticalScrollBar) {
return false;
}
if (i->isWidget()) {
Plasma::Label *label = dynamic_cast<Plasma::Label *>(static_cast<QGraphicsWidget *>(i));
if (label && (label->nativeWidget()->textInteractionFlags() & Qt::TextSelectableByMouse)) {
return false;
}
Plasma::TextEdit *textEdit = dynamic_cast<Plasma::TextEdit *>(static_cast<QGraphicsWidget *>(i));
if (textEdit && (textEdit->nativeWidget()->textInteractionFlags() & Qt::TextSelectableByMouse)) {
return false;
}
Plasma::TextBrowser *textBrowser= dynamic_cast<Plasma::TextBrowser *>(static_cast<QGraphicsWidget *>(i));
if (textBrowser && (textBrowser->nativeWidget()->textInteractionFlags() & Qt::TextSelectableByMouse)) {
return false;
}
}
bool stealThisEvent = d->stealEvent;
//still pass around mouse moves: try to make still possible to make items start a drag event. thi could be either necessary or annoying, let's see how it goes. (add QEvent::GraphicsSceneMouseMove to block them)
stealThisEvent &= (e->type() == QEvent::GraphicsSceneMousePress ||
e->type() == QEvent::GraphicsSceneMouseRelease);
#if DEBUG
qDebug()<<"sceneEventFilter = " <<i<<", "
<<QTime::currentTime().toString(QString::fromLatin1("hh:mm:ss.zzz"));
#endif
switch (e->type()) {
case QEvent::GraphicsSceneMousePress:
d->handleMousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(e));
break;
case QEvent::GraphicsSceneMouseMove:
d->handleMouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(e));
break;
case QEvent::GraphicsSceneMouseRelease:
d->handleMouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(e));
break;
//Multitouch related events, we actually need only TouchUpdate
case QEvent::TouchUpdate: {
QList<QTouchEvent::TouchPoint> touchPoints = static_cast<QTouchEvent *>(e)->touchPoints();
if (touchPoints.count() == 2) {
const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
const QLineF line0(touchPoint0.lastPos(), touchPoint1.lastPos());
const QLineF line1(touchPoint0.pos(), touchPoint1.pos());
const QLineF startLine(touchPoint0.startPos(), touchPoint1.startPos());
const QPointF point = line1.pointAt(0.5);
const QPointF lastPoint = line0.pointAt(0.5);
if (d->multitouchGesture == ScrollWidgetPrivate::GestureNone) {
d->multitouchGesture = ScrollWidgetPrivate::GestureUndefined;
}
if (d->multitouchGesture == ScrollWidgetPrivate::GestureUndefined) {
const int zoomDistance = qAbs(line1.length() - startLine.length());
const int dragDistance = (startLine.pointAt(0.5) - point).manhattanLength();
if (zoomDistance - dragDistance > 30) {
d->multitouchGesture = ScrollWidgetPrivate::GestureZoom;
} else if (dragDistance - zoomDistance > 30) {
d->multitouchGesture = ScrollWidgetPrivate::GestureScroll;
}
}
if (d->multitouchGesture == ScrollWidgetPrivate::GestureScroll) {
QGraphicsSceneMouseEvent fakeEvent;
fakeEvent.setPos(point);
fakeEvent.setLastPos(lastPoint);
d->handleMouseMoveEvent(&fakeEvent);
} else if (d->multitouchGesture == ScrollWidgetPrivate::GestureZoom) {
if (d->widget && d->widget.data()->property("zoomFactor").isValid()) {
qreal scaleFactor = 1;
if (line0.length() > 0) {
scaleFactor = line1.length() / line0.length();
}
qreal zoom = d->widget.data()->property("zoomFactor").toReal();
d->widget.data()->setProperty("zoomFactor", zoom * scaleFactor);
}
}
}
break;
}
default:
break;
}
if (stealThisEvent)
return true;
return QGraphicsWidget::sceneEventFilter(i, e);
}
void Plasma::ScrollWidget::setAlignment(Qt::Alignment align)
{
d->alignment = align;
if (d->widget.data() &&
d->widget.data()->isVisible()) {
d->widget.data()->setPos(d->minXExtent(),
d->minYExtent());
}
}
Qt::Alignment Plasma::ScrollWidget::alignment() const
{
return d->alignment;
}
void ScrollWidget::setOverShoot(bool enable)
{
d->hasOvershoot = enable;
}
bool ScrollWidget::hasOverShoot() const
{
return d->hasOvershoot;
}
} // namespace Plasma
-#include <scrollwidget.moc>
+
+
+#include "moc_scrollwidget.cpp"
diff --git a/plasma/widgets/separator.cpp b/plasma/widgets/separator.cpp
index c60baea4d2..2ec2c82c52 100644
--- a/plasma/widgets/separator.cpp
+++ b/plasma/widgets/separator.cpp
@@ -1,98 +1,101 @@
/*
* Copyright 2009 by Davide Bettio <davide.bettio@kdemail.net>
*
* 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 "separator.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include "svg.h"
namespace Plasma
{
class SeparatorPrivate
{
public:
Svg *svg;
Qt::Orientation orientation;
};
Separator::Separator(QGraphicsItem *parent, Qt::WindowFlags wFlags)
: QGraphicsWidget(parent, wFlags),
d(new SeparatorPrivate())
{
d->svg = new Svg();
d->svg->setImagePath("widgets/line");
d->svg->setContainsMultipleImages(true);
setOrientation(Qt::Horizontal);
}
Separator::~Separator()
{
delete d->svg;
delete d;
}
void Separator::setOrientation(Qt::Orientation orientation)
{
d->orientation = orientation;
if (orientation == Qt::Horizontal) {
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
} else {
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
}
}
Qt::Orientation Separator::orientation()
{
return d->orientation;
}
void Separator::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
if (d->svg){
if (d->orientation == Qt::Horizontal){
d->svg->paint(painter, boundingRect(), "horizontal-line");
} else {
d->svg->paint(painter, boundingRect(), "vertical-line");
}
}
}
QSizeF Separator::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
QSizeF hint = QGraphicsWidget::sizeHint(which, constraint);
if (d->orientation == Qt::Horizontal) {
hint.setHeight(d->svg->elementSize("horizontal-line").height());
} else {
hint.setWidth(d->svg->elementSize("vertical-line").width());
}
return hint;
}
} // Plasma namespace
+
+
+#include "moc_separator.cpp"
diff --git a/plasma/widgets/signalplotter.cpp b/plasma/widgets/signalplotter.cpp
index 2e0b743238..fd03ba0a98 100644
--- a/plasma/widgets/signalplotter.cpp
+++ b/plasma/widgets/signalplotter.cpp
@@ -1,1115 +1,1118 @@
/*
* KSysGuard, the KDE System Guard
*
* Copyright 1999 - 2002 Chris Schlaeger <cs@kde.org>
* Copyright 2006 John Tapsell <tapsell@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 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 "signalplotter.h"
#include <math.h>
#include <string.h>
#include <QApplication>
#include <QList>
#include <QPalette>
#include <QPainter>
#include <QPixmap>
#include <QPainterPath>
#include <QPolygon>
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include <plasma/svg.h>
#include <plasma/theme.h>
namespace Plasma
{
class SignalPlotterPrivate
{
public:
SignalPlotterPrivate()
: svgBackground(0)
{ }
~SignalPlotterPrivate()
{
}
void themeChanged()
{
Plasma::Theme *theme = Plasma::Theme::defaultTheme();
backgroundColor = theme->color(Theme::BackgroundColor);
fontColor = theme->color(Theme::TextColor);
borderColor = fontColor;
verticalLinesColor = fontColor;
verticalLinesColor.setAlphaF(0.4);
horizontalLinesColor = verticalLinesColor;
}
int precision;
uint samples;
uint bezierCurveOffset;
double scaledBy;
double verticalMin;
double verticalMax;
double niceVertMin;
double niceVertMax;
double niceVertRange;
uint verticalLinesOffset;
uint verticalLinesDistance;
QColor verticalLinesColor;
bool showHorizontalLines;
uint horizontalScale;
uint horizontalLinesCount;
QColor horizontalLinesColor;
Svg *svgBackground;
QString svgFilename;
QColor fontColor;
QColor borderColor;
QColor backgroundColor;
QPixmap backgroundPixmap;
QFont font;
QString title;
QString unit;
QList<PlotColor> plotColors;
QList<QList<double> > plotData;
bool fillPlots : 1;
bool showLabels : 1;
bool showTopBar : 1;
bool stackPlots : 1;
bool useAutoRange : 1;
bool showThinFrame : 1;
bool showVerticalLines : 1;
bool verticalLinesScroll : 1;
};
SignalPlotter::SignalPlotter(QGraphicsItem *parent)
: QGraphicsWidget(parent),
d(new SignalPlotterPrivate)
{
d->precision = 0;
d->bezierCurveOffset = 0;
d->samples = 0;
d->verticalMin = d->verticalMax = 0.0;
d->niceVertMin = d->niceVertMax = 0.0;
d->niceVertRange = 0;
d->useAutoRange = true;
d->scaledBy = 1;
d->showThinFrame = true;
d->showVerticalLines = true;
d->verticalLinesDistance = 30;
d->verticalLinesScroll = true;
d->verticalLinesOffset = 0;
d->horizontalScale = 1;
d->showHorizontalLines = true;
d->horizontalLinesCount = 5;
d->showLabels = true;
d->showTopBar = true;
d->stackPlots = true;
d->fillPlots = true;
// Anything smaller than this does not make sense.
setMinimumSize(QSizeF(KIconLoader::SizeSmall, KIconLoader::SizeSmall));
setSvgBackground("widgets/plot-background");
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(themeChanged()));
d->themeChanged();
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
SignalPlotter::~SignalPlotter()
{
delete d;
}
QString SignalPlotter::unit() const
{
return d->unit;
}
void SignalPlotter::setUnit(const QString &unit)
{
d->unit= unit;
}
void SignalPlotter::addPlot(const QColor &color)
{
// When we add a new plot, go back and set the data for this plot to 0 for
// all the other times. This is because it makes it easier for moveSensors.
foreach (QList<double> data, d->plotData) {
data.append(0);
}
PlotColor newColor;
newColor.color = color;
newColor.darkColor = color.dark(150);
d->plotColors.append(newColor);
}
void SignalPlotter::addSample(const QList<double>& sampleBuf)
{
if (d->samples < 4) {
// It might be possible, under some race conditions, for addSample
// to be called before d->samples is set. This is just to be safe.
#ifndef NDEBUG
kDebug() << "Error - d->samples is only " << d->samples;
#endif
updateDataBuffers();
#ifndef NDEBUG
kDebug() << "d->samples is now " << d->samples;
#endif
if (d->samples < 4) {
return;
}
}
d->plotData.prepend(sampleBuf);
Q_ASSERT(sampleBuf.count() == d->plotColors.count());
if ((uint)d->plotData.size() > d->samples) {
d->plotData.removeLast(); // we have too many. Remove the last item
if ((uint)d->plotData.size() > d->samples) {
// If we still have too many, then we have resized the widget.
// Remove one more. That way we will slowly resize to the new size
d->plotData.removeLast();
}
}
if (d->bezierCurveOffset >= 2) {
d->bezierCurveOffset = 0;
} else {
d->bezierCurveOffset++;
}
Q_ASSERT((uint)d->plotData.size() >= d->bezierCurveOffset);
// If the vertical lines are scrolling, increment the offset
// so they move with the data.
if (d->verticalLinesScroll) {
d->verticalLinesOffset =
(d->verticalLinesOffset + d->horizontalScale) % d->verticalLinesDistance;
}
update();
}
void SignalPlotter::reorderPlots(const QList<uint>& newOrder)
{
if (newOrder.count() != d->plotColors.count()) {
#ifndef NDEBUG
kDebug() << "neworder has " << newOrder.count()
<< " and plot colors is " << d->plotColors.count();
#endif
return;
}
foreach (QList<double> data, d->plotData) {
if (newOrder.count() != data.count()) {
#ifndef NDEBUG
kDebug() << "Serious problem in move sample. plotdata[i] has "
<< data.count() << " and neworder has " << newOrder.count();
#endif
} else {
QList<double> newPlot;
for (int i = 0; i < newOrder.count(); i++) {
int newIndex = newOrder[i];
newPlot.append(data.at(newIndex));
}
data = newPlot;
}
}
QList<PlotColor> newPlotColors;
for (int i = 0; i < newOrder.count(); i++) {
int newIndex = newOrder[i];
PlotColor newColor = d->plotColors.at(newIndex);
newPlotColors.append(newColor);
}
d->plotColors = newPlotColors;
}
void SignalPlotter::setVerticalRange(double min, double max)
{
d->verticalMin = min;
d->verticalMax = max;
calculateNiceRange();
}
QList<PlotColor> &SignalPlotter::plotColors()
{
return d->plotColors;
}
void SignalPlotter::removePlot(uint pos)
{
if (pos >= (uint)d->plotColors.size()) {
return;
}
d->plotColors.removeAt(pos);
foreach (QList<double> data, d->plotData) {
if ((uint)data.size() >= pos) {
data.removeAt(pos);
}
}
}
void SignalPlotter::scale(qreal delta)
{
if (d->scaledBy == delta) {
return;
}
d->scaledBy = delta;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
calculateNiceRange();
}
qreal SignalPlotter::scaledBy() const
{
return d->scaledBy;
}
void SignalPlotter::setTitle(const QString &title)
{
if (d->title == title) {
return;
}
d->title = title;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
QString SignalPlotter::title() const
{
return d->title;
}
void SignalPlotter::setUseAutoRange(bool value)
{
d->useAutoRange = value;
calculateNiceRange();
// this change will be detected in paint and the image cache regenerated
}
bool SignalPlotter::useAutoRange() const
{
return d->useAutoRange;
}
double SignalPlotter::verticalMinValue() const
{
return d->verticalMin;
}
double SignalPlotter::verticalMaxValue() const
{
return d->verticalMax;
}
void SignalPlotter::setHorizontalScale(uint scale)
{
if (scale == d->horizontalScale) {
return;
}
d->horizontalScale = scale;
updateDataBuffers();
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
uint SignalPlotter::horizontalScale() const
{
return d->horizontalScale;
}
void SignalPlotter::setShowVerticalLines(bool value)
{
if (d->showVerticalLines == value) {
return;
}
d->showVerticalLines = value;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
bool SignalPlotter::showVerticalLines() const
{
return d->showVerticalLines;
}
void SignalPlotter::setVerticalLinesColor(const QColor &color)
{
if (d->verticalLinesColor == color) {
return;
}
d->verticalLinesColor = color;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
QColor SignalPlotter::verticalLinesColor() const
{
return d->verticalLinesColor;
}
void SignalPlotter::setVerticalLinesDistance(uint distance)
{
if (distance == d->verticalLinesDistance) {
return;
}
d->verticalLinesDistance = distance;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
uint SignalPlotter::verticalLinesDistance() const
{
return d->verticalLinesDistance;
}
void SignalPlotter::setVerticalLinesScroll(bool value)
{
if (value == d->verticalLinesScroll) {
return;
}
d->verticalLinesScroll = value;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
bool SignalPlotter::verticalLinesScroll() const
{
return d->verticalLinesScroll;
}
void SignalPlotter::setShowHorizontalLines(bool value)
{
if (value == d->showHorizontalLines) {
return;
}
d->showHorizontalLines = value;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
bool SignalPlotter::showHorizontalLines() const
{
return d->showHorizontalLines;
}
void SignalPlotter::setFontColor(const QColor &color)
{
d->fontColor = color;
}
QColor SignalPlotter::fontColor() const
{
return d->fontColor;
}
void SignalPlotter::setHorizontalLinesColor(const QColor &color)
{
if (color == d->horizontalLinesColor) {
return;
}
d->horizontalLinesColor = color;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
QColor SignalPlotter::horizontalLinesColor() const
{
return d->horizontalLinesColor;
}
void SignalPlotter::setHorizontalLinesCount(uint count)
{
if (count == d->horizontalLinesCount) {
return;
}
d->horizontalLinesCount = count;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
calculateNiceRange();
}
uint SignalPlotter::horizontalLinesCount() const
{
return d->horizontalLinesCount;
}
void SignalPlotter::setShowLabels(bool value)
{
if (value == d->showLabels) {
return;
}
d->showLabels = value;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
bool SignalPlotter::showLabels() const
{
return d->showLabels;
}
void SignalPlotter::setShowTopBar(bool value)
{
if (d->showTopBar == value) {
return;
}
d->showTopBar = value;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
bool SignalPlotter::showTopBar() const
{
return d->showTopBar;
}
void SignalPlotter::setFont(const QFont &font)
{
d->font = font;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
QFont SignalPlotter::font() const
{
return d->font;
}
QString SignalPlotter::svgBackground()
{
return d->svgFilename;
}
void SignalPlotter::setSvgBackground(const QString &filename)
{
if (d->svgFilename == filename) {
return;
}
if (!filename.isEmpty() && filename[0] == '/') {
KStandardDirs *kstd = KGlobal::dirs();
d->svgFilename = kstd->findResource("data", "ksysguard/" + filename);
} else {
d->svgFilename = filename;
}
delete d->svgBackground;
d->svgBackground = 0;
if (!d->svgFilename.isEmpty()) {
d->svgBackground = new Svg(this);
d->svgBackground->setImagePath(d->svgFilename);
}
}
void SignalPlotter::setBackgroundColor(const QColor &color)
{
if (color == d->backgroundColor) {
return;
}
d->backgroundColor = color;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
QColor SignalPlotter::backgroundColor() const
{
return d->backgroundColor;
}
void SignalPlotter::setThinFrame(bool set)
{
if (d->showThinFrame == set) {
return;
}
d->showThinFrame = set;
d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
}
bool SignalPlotter::thinFrame() const
{
return d->showThinFrame;
}
void SignalPlotter::setStackPlots(bool stack)
{
d->stackPlots = stack;
d->fillPlots = stack;
}
bool SignalPlotter::stackPlots() const
{
return d->stackPlots;
}
void SignalPlotter::updateDataBuffers()
{
// This is called when the widget has resized
//
// Determine new number of samples first.
// +0.5 to ensure rounding up
// +4 for extra data points so there is
// 1) no wasted space and
// 2) no loss of precision when drawing the first data point.
d->samples = static_cast<uint>(((size().width() - 2) /
d->horizontalScale) + 4.5);
}
QPixmap SignalPlotter::getSnapshotImage(uint w, uint height)
{
uint horizontalStep = (uint)((1.0 * w / size().width()) + 0.5); // get the closest integer horizontal step
uint newWidth = (uint) (horizontalStep * size().width());
QPixmap image = QPixmap(newWidth, height);
QPainter p(&image);
drawWidget(&p, newWidth, height, newWidth);
p.end();
return image;
}
void SignalPlotter::setGeometry(const QRectF &geometry)
{
// First update our size, then update the data buffers accordingly.
QGraphicsWidget::setGeometry(geometry);
updateDataBuffers();
}
void SignalPlotter::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
uint w = (uint) size().width();
uint h = (uint) size().height();
// Do not do repaints when the widget is not yet setup properly.
if (w <= 2) {
return;
}
drawWidget(painter, w, h, d->horizontalScale);
}
void SignalPlotter::drawWidget(QPainter *p, uint w, uint height, int horizontalScale)
{
uint h = height; // h will become the height of just the bit we draw the plots in
p->setFont(d->font);
uint fontheight = p->fontMetrics().height();
if (d->verticalMin < d->niceVertMin ||
d->verticalMax > d->niceVertMax ||
d->verticalMax < (d->niceVertRange * 0.75 + d->niceVertMin) ||
d->niceVertRange == 0) {
calculateNiceRange();
}
QPen pen;
pen.setWidth(1);
pen.setCapStyle(Qt::RoundCap);
p->setPen(pen);
uint top = p->pen().width() / 2; // The y position of the top of the graph. Basically this is one more than the height of the top bar
h-= top;
// Check if there's enough room to actually show a top bar.
// Must be enough room for a bar at the top, plus horizontal
// lines each of a size with room for a scale.
bool showTopBar = d->showTopBar && h > (fontheight/*top bar size*/ +5/*smallest reasonable size for a graph*/);
if (showTopBar) {
top += fontheight; // The top bar has the same height as fontheight. Thus the top of the graph is at fontheight
h -= fontheight;
}
if (d->backgroundPixmap.isNull() ||
(uint)d->backgroundPixmap.size().height() != height ||
(uint)d->backgroundPixmap.size().width() != w) {
// recreate on resize etc
d->backgroundPixmap = QPixmap(w, height);
d->backgroundPixmap.fill(Qt::transparent);
QPainter pCache(&d->backgroundPixmap);
pCache.setRenderHint(QPainter::Antialiasing, false);
pCache.setFont(d->font);
drawBackground(&pCache, w, height);
if (d->showThinFrame) {
drawThinFrame(&pCache, w, height);
// We have a 'frame' in the bottom and right - so subtract them from the view
h--;
w--;
pCache.setClipRect(0, 0, w, height-1);
}
if (showTopBar) {
int separatorX = w / 2;
drawTopBarFrame(&pCache, separatorX, top);
}
// Draw scope-like grid vertical lines if it doesn't move.
// If it does move, draw it in the dynamic part of the code.
if (!d->verticalLinesScroll && d->showVerticalLines && w > 60) {
drawVerticalLines(&pCache, top, w, h);
}
if (d->showHorizontalLines) {
drawHorizontalLines(&pCache, top, w, h);
}
} else {
if (d->showThinFrame) {
// We have a 'frame' in the bottom and right - so subtract them from the view
h--;
w--;
}
}
p->drawPixmap(0, 0, d->backgroundPixmap);
p->setRenderHint(QPainter::Antialiasing, true);
if (showTopBar) {
int separatorX = w / 2;
int topBarWidth = w - separatorX -2;
drawTopBarContents(p, separatorX, topBarWidth, top -1);
}
p->setClipRect(0, top, w, h);
// Draw scope-like grid vertical lines
if (d->verticalLinesScroll && d->showVerticalLines && w > 60) {
drawVerticalLines(p, top, w, h);
}
drawPlots(p, top, w, h, horizontalScale);
if (d->showLabels && w > 60 && h > (fontheight + 1)) {
// if there's room to draw the labels, then draw them!
drawAxisText(p, top, h);
}
}
void SignalPlotter::drawBackground(QPainter *p, int w, int h)
{
if (d->svgBackground) {
d->svgBackground->resize(w, h);
d->svgBackground->paint(p, 0, 0);
} else {
p->fillRect(0, 0, w, h, d->backgroundColor);
}
}
void SignalPlotter::drawThinFrame(QPainter *p, int w, int h)
{
// Draw a line along the bottom and the right side of the
// widget to create a 3D like look.
p->setPen(d->borderColor);
p->drawLine(0, h - 1, w - 1, h - 1);
p->drawLine(w - 1, 0, w - 1, h - 1);
}
void SignalPlotter::calculateNiceRange()
{
d->niceVertRange = d->verticalMax - d->verticalMin;
// If the range is too small we will force it to 1.0 since it
// looks a lot nicer.
if (d->niceVertRange < 0.000001) {
d->niceVertRange = 1.0;
}
d->niceVertMin = d->verticalMin;
if (d->verticalMin != 0.0) {
double dim = pow(10, floor(log10(fabs(d->verticalMin)))) / 2;
if (d->verticalMin < 0.0) {
d->niceVertMin = dim * floor(d->verticalMin / dim);
} else {
d->niceVertMin = dim * ceil(d->verticalMin / dim);
}
d->niceVertRange = d->verticalMax - d->niceVertMin;
if (d->niceVertRange < 0.000001) {
d->niceVertRange = 1.0;
}
}
// Massage the range so that the grid shows some nice values.
double step = d->niceVertRange / (d->scaledBy * (d->horizontalLinesCount + 1));
int logdim = (int)floor(log10(step));
double dim = pow((double)10.0, logdim) / 2;
int a = (int)ceil(step / dim);
if (logdim >= 0) {
d->precision = 0;
} else if (a % 2 == 0) {
d->precision = -logdim;
} else {
d->precision = 1 - logdim;
}
d->niceVertRange = d->scaledBy * dim * a * (d->horizontalLinesCount + 1);
d->niceVertMax = d->niceVertMin + d->niceVertRange;
}
void SignalPlotter::drawTopBarFrame(QPainter *p, int separatorX, int height)
{
// Draw horizontal bar with current sensor values at top of display.
// Remember that it has a height of 'height'. Thus the lowest pixel
// it can draw on is height-1 since we count from 0.
p->setPen(Qt::NoPen);
p->setPen(d->fontColor);
p->drawText(0, 1, separatorX, height, Qt::AlignCenter, d->title);
p->setPen(d->horizontalLinesColor);
p->drawLine(separatorX - 1, 1, separatorX - 1, height - 1);
}
void SignalPlotter::drawTopBarContents(QPainter *p, int x, int width, int height)
{
// The height is the height of the contents, so this will be
// one pixel less than the height of the topbar
double bias = -d->niceVertMin;
double scaleFac = width / d->niceVertRange;
// The top bar shows the current values of all the plot data.
// This iterates through each different plot and plots the newest data for each.
if (!d->plotData.isEmpty()) {
QList<double> newestData = d->plotData.first();
for (int i = newestData.count()-1; i >= 0; --i) {
double newest_datapoint = newestData.at(i);
int start = x + (int)(bias * scaleFac);
int end = x + (int)((bias += newest_datapoint) * scaleFac);
int start2 = qMin(start, end);
end = qMax(start, end);
start = start2;
// If the rect is wider than 2 pixels we draw only the last
// pixels with the bright color. The rest is painted with
// a 50% darker color.
p->setPen(Qt::NoPen);
QLinearGradient linearGrad(QPointF(start, 1), QPointF(end, 1));
linearGrad.setColorAt(0, d->plotColors[i].darkColor);
linearGrad.setColorAt(1, d->plotColors[i].color);
p->fillRect(start, 1, end - start, height-1, QBrush(linearGrad));
}
}
}
void SignalPlotter::drawVerticalLines(QPainter *p, int top, int w, int h)
{
p->setPen(d->verticalLinesColor);
for (int x = d->verticalLinesOffset; x < (w - 2); x += d->verticalLinesDistance) {
p->drawLine(w - x, top, w - x, h + top -1);
}
}
void SignalPlotter::drawPlots(QPainter *p, int top, int w, int h, int horizontalScale)
{
Q_ASSERT(d->niceVertRange != 0);
if (d->niceVertRange == 0) {
d->niceVertRange = 1;
}
double scaleFac = (h - 1) / d->niceVertRange;
int xPos = 0;
QList< QList<double> >::Iterator it = d->plotData.begin();
p->setPen(Qt::NoPen);
// In autoRange mode we determine the range and plot the values in
// one go. This is more efficiently than running through the
// buffers twice but we do react on recently discarded samples as
// well as new samples one plot too late. So the range is not
// correct if the recently discarded samples are larger or smaller
// than the current extreme values. But we can probably live with
// this.
// These values aren't used directly anywhere. Instead we call
// calculateNiceRange() which massages these values into a nicer
// values. Rounding etc. This means it's safe to change these values
// without affecting any other drawings.
if (d->useAutoRange) {
d->verticalMin = d->verticalMax = 0.0;
}
// d->bezierCurveOffset is how many points we have at the start.
// All the bezier curves are in groups of 3, with the first of the
// next group being the last point of the previous group
// Example, when d->bezierCurveOffset == 0, and we have data, then just
// plot a normal bezier curve. (we will have at least 3 points in this case)
// When d->bezierCurveOffset == 1, then we want a bezier curve that uses
// the first data point and the second data point. Then the next group
// starts from the second data point.
//
// When d->bezierCurveOffset == 2, then we want a bezier curve that
// uses the first, second and third data.
for (uint i = 0; it != d->plotData.end() && i < d->samples; ++i) {
QPen pen;
pen.setWidth(1);
pen.setCapStyle(Qt::FlatCap);
// We will plot 1 bezier curve for every 3 points, with the 4th point
// being the end of one bezier curve and the start of the second.
// This does means the bezier curves will not join nicely, but it
// should be better than nothing.
QList<double> datapoints = *it;
QList<double> prev_datapoints = datapoints;
QList<double> prev_prev_datapoints = datapoints;
QList<double> prev_prev_prev_datapoints = datapoints;
if (i == 0 && d->bezierCurveOffset > 0) {
// We are plotting an incomplete bezier curve - we don't have
// all the data we want. Try to cope.
xPos += horizontalScale * d->bezierCurveOffset;
if (d->bezierCurveOffset == 1) {
prev_datapoints = *it;
++it; // Now we are on the first element of the next group, if it exists
if (it != d->plotData.end()) {
prev_prev_prev_datapoints = prev_prev_datapoints = *it;
} else {
prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints;
}
} else {
// d->bezierCurveOffset must be 2 now
prev_datapoints = *it;
Q_ASSERT(it != d->plotData.end());
++it;
prev_prev_datapoints = *it;
Q_ASSERT(it != d->plotData.end());
++it; // Now we are on the first element of the next group, if it exists
if (it != d->plotData.end()) {
prev_prev_prev_datapoints = *it;
} else {
prev_prev_prev_datapoints = prev_prev_datapoints;
}
}
} else {
// We have a group of 3 points at least. That's 1 start point and 2 control points.
xPos += horizontalScale * 3;
it++;
if (it != d->plotData.end()) {
prev_datapoints = *it;
it++;
if (it != d->plotData.end()) {
prev_prev_datapoints = *it;
it++; // We are now on the next set of data points
if (it != d->plotData.end()) {
// We have this datapoint, so use it for our finish point
prev_prev_prev_datapoints = *it;
} else {
// We don't have the next set, so use our last control
// point as our finish point
prev_prev_prev_datapoints = prev_prev_datapoints;
}
} else {
prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints;
}
} else {
prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints = datapoints;
}
}
float x0 = w - xPos + 3.0 * horizontalScale;
float x1 = w - xPos + 2.0 * horizontalScale;
float x2 = w - xPos + 1.0 * horizontalScale;
float x3 = w - xPos;
float y0 = h - 1 + top;
float y1 = y0;
float y2 = y0;
float y3 = y0;
int offset = 0; // Our line is 2 pixels thick. This means that when we draw the area, we need to offset
double max_y = 0;
double min_y = 0;
for (int j = qMin(datapoints.size(), d->plotColors.size()) - 1; j >=0; --j) {
if (d->useAutoRange) {
// If we use autorange, then we need to prepare the min and max values for _next_ time we paint.
// If we are stacking the plots, then we need to add the maximums together.
double current_maxvalue =
qMax(datapoints[j],
qMax(prev_datapoints[j],
qMax(prev_prev_datapoints[j],
prev_prev_prev_datapoints[j])));
double current_minvalue =
qMin<double>(datapoints[j],
qMin(prev_datapoints[j],
qMin(prev_prev_datapoints[j],
prev_prev_prev_datapoints[j])));
d->verticalMax = qMax(d->verticalMax, current_maxvalue);
d->verticalMin = qMin(d->verticalMin, current_maxvalue);
if (d->stackPlots) {
max_y += current_maxvalue;
min_y += current_minvalue;
}
}
// Draw polygon only if enough data points are available.
if (j < prev_prev_prev_datapoints.count() &&
j < prev_prev_datapoints.count() &&
j < prev_datapoints.count()) {
// The height of the whole widget is h+top-> The height of
// the area we are plotting in is just h.
// The y coordinate system starts from the top, so at the
// bottom the y coordinate is h+top.
// So to draw a point at value y', we need to put this at h+top-y'
float delta_y0;
delta_y0 = (datapoints[j] - d->niceVertMin) * scaleFac;
float delta_y1;
delta_y1 = (prev_datapoints[j] - d->niceVertMin) * scaleFac;
float delta_y2;
delta_y2 = (prev_prev_datapoints[j] - d->niceVertMin) * scaleFac;
float delta_y3;
delta_y3 = (prev_prev_prev_datapoints[j] - d->niceVertMin) * scaleFac;
QPainterPath path;
if (d->stackPlots && offset) {
// we don't want the lines to overdraw each other.
// This isn't a great solution though :(
if (delta_y0 < 3) {
delta_y0=3;
}
if (delta_y1 < 3) {
delta_y1=3;
}
if (delta_y2 < 3) {
delta_y2=3;
}
if (delta_y3 < 3) {
delta_y3=3;
}
}
path.moveTo(x0, y0 - delta_y0);
path.cubicTo(x1, y1 - delta_y1, x2, y2 - delta_y2, x3, y3 - delta_y3);
if (d->fillPlots) {
QPainterPath path2(path);
QLinearGradient myGradient(0,(h - 1 + top), 0, (h - 1 + top) / 5);
Q_ASSERT(d->plotColors.size() >= j);
QColor c0(d->plotColors[j].darkColor);
QColor c1(d->plotColors[j].color);
c0.setAlpha(150);
c1.setAlpha(150);
myGradient.setColorAt(0, c0);
myGradient.setColorAt(1, c1);
path2.lineTo(x3, y3 - offset);
if (d->stackPlots) {
// offset is set to 1 after the first plot is drawn,
// so we don't trample on top of the 2pt thick line
path2.cubicTo(x2, y2 - offset, x1, y1 - offset, x0, y0 - offset);
} else {
path2.lineTo(x0, y0 - 1);
}
p->setBrush(myGradient);
p->setPen(Qt::NoPen);
p->drawPath(path2);
}
p->setBrush(Qt::NoBrush);
Q_ASSERT(d->plotColors.size() >= j);
pen.setColor(d->plotColors[j].color);
p->setPen(pen);
p->drawPath(path);
if (d->stackPlots) {
// We can draw the plots stacked on top of each other.
// This means that say plot 0 has the value 2 and plot
// 1 has the value 3, then we plot plot 0 at 2 and plot 1 at 2+3 = 5.
y0 -= delta_y0;
y1 -= delta_y1;
y2 -= delta_y2;
y3 -= delta_y3;
offset = 1; // see the comment further up for int offset;
}
}
if (d->useAutoRange && d->stackPlots) {
d->verticalMax = qMax(max_y, d->verticalMax);
d->verticalMin = qMin(min_y, d->verticalMin);
}
}
}
}
void SignalPlotter::drawAxisText(QPainter *p, int top, int h)
{
// Draw horizontal lines and values. Lines are always drawn.
// Values are only draw when width is greater than 60.
QString val;
// top = 0 or font.height depending on whether there's a topbar or not
// h = graphing area.height - i.e. the actual space we have to draw inside
// Note we are drawing from 0,0 as the top left corner. So we have to add on top
// to get to the top of where we are drawing so top+h is the height of the widget.
p->setPen(d->fontColor);
double stepsize = d->niceVertRange / (d->scaledBy * (d->horizontalLinesCount + 1));
int step =
(int)ceil((d->horizontalLinesCount+1) *
(p->fontMetrics().height() + p->fontMetrics().leading() / 2.0) / h);
if (step == 0) {
step = 1;
}
for (int y = d->horizontalLinesCount + 1; y >= 1; y-= step) {
int y_coord =
top + (y * (h - 1)) / (d->horizontalLinesCount + 1); // Make sure it's y*h first to avoid rounding bugs
if (y_coord - p->fontMetrics().ascent() < top) {
// at most, only allow 4 pixels of the text to be covered up
// by the top bar. Otherwise just don't bother to draw it
continue;
}
double value;
if ((uint)y == d->horizontalLinesCount + 1) {
value = d->niceVertMin; // sometimes using the formulas gives us a value very slightly off
} else {
value = d->niceVertMax / d->scaledBy - y * stepsize;
}
QString number = KGlobal::locale()->formatNumber(value, d->precision);
val = QString("%1 %2").arg(number, d->unit);
p->drawText(6, y_coord - 3, val);
}
}
void SignalPlotter::drawHorizontalLines(QPainter *p, int top, int w, int h)
{
p->setPen(d->horizontalLinesColor);
for (uint y = 0; y <= d->horizontalLinesCount + 1; y++) {
// note that the y_coord starts from 0. so we draw from pixel number 0 to h-1. Thus the -1 in the y_coord
int y_coord = top + (y * (h - 1)) / (d->horizontalLinesCount + 1); // Make sure it's y*h first to avoid rounding bugs
p->drawLine(0, y_coord, w - 2, y_coord);
}
}
double SignalPlotter::lastValue(uint i) const
{
if (d->plotData.isEmpty() || d->plotData.first().size() <= (int)i) {
return 0;
}
return d->plotData.first()[i];
}
QString SignalPlotter::lastValueAsString(uint i) const
{
if (d->plotData.isEmpty()) {
return QString();
}
double value = d->plotData.first()[i] / d->scaledBy; // retrieve the newest value for this plot then scale it correct
QString number = KGlobal::locale()->formatNumber(value, (value >= 100)?0:2);
return QString("%1 %2").arg(number, d->unit);
}
} // Plasma namespace
+
+
+#include "moc_signalplotter.cpp"
diff --git a/plasma/widgets/slider.cpp b/plasma/widgets/slider.cpp
index bfad249b42..865823f00a 100644
--- a/plasma/widgets/slider.cpp
+++ b/plasma/widgets/slider.cpp
@@ -1,255 +1,257 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "slider.h"
#include <QApplication>
#include <QPainter>
#include <QSlider>
#include <QStyleOptionSlider>
#include <QGraphicsSceneWheelEvent>
#include <kmimetype.h>
#include "theme.h"
#include "framesvg.h"
#include "private/style_p.h"
#include "private/focusindicator_p.h"
namespace Plasma
{
class SliderPrivate
{
public:
SliderPrivate()
{
}
~SliderPrivate()
{
}
Plasma::FrameSvg *background;
Plasma::Style::Ptr style;
FocusIndicator *focusIndicator;
};
Slider::Slider(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new SliderPrivate)
{
QSlider *native = new QSlider;
connect(native, SIGNAL(sliderMoved(int)), this, SIGNAL(sliderMoved(int)));
connect(native, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
setWidget(native);
native->setWindowIcon(QIcon());
native->setAttribute(Qt::WA_NoSystemBackground);
d->background = new Plasma::FrameSvg(this);
d->background->setImagePath("widgets/slider");
d->focusIndicator = new FocusIndicator(this, d->background);
d->style = Plasma::Style::sharedStyle();
native->setStyle(d->style.data());
}
Slider::~Slider()
{
delete d;
Plasma::Style::doneWithSharedStyle();
}
void Slider::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
if (!styleSheet().isNull() || Theme::defaultTheme()->useNativeWidgetStyle()) {
QGraphicsProxyWidget::paint(painter, option, widget);
return;
}
QSlider *slider = nativeWidget();
QStyle *style = slider->style();
QStyleOptionSlider sliderOpt;
sliderOpt.initFrom(slider);
//init the other stuff in the slider, taken from initStyleOption()
sliderOpt.subControls = QStyle::SC_None;
sliderOpt.activeSubControls = QStyle::SC_None;
sliderOpt.orientation = slider->orientation();
sliderOpt.maximum = slider->maximum();
sliderOpt.minimum = slider->minimum();
sliderOpt.tickPosition = (QSlider::TickPosition)slider->tickPosition();
sliderOpt.tickInterval = slider->tickInterval();
sliderOpt.upsideDown = (slider->orientation() == Qt::Horizontal) ?
(slider->invertedAppearance() != (sliderOpt.direction == Qt::RightToLeft))
: (!slider->invertedAppearance());
sliderOpt.direction = Qt::LeftToRight; // we use the upsideDown option instead
sliderOpt.sliderPosition = slider->sliderPosition();
sliderOpt.sliderValue = slider->value();
sliderOpt.singleStep = slider->singleStep();
sliderOpt.pageStep = slider->pageStep();
if (slider->orientation() == Qt::Horizontal) {
sliderOpt.state |= QStyle::State_Horizontal;
}
QRect backgroundRect =
style->subControlRect(QStyle::CC_Slider, &sliderOpt, QStyle::SC_SliderGroove, slider);
if (sliderOpt.orientation == Qt::Horizontal &&
d->background->hasElement("horizontal-background-center")) {
d->background->setElementPrefix("horizontal-background");
d->background->resizeFrame(backgroundRect.size());
d->background->paintFrame(painter, backgroundRect.topLeft());
} else if (sliderOpt.orientation == Qt::Vertical &&
d->background->hasElement("vertical-background-center")) {
d->background->setElementPrefix("vertical-background");
d->background->resizeFrame(backgroundRect.size());
d->background->paintFrame(painter, backgroundRect.topLeft());
} else if (sliderOpt.orientation == Qt::Horizontal) {
QRect elementRect = d->background->elementRect("horizontal-slider-line").toRect();
elementRect.setWidth(sliderOpt.rect.width());
elementRect.moveCenter(sliderOpt.rect.center());
d->background->paint(painter, elementRect, "horizontal-slider-line");
} else {
QRect elementRect = d->background->elementRect("vertical-slider-line").toRect();
elementRect.setHeight(sliderOpt.rect.height());
elementRect.moveCenter(sliderOpt.rect.center());
d->background->paint(painter, elementRect, "vertical-slider-line");
}
//Tickmarks
if (sliderOpt.tickPosition != QSlider::NoTicks) {
sliderOpt.subControls = QStyle::SC_SliderTickmarks;
sliderOpt.palette.setColor(
QPalette::WindowText, Plasma::Theme::defaultTheme()->color(Theme::TextColor));
style->drawComplexControl(QStyle::CC_Slider, &sliderOpt, painter, slider);
}
QRect handleRect = style->subControlRect(QStyle::CC_Slider, &sliderOpt, QStyle::SC_SliderHandle, slider);
QString handle;
if (sliderOpt.orientation == Qt::Horizontal) {
handle = "horizontal-slider-handle";
} else {
handle = "vertical-slider-handle";
}
QRect elementRect = d->background->elementRect(handle).toRect();
elementRect.moveCenter(handleRect.center());
if (elementRect.right() > rect().right()) {
elementRect.moveRight(rect().right());
}
if (elementRect.left() < rect().left()) {
elementRect.moveLeft(rect().left());
}
if (elementRect.top() < rect().top()) {
elementRect.moveTop(rect().top());
}
if (elementRect.bottom() > rect().bottom()) {
elementRect.moveBottom(rect().bottom());
}
if (orientation() == Qt::Vertical) {
d->focusIndicator->setCustomPrefix("vertical-slider-");
} else {
d->focusIndicator->setCustomPrefix("horizontal-slider-");
}
d->focusIndicator->setCustomGeometry(elementRect);
d->background->paint(painter, elementRect, handle);
}
void Slider::wheelEvent(QGraphicsSceneWheelEvent *event)
{
QWheelEvent e(event->pos().toPoint(), event->delta(),event->buttons(),event->modifiers(),event->orientation());
QApplication::sendEvent(widget(), &e);
event->accept();
}
void Slider::setMaximum(int max)
{
static_cast<QSlider*>(widget())->setMaximum(max);
}
int Slider::maximum() const
{
return static_cast<QSlider*>(widget())->maximum();
}
void Slider::setMinimum(int min)
{
static_cast<QSlider*>(widget())->setMinimum(min);
}
int Slider::minimum() const
{
return static_cast<QSlider*>(widget())->minimum();
}
void Slider::setRange(int min, int max)
{
static_cast<QSlider*>(widget())->setRange(min, max);
}
void Slider::setValue(int value)
{
static_cast<QSlider*>(widget())->setValue(value);
}
int Slider::value() const
{
return static_cast<QSlider*>(widget())->value();
}
void Slider::setOrientation(Qt::Orientation orientation)
{
static_cast<QSlider*>(widget())->setOrientation(orientation);
}
Qt::Orientation Slider::orientation() const
{
return static_cast<QSlider*>(widget())->orientation();
}
void Slider::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString Slider::styleSheet()
{
return widget()->styleSheet();
}
QSlider *Slider::nativeWidget() const
{
return static_cast<QSlider*>(widget());
}
} // namespace Plasma
-#include <slider.moc>
+
+
+#include "moc_slider.cpp"
diff --git a/plasma/widgets/spinbox.cpp b/plasma/widgets/spinbox.cpp
index 9c1c3fe661..9815b37e1c 100644
--- a/plasma/widgets/spinbox.cpp
+++ b/plasma/widgets/spinbox.cpp
@@ -1,232 +1,234 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
* Copyright 2009 Davide Bettio <davide.bettio@kdemail.net>
*
* 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 "spinbox.h"
#include <QPainter>
#include <QStyleOptionSpinBox>
#include <QGraphicsView>
#include <kmimetype.h>
#include <knuminput.h>
#include "applet.h"
#include "framesvg.h"
#include "private/focusindicator_p.h"
#include "private/style_p.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
namespace Plasma
{
class SpinBoxPrivate : public ThemedWidgetInterface<SpinBox>
{
public:
SpinBoxPrivate(SpinBox *spinBox)
: ThemedWidgetInterface<SpinBox>(spinBox),
focusIndicator(0)
{
buttonColorForText = true;
}
~SpinBoxPrivate()
{
}
Plasma::Style::Ptr style;
Plasma::FrameSvg *background;
FocusIndicator *focusIndicator;
};
SpinBox::SpinBox(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new SpinBoxPrivate(this))
{
KIntSpinBox *native = new KIntSpinBox;
connect(native, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
connect(native, SIGNAL(editingFinished()), this, SIGNAL(editingFinished()));
d->focusIndicator = new FocusIndicator(this, "widgets/lineedit");
d->setWidget(native);
native->setWindowIcon(QIcon());
native->setAttribute(Qt::WA_NoSystemBackground);
native->setAutoFillBackground(false);
d->background = new Plasma::FrameSvg(this);
d->background->setImagePath("widgets/lineedit");
d->background->setCacheAllRenderedFrames(true);
if (d->background->hasElement("hint-focus-over-base")) {
d->focusIndicator->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
}
d->style = Plasma::Style::sharedStyle();
native->setStyle(d->style.data());
d->initTheming();
QStyleOptionSpinBox spinOpt;
spinOpt.initFrom(nativeWidget());
QRect controlrect = nativeWidget()->style()->subControlRect(QStyle::CC_SpinBox, &spinOpt, QStyle::SC_SpinBoxFrame, nativeWidget());
d->focusIndicator->setCustomGeometry(controlrect);
}
SpinBox::~SpinBox()
{
delete d;
Plasma::Style::doneWithSharedStyle();
}
void SpinBox::setMaximum(int max)
{
static_cast<KIntSpinBox*>(widget())->setMaximum(max);
}
int SpinBox::maximum() const
{
return static_cast<KIntSpinBox*>(widget())->maximum();
}
void SpinBox::setMinimum(int min)
{
static_cast<KIntSpinBox*>(widget())->setMinimum(min);
}
int SpinBox::minimum() const
{
return static_cast<KIntSpinBox*>(widget())->minimum();
}
void SpinBox::setRange(int min, int max)
{
static_cast<KIntSpinBox*>(widget())->setRange(min, max);
}
void SpinBox::setValue(int value)
{
static_cast<KIntSpinBox*>(widget())->setValue(value);
}
int SpinBox::value() const
{
return static_cast<KIntSpinBox*>(widget())->value();
}
void SpinBox::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString SpinBox::styleSheet()
{
return widget()->styleSheet();
}
KIntSpinBox *SpinBox::nativeWidget() const
{
return static_cast<KIntSpinBox*>(widget());
}
void SpinBox::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
void SpinBox::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
update();
}
void SpinBox::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
update();
}
void SpinBox::resizeEvent(QGraphicsSceneResizeEvent *event)
{
QGraphicsProxyWidget::resizeEvent(event);
QStyleOptionSpinBox spinOpt;
spinOpt.initFrom(nativeWidget());
QRect controlrect = nativeWidget()->style()->subControlRect(QStyle::CC_SpinBox, &spinOpt, QStyle::SC_SpinBoxFrame, nativeWidget());
if (d->focusIndicator) {
d->focusIndicator->setCustomGeometry(controlrect);
}
}
void SpinBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
QGraphicsProxyWidget::paint(painter, option, widget);
}
void SpinBox::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget *widget = parentWidget();
Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(widget);
while (!applet && widget) {
widget = widget->parentWidget();
applet = qobject_cast<Plasma::Applet *>(widget);
}
if (applet) {
applet->setStatus(Plasma::AcceptingInputStatus);
}
QGraphicsProxyWidget::mousePressEvent(event);
}
void SpinBox::focusOutEvent(QFocusEvent *event)
{
QGraphicsWidget *widget = parentWidget();
Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(widget);
while (!applet && widget) {
widget = widget->parentWidget();
applet = qobject_cast<Plasma::Applet *>(widget);
}
if (applet) {
applet->setStatus(Plasma::UnknownStatus);
}
QEvent closeEvent(QEvent::CloseSoftwareInputPanel);
if (qApp) {
if (QGraphicsView *view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
if (view->scene() && view->scene() == scene()) {
QApplication::sendEvent(view, &closeEvent);
}
}
}
QGraphicsProxyWidget::focusOutEvent(event);
}
} // namespace Plasma
-#include <spinbox.moc>
+
+
+#include "moc_spinbox.cpp"
diff --git a/plasma/widgets/svgwidget.cpp b/plasma/widgets/svgwidget.cpp
index f8aa8e5492..24816eb2bf 100644
--- a/plasma/widgets/svgwidget.cpp
+++ b/plasma/widgets/svgwidget.cpp
@@ -1,141 +1,144 @@
/*
* Copyright 2008 by Davide Bettio <davide.bettio@kdemail.net>
*
* 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 "svgwidget.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include "kdebug.h"
#include "svg.h"
namespace Plasma
{
class SvgWidgetPrivate
{
public:
SvgWidgetPrivate(SvgWidget *widget, Svg *s, const QString &element)
: q(widget), svg(s), elementID(element)
{
}
void svgChanged()
{
q->update();
}
SvgWidget *q;
Svg *svg;
QString elementID;
};
SvgWidget::SvgWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
: QGraphicsWidget(parent, wFlags),
d(new SvgWidgetPrivate(this, 0, QString()))
{
}
SvgWidget::SvgWidget(Svg *svg, const QString &elementID, QGraphicsItem *parent, Qt::WindowFlags wFlags)
: QGraphicsWidget(parent, wFlags),
d(new SvgWidgetPrivate(this, svg, elementID))
{
}
SvgWidget::~SvgWidget()
{
delete d;
}
void SvgWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// we check for receivers so that SvgWidgets that aren't being used for events remain "click
// transparent"
if (receivers(SIGNAL(clicked(Qt::MouseButton)))) {
event->accept();
} else {
QGraphicsWidget::mousePressEvent(event);
}
}
void SvgWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (boundingRect().contains(event->pos())) {
emit clicked(event->button());
}
}
void SvgWidget::setSvg(Svg *svg)
{
if (d->svg) {
disconnect(d->svg);
}
d->svg = svg;
if (svg) {
connect(svg, SIGNAL(repaintNeeded()), this, SLOT(svgChanged()));
}
update();
}
Svg *SvgWidget::svg() const
{
return d->svg;
}
void SvgWidget::setElementID(const QString &elementID)
{
if (d->svg) {
d->svg->setContainsMultipleImages(!elementID.isNull());
}
d->elementID = elementID;
update();
}
QString SvgWidget::elementID() const
{
return d->elementID;
}
void SvgWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
if (d->svg){
d->svg->paint(painter, boundingRect(), d->elementID);
}
}
QSizeF SvgWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
if (d->svg && which == Qt::PreferredSize) {
if (d->elementID.isNull()) {
return d->svg->size();
} else {
return d->svg->elementSize(d->elementID);
}
} else {
return QGraphicsWidget::sizeHint(which, constraint);
}
}
} // Plasma namespace
+
+
+#include "moc_svgwidget.cpp"
diff --git a/plasma/widgets/tabbar.cpp b/plasma/widgets/tabbar.cpp
index 191c67cb16..522e84a4b2 100644
--- a/plasma/widgets/tabbar.cpp
+++ b/plasma/widgets/tabbar.cpp
@@ -1,682 +1,684 @@
/*
* 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 "tabbar.h"
#include <QGraphicsLinearLayout>
#include <QGraphicsLayoutItem>
#include <QGraphicsProxyWidget>
#include <QGraphicsScene>
#include <QGraphicsSceneWheelEvent>
#include <QIcon>
#include <QMenu>
#include <QPainter>
#include <QParallelAnimationGroup>
#include <QString>
#include <QStyleOption>
#include <kdebug.h>
#include "animator.h"
#include "animations/animation.h"
#include "private/nativetabbar_p.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
namespace Plasma
{
class TabBarProxy : public QGraphicsProxyWidget
{
public:
TabBarProxy(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent)
{
native = new NativeTabBar();
native->setAttribute(Qt::WA_NoSystemBackground);
setWidget(native);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
}
void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
//Don't paint the child widgets
static_cast<NativeTabBar *>(QGraphicsProxyWidget::widget())->render(
painter, QPoint(0, 0), QRegion(), 0);
}
NativeTabBar *native;
};
class TabBarPrivate : public ThemedWidgetInterface<TabBar>
{
public:
TabBarPrivate(TabBar *parent)
: ThemedWidgetInterface<TabBar>(parent),
tabProxy(0),
currentIndex(0),
tabWidgetMode(true),
oldPageAnimId(-1),
newPageAnimId(-1),
tabBarShown(true)
{
}
~TabBarPrivate()
{
}
void updateTabWidgetMode();
void slidingCompleted(QGraphicsItem *item);
void slidingNewPageCompleted();
void slidingOldPageCompleted();
void shapeChanged(const KTabBar::Shape shape);
TabBarProxy *tabProxy;
QList<QGraphicsWidget *> pages;
QGraphicsWidget *emptyTabBarSpacer;
QGraphicsLinearLayout *mainLayout;
QGraphicsLinearLayout *tabWidgetLayout;
QGraphicsLinearLayout *tabBarLayout;
int currentIndex;
bool tabWidgetMode;
QWeakPointer<QGraphicsWidget> oldPage;
QWeakPointer<QGraphicsWidget> newPage;
int oldPageAnimId;
int newPageAnimId;
Animation *oldPageAnim;
Animation *newPageAnim;
QParallelAnimationGroup *animGroup;
bool tabBarShown;
QWeakPointer<QGraphicsWidget> firstPositionWidget;
QWeakPointer<QGraphicsWidget> lastPositionWidget;
};
void TabBarPrivate::updateTabWidgetMode()
{
if (!tabBarShown) {
return;
}
bool tabWidget = false;
foreach (QGraphicsWidget *page, pages) {
if (page->preferredSize() != QSize(0, 0)) {
tabWidget = true;
break;
}
}
if (tabWidget != tabWidgetMode) {
if (tabWidget) {
mainLayout->removeAt(0);
tabBarLayout->insertItem(1, tabProxy);
mainLayout->addItem(tabWidgetLayout);
} else {
mainLayout->removeAt(0);
tabBarLayout->removeAt(1);
mainLayout->addItem(tabProxy);
}
}
//always show the tabbar
//FIXME: Qt BUG: calling show on a child of an hidden item it shows it anyways
//so we avoid to call it if the parent is hidden
if (!tabWidget && q->isVisible()) {
q->setTabBarShown(true);
}
tabWidgetMode = tabWidget;
if (!tabWidgetMode) {
q->setMinimumSize(QSize(0, 0));
q->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
} else {
tabProxy->native->setMinimumSize(QSize(0,0));
tabProxy->setMinimumSize(QSize(0,0));
}
}
void TabBarPrivate::slidingNewPageCompleted()
{
if (newPage) {
tabWidgetLayout->addItem(newPage.data());
}
newPageAnimId = -1;
mainLayout->invalidate();
emit q->currentChanged(currentIndex);
q->setFlags(0);
}
void TabBarPrivate::slidingOldPageCompleted()
{
QGraphicsWidget *item = oldPageAnim->targetWidget();
oldPageAnimId = -1;
if (item) {
item->hide();
}
q->setFlags(0);
}
void TabBarPrivate::shapeChanged(const QTabBar::Shape shape)
{
//FIXME: QGraphicsLinearLayout doesn't have setDirection, so for now
// North is equal to south and East is equal to West
switch (shape) {
case QTabBar::RoundedWest:
case QTabBar::TriangularWest:
case QTabBar::RoundedEast:
case QTabBar::TriangularEast:
q->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
tabBarLayout->setOrientation(Qt::Vertical);
tabWidgetLayout->setOrientation(Qt::Horizontal);
tabWidgetLayout->itemAt(0)->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
if (tabWidgetLayout->count() > 1) {
tabWidgetLayout->itemAt(1)->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
}
tabProxy->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
break;
case QTabBar::RoundedSouth:
case QTabBar::TriangularSouth:
case QTabBar::RoundedNorth:
case QTabBar::TriangularNorth:
default:
q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
tabBarLayout->setOrientation(Qt::Horizontal);
tabWidgetLayout->setOrientation(Qt::Vertical);
tabWidgetLayout->itemAt(0)->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
if (tabWidgetLayout->count() > 1) {
tabWidgetLayout->itemAt(1)->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
}
tabProxy->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
}
tabProxy->setPreferredSize(tabProxy->native->sizeHint());
}
TabBar::TabBar(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new TabBarPrivate(this))
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
setContentsMargins(0,0,0,0);
d->tabProxy = new TabBarProxy(this);
d->tabWidgetLayout = new QGraphicsLinearLayout(Qt::Vertical);
d->tabBarLayout = new QGraphicsLinearLayout(Qt::Horizontal);
d->tabWidgetLayout->setContentsMargins(0,0,0,0);
d->mainLayout = new QGraphicsLinearLayout(Qt::Horizontal);
d->mainLayout->addItem(d->tabWidgetLayout);
setLayout(d->mainLayout);
d->mainLayout->setContentsMargins(0,0,0,0);
//simulate a page until there isn't one
//needed to make the widget resize well when there are no tab added
d->emptyTabBarSpacer = new QGraphicsWidget(this);
d->tabWidgetLayout->addItem(d->tabBarLayout);
d->tabWidgetLayout->addItem(d->emptyTabBarSpacer);
//tabBar is centered, so a stretch at begin one at the end
d->tabBarLayout->addStretch();
d->tabBarLayout->addItem(d->tabProxy);
d->tabBarLayout->addStretch();
d->tabBarLayout->setContentsMargins(0,0,0,0);
//d->tabBarLayout->setStretchFactor(d->tabProxy, 2);
d->newPageAnim = Animator::create(Animator::SlideAnimation);
d->oldPageAnim = Animator::create(Animator::SlideAnimation);
d->animGroup = new QParallelAnimationGroup(this);
d->animGroup->addAnimation(d->newPageAnim);
d->animGroup->addAnimation(d->oldPageAnim);
connect(d->tabProxy->native, SIGNAL(currentChanged(int)),
this, SLOT(setCurrentIndex(int)));
connect(d->tabProxy->native, SIGNAL(shapeChanged(QTabBar::Shape)),
this, SLOT(shapeChanged(QTabBar::Shape)));
connect(d->newPageAnim, SIGNAL(finished()), this, SLOT(slidingNewPageCompleted()));
connect(d->oldPageAnim, SIGNAL(finished()), this, SLOT(slidingOldPageCompleted()));
d->initTheming();
}
TabBar::~TabBar()
{
delete d;
}
int TabBar::insertTab(int index, const QIcon &icon, const QString &label,
QGraphicsLayoutItem *content)
{
QGraphicsWidget *page = new QGraphicsWidget(this);
page->setContentsMargins(0,0,0,0);
page->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
if (content) {
if (content->isLayout()) {
page->setLayout(static_cast<QGraphicsLayout *>(content));
} else {
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, page);
layout->setContentsMargins(0,0,0,0);
layout->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
layout->addItem(content);
page->setLayout(layout);
}
} else {
page->setPreferredSize(0, 0);
}
d->pages.insert(qBound(0, index, d->pages.count()), page);
if (d->pages.count() == 1) {
d->tabWidgetLayout->removeItem(d->emptyTabBarSpacer);
d->tabWidgetLayout->addItem(page);
page->setVisible(true);
page->setEnabled(true);
} else {
page->setVisible(false);
page->setEnabled(false);
}
d->tabProxy->setPreferredSize(d->tabProxy->native->sizeHint());
d->updateTabWidgetMode();
int actualIndex = d->tabProxy->native->insertTab(index, icon, label);
d->currentIndex = d->tabProxy->native->currentIndex();
d->tabProxy->setPreferredSize(d->tabProxy->native->sizeHint());
d->updateTabWidgetMode();
return actualIndex;
}
int TabBar::insertTab(int index, const QString &label, QGraphicsLayoutItem *content)
{
return insertTab(index, QIcon(), label, content);
}
int TabBar::addTab(const QIcon &icon, const QString &label, QGraphicsLayoutItem *content)
{
return insertTab(d->pages.count(), icon, label, content);
}
int TabBar::addTab(const QString &label, QGraphicsLayoutItem *content)
{
return insertTab(d->pages.count(), QIcon(), label, content);
}
int TabBar::currentIndex() const
{
return d->tabProxy->native->currentIndex();
}
void TabBar::resizeEvent(QGraphicsSceneResizeEvent * event)
{
if (!d->tabWidgetMode) {
d->tabProxy->setMinimumSize(event->newSize().toSize());
setMinimumSize(QSize(0, 0));
setMinimumHeight(d->tabProxy->widget()->minimumSizeHint().height());
setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
} else {
setMinimumSize(QSize(-1, -1));
d->tabProxy->native->setMinimumSize(QSize(0,0));
}
}
void TabBar::setCurrentIndex(int index)
{
if (index >= d->pages.count() ||
d->pages.count() < 2 ||
d->currentIndex == index) {
return;
}
d->oldPage = d->pages.value(d->currentIndex);
if (d->oldPage) {
d->tabWidgetLayout->removeItem(d->oldPage.data());
}
if (index >= 0) {
d->newPage = d->pages.value(index);
}
setFlags(QGraphicsItem::ItemClipsChildrenToShape);
//if an animation was in rogress hide everything to avoid an inconsistent state
if (d->animGroup->state() != QAbstractAnimation::Stopped) {
foreach (QGraphicsWidget *page, d->pages) {
page->hide();
}
d->animGroup->stop();
}
if (d->newPage) {
d->newPage.data()->show();
d->newPage.data()->setEnabled(true);
}
if (d->oldPage) {
d->oldPage.data()->show();
d->oldPage.data()->setEnabled(false);
}
if (d->newPage && d->oldPage) {
//FIXME: it seems necessary to resiz the thing 2 times to have effect
d->newPage.data()->resize(1,1);
d->newPage.data()->resize(d->oldPage.data()->size());
QRect beforeCurrentGeom(d->oldPage.data()->geometry().toRect());
beforeCurrentGeom.moveTopRight(beforeCurrentGeom.topLeft());
if (index > d->currentIndex) {
d->newPage.data()->setPos(d->oldPage.data()->geometry().topRight());
d->newPageAnim->setProperty("movementDirection", Animation::MoveLeft);
d->newPageAnim->setProperty("distancePointF", QPointF(d->oldPage.data()->size().width(), 0));
d->newPageAnim->setTargetWidget(d->newPage.data());
d->oldPageAnim->setProperty("movementDirection", Animation::MoveLeft);
d->oldPageAnim->setProperty("distancePointF", QPointF(beforeCurrentGeom.width(), 0));
d->oldPageAnim->setTargetWidget(d->oldPage.data());
d->animGroup->start();
} else {
d->newPage.data()->setPos(beforeCurrentGeom.topLeft());
d->newPageAnim->setProperty("movementDirection", Animation::MoveRight);
d->newPageAnim->setProperty("distancePointF", QPointF(d->oldPage.data()->size().width(), 0));
d->newPageAnim->setTargetWidget(d->newPage.data());
d->oldPageAnim->setProperty("movementDirection", Animation::MoveRight);
d->oldPageAnim->setProperty("distancePointF",
QPointF(d->oldPage.data()->size().width(), 0));
d->oldPageAnim->setTargetWidget(d->oldPage.data());
d->animGroup->start();
}
} else if (d->newPage) {
d->tabWidgetLayout->addItem(d->newPage.data());
}
d->currentIndex = index;
d->tabProxy->native->setCurrentIndex(index);
}
int TabBar::count() const
{
return d->pages.count();
}
void TabBar::removeTab(int index)
{
if (index >= d->pages.count() || index < 0) {
return;
}
d->newPageAnim->stop();
d->oldPageAnim->stop();
int oldCurrentIndex = d->tabProxy->native->currentIndex();
d->tabProxy->native->removeTab(index);
d->currentIndex = oldCurrentIndex;
int currentIndex = d->tabProxy->native->currentIndex();
if (oldCurrentIndex == index) {
d->tabWidgetLayout->removeAt(1);
if (d->tabProxy->native->count() > 0) {
setCurrentIndex(currentIndex >= oldCurrentIndex ? currentIndex + 1 : currentIndex);
}
}
QGraphicsWidget *page = d->pages.takeAt(index);
scene()->removeItem(page);
page->deleteLater();
if (d->pages.count() > 0) {
d->updateTabWidgetMode();
} else {
d->tabWidgetLayout->addItem(d->emptyTabBarSpacer);
}
}
QGraphicsLayoutItem *TabBar::takeTab(int index)
{
if (index >= d->pages.count()) {
return 0;
}
int oldCurrentIndex = d->tabProxy->native->currentIndex();
d->tabProxy->native->removeTab(index);
int currentIndex = d->tabProxy->native->currentIndex();
if (oldCurrentIndex == index) {
d->tabWidgetLayout->removeAt(1);
if (d->tabProxy->native->count() > 0) {
setCurrentIndex(currentIndex >= oldCurrentIndex ? currentIndex + 1 : currentIndex);
}
}
QGraphicsWidget *page = d->pages.takeAt(index);
QGraphicsLayoutItem *returnItem = 0;
QGraphicsLayout *lay = page->layout();
if (lay && lay->count() == 1) {
returnItem = lay->itemAt(0);
lay->removeAt(0);
} else {
returnItem = lay;
}
if (returnItem) {
returnItem->setParentLayoutItem(0);
if (QGraphicsItem *item = returnItem->graphicsItem()) {
item->setParentItem(0);
}
}
page->setLayout(0);
scene()->removeItem(page);
page->deleteLater();
if (oldCurrentIndex != currentIndex) {
setCurrentIndex(currentIndex);
}
d->updateTabWidgetMode();
d->tabProxy->setPreferredSize(d->tabProxy->native->sizeHint());
return returnItem;
}
QGraphicsLayoutItem *TabBar::tabAt(int index)
{
if (index >= d->pages.count()) {
return 0;
}
QGraphicsWidget *page = d->pages.value(index);
QGraphicsLayoutItem *returnItem = 0;
QGraphicsLayout *lay = page->layout();
if (lay && lay->count() == 1) {
returnItem = lay->itemAt(0);
} else {
returnItem = lay;
}
return returnItem;
}
void TabBar::setTabText(int index, const QString &label)
{
if (index >= d->pages.count()) {
return;
}
d->tabProxy->native->setTabText(index, label);
}
QString TabBar::tabText(int index) const
{
return d->tabProxy->native->tabText(index);
}
void TabBar::setTabIcon(int index, const QIcon &icon)
{
d->tabProxy->native->setTabIcon(index, icon);
}
QIcon TabBar::tabIcon(int index) const
{
return d->tabProxy->native->tabIcon(index);
}
void TabBar::setTabBarShown(bool show)
{
if (!show && !d->tabWidgetMode) {
return;
}
if (d->tabBarShown == show) {
return;
}
d->tabBarShown = show;
if (!show) {
d->tabProxy->hide();
d->tabWidgetLayout->removeItem(d->tabBarLayout);
} else {
d->tabProxy->show();
d->tabWidgetLayout->insertItem(0, d->tabBarLayout);
}
}
bool TabBar::isTabBarShown() const
{
return d->tabBarShown;
}
void TabBar::setStyleSheet(const QString &stylesheet)
{
d->tabProxy->native->setStyleSheet(stylesheet);
}
QString TabBar::styleSheet() const
{
return d->tabProxy->native->styleSheet();
}
void TabBar::setTabHighlighted(int index, bool highlight)
{
d->tabProxy->native->setTabHighlighted(index, highlight);
}
bool TabBar::isTabHighlighted(int index) const
{
return d->tabProxy->native->isTabHighlighted(index);
}
KTabBar *TabBar::nativeWidget() const
{
return d->tabProxy->native;
}
void TabBar::wheelEvent(QGraphicsSceneWheelEvent * event)
{
Q_UNUSED(event)
//Still here for binary compatibility
}
void TabBar::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsWidget::changeEvent(event);
}
void TabBar::setFirstPositionWidget(QGraphicsWidget *widget)
{
if (d->lastPositionWidget.data() == widget) {
return;
}
if (d->firstPositionWidget) {
QGraphicsWidget *widget = d->firstPositionWidget.data();
d->tabBarLayout->removeItem(widget);
scene()->removeItem(widget);
widget->deleteLater();
}
d->firstPositionWidget = widget;
if (widget) {
widget->setParentItem(this);
if (layoutDirection() == Qt::LeftToRight) {
d->tabBarLayout->insertItem(0, widget);
} else {
d->tabBarLayout->addItem(widget);
}
}
}
QGraphicsWidget *TabBar::firstPositionWidget() const
{
return d->firstPositionWidget.data();
}
void TabBar::setLastPositionWidget(QGraphicsWidget *widget)
{
if (d->lastPositionWidget.data() == widget) {
return;
}
if (d->lastPositionWidget) {
QGraphicsWidget *widget = d->lastPositionWidget.data();
d->tabBarLayout->removeItem(widget);
scene()->removeItem(widget);
widget->deleteLater();
}
d->lastPositionWidget = widget;
if (widget) {
widget->setParentItem(this);
if (layoutDirection() == Qt::LeftToRight) {
d->tabBarLayout->addItem(widget);
} else {
d->tabBarLayout->insertItem(0, widget);
}
}
}
QGraphicsWidget *TabBar::lastPositionWidget() const
{
return d->lastPositionWidget.data();
}
} // namespace Plasma
-#include <tabbar.moc>
+
+
+#include "moc_tabbar.cpp"
diff --git a/plasma/widgets/textbrowser.cpp b/plasma/widgets/textbrowser.cpp
index 870d570e0f..43bf3689d6 100644
--- a/plasma/widgets/textbrowser.cpp
+++ b/plasma/widgets/textbrowser.cpp
@@ -1,193 +1,195 @@
/*
* Copyright 2009 Marco Martin <notmart@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "textbrowser.h"
#include <QGraphicsSceneWheelEvent>
#include <QMenu>
#include <QPainter>
#include <QScrollBar>
#include <kmimetype.h>
#include <ktextbrowser.h>
#include "svg.h"
#include "theme.h"
#include "private/style_p.h"
#include "private/themedwidgetinterface_p.h"
namespace Plasma
{
class TextBrowserPrivate : public ThemedWidgetInterface<TextBrowser>
{
public:
TextBrowserPrivate(TextBrowser *browser)
: ThemedWidgetInterface<TextBrowser>(browser),
savedMinimumHeight(0),
savedMaximumHeight(QWIDGETSIZE_MAX),
wasNotFixed(true)
{
}
void setFixedHeight()
{
KTextBrowser *native = q->nativeWidget();
if (native->document() &&
q->sizePolicy().verticalPolicy() == QSizePolicy::Fixed &&
native->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
native->document()->setTextWidth(q->size().width());
QSize s = native->document()->size().toSize();
if (wasNotFixed) {
savedMinimumHeight = q->minimumHeight();
savedMaximumHeight = q->maximumHeight();
wasNotFixed = false;
}
q->setMinimumHeight(s.height());
q->setMaximumHeight(s.height());
} else if (!wasNotFixed) {
q->setMinimumHeight(savedMinimumHeight);
q->setMaximumHeight(savedMaximumHeight);
wasNotFixed = true;
}
}
KTextBrowser *native;
Plasma::Style::Ptr style;
int savedMinimumHeight;
int savedMaximumHeight;
bool wasNotFixed;
};
TextBrowser::TextBrowser(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new TextBrowserPrivate(this))
{
KTextBrowser *native = new KTextBrowser;
native->setWindowFlags(native->windowFlags()|Qt::BypassGraphicsProxyWidget);
connect(native, SIGNAL(textChanged()), this, SIGNAL(textChanged()));
connect(native, SIGNAL(textChanged()), this, SLOT(setFixedHeight()));
native->setWindowIcon(QIcon());
d->setWidget(native);
d->native = native;
native->setAttribute(Qt::WA_NoSystemBackground);
native->setFrameShape(QFrame::NoFrame);
native->setTextBackgroundColor(Qt::transparent);
native->viewport()->setAutoFillBackground(false);
d->style = Plasma::Style::sharedStyle();
native->verticalScrollBar()->setStyle(d->style.data());
native->horizontalScrollBar()->setStyle(d->style.data());
d->initTheming();
}
TextBrowser::~TextBrowser()
{
delete d;
Plasma::Style::doneWithSharedStyle();
}
void TextBrowser::setText(const QString &text)
{
static_cast<KTextBrowser*>(widget())->setText(text);
}
QString TextBrowser::text() const
{
return static_cast<KTextBrowser*>(widget())->toHtml();
}
void TextBrowser::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
{
nativeWidget()->setHorizontalScrollBarPolicy(policy);
}
void TextBrowser::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
{
nativeWidget()->setVerticalScrollBarPolicy(policy);
}
void TextBrowser::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString TextBrowser::styleSheet()
{
return widget()->styleSheet();
}
KTextBrowser *TextBrowser::nativeWidget() const
{
return static_cast<KTextBrowser*>(widget());
}
void TextBrowser::append(const QString &text)
{
return nativeWidget()->append(text);
}
void TextBrowser::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
{
Q_UNUSED(sourceName)
KTextBrowser *te = nativeWidget();
te->clear();
foreach (const QVariant &v, data) {
if (v.canConvert(QVariant::String)) {
te->append(v.toString() + '\n');
}
}
}
void TextBrowser::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
QMenu *popup = nativeWidget()->createStandardContextMenu(event->screenPos());
if (popup) {
popup->exec(event->screenPos());
delete popup;
}
}
void TextBrowser::resizeEvent(QGraphicsSceneResizeEvent *event)
{
d->setFixedHeight();
QGraphicsProxyWidget::resizeEvent(event);
}
void TextBrowser::wheelEvent(QGraphicsSceneWheelEvent *event)
{
if (nativeWidget()->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff &&
nativeWidget()->horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
event->ignore();
} else {
QGraphicsProxyWidget::wheelEvent(event);
}
}
void TextBrowser::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
} // namespace Plasma
-#include <textbrowser.moc>
+
+
+#include "moc_textbrowser.cpp"
diff --git a/plasma/widgets/textedit.cpp b/plasma/widgets/textedit.cpp
index 271f6cbfc6..c98871d94c 100644
--- a/plasma/widgets/textedit.cpp
+++ b/plasma/widgets/textedit.cpp
@@ -1,207 +1,209 @@
/*
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "textedit.h"
#include <QGraphicsSceneContextMenuEvent>
#include <QMenu>
#include <QPainter>
#include <QScrollBar>
#include <QGraphicsView>
#include <kmimetype.h>
#include <ktextedit.h>
#include "applet.h"
#include "private/style_p.h"
#include "private/themedwidgetinterface_p.h"
#include "svg.h"
#include "theme.h"
namespace Plasma
{
class TextEditPrivate : public ThemedWidgetInterface<TextEdit>
{
public:
TextEditPrivate(TextEdit *textEdit)
: ThemedWidgetInterface<TextEdit>(textEdit)
{
}
~TextEditPrivate()
{
}
Plasma::Style::Ptr style;
};
TextEdit::TextEdit(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new TextEditPrivate(this))
{
setNativeWidget(new KTextEdit);
d->style = Plasma::Style::sharedStyle();
d->initTheming();
}
TextEdit::~TextEdit()
{
delete d;
Plasma::Style::doneWithSharedStyle();
}
void TextEdit::setText(const QString &text)
{
static_cast<KTextEdit*>(widget())->setText(text);
}
QString TextEdit::text() const
{
return static_cast<KTextEdit*>(widget())->toHtml();
}
void TextEdit::setReadOnly(bool readOnly)
{
static_cast<KTextEdit*>(widget())->setReadOnly(readOnly);
}
bool TextEdit::isReadOnly() const
{
return static_cast<KTextEdit*>(widget())->isReadOnly();
}
void TextEdit::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString TextEdit::styleSheet()
{
return widget()->styleSheet();
}
void TextEdit::setNativeWidget(KTextEdit *nativeWidget)
{
if (widget()) {
widget()->deleteLater();
}
nativeWidget->setWindowFlags(nativeWidget->windowFlags()|Qt::BypassGraphicsProxyWidget);
connect(nativeWidget, SIGNAL(textChanged()), this, SIGNAL(textChanged()));
nativeWidget->setWindowIcon(QIcon());
d->setWidget(nativeWidget);
nativeWidget->setAttribute(Qt::WA_NoSystemBackground);
nativeWidget->setFrameShape(QFrame::NoFrame);
nativeWidget->viewport()->setAutoFillBackground(false);
nativeWidget->verticalScrollBar()->setStyle(d->style.data());
nativeWidget->horizontalScrollBar()->setStyle(d->style.data());
}
KTextEdit *TextEdit::nativeWidget() const
{
return static_cast<KTextEdit*>(widget());
}
void TextEdit::append(const QString &text)
{
return nativeWidget()->append(text);
}
void TextEdit::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
{
Q_UNUSED(sourceName)
KTextEdit *te = nativeWidget();
te->clear();
foreach (const QVariant &v, data) {
if (v.canConvert(QVariant::String)) {
te->append(v.toString() + '\n');
}
}
}
void TextEdit::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
QMenu *popup = nativeWidget()->mousePopupMenu();
popup->exec(event->screenPos());
delete popup;
}
void TextEdit::resizeEvent(QGraphicsSceneResizeEvent *event)
{
QGraphicsProxyWidget::resizeEvent(event);
}
void TextEdit::changeEvent(QEvent *event)
{
d->changeEvent(event);
QGraphicsProxyWidget::changeEvent(event);
}
void TextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget *widget = parentWidget();
Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(widget);
while (!applet && widget) {
widget = widget->parentWidget();
applet = qobject_cast<Plasma::Applet *>(widget);
}
if (applet) {
applet->setStatus(Plasma::AcceptingInputStatus);
}
QGraphicsProxyWidget::mousePressEvent(event);
}
void TextEdit::focusOutEvent(QFocusEvent *event)
{
QGraphicsWidget *widget = parentWidget();
Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(widget);
while (!applet && widget) {
widget = widget->parentWidget();
applet = qobject_cast<Plasma::Applet *>(widget);
}
if (applet) {
applet->setStatus(Plasma::UnknownStatus);
}
QEvent closeEvent(QEvent::CloseSoftwareInputPanel);
if (qApp) {
if (QGraphicsView *view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
if (view->scene() && view->scene() == scene()) {
QApplication::sendEvent(view, &closeEvent);
}
}
}
QGraphicsProxyWidget::focusOutEvent(event);
}
} // namespace Plasma
-#include <textedit.moc>
+
+
+#include "moc_textedit.cpp"
diff --git a/plasma/widgets/toolbutton.cpp b/plasma/widgets/toolbutton.cpp
index ee9ed6a6cf..e9f1e021d7 100644
--- a/plasma/widgets/toolbutton.cpp
+++ b/plasma/widgets/toolbutton.cpp
@@ -1,460 +1,462 @@
/*
* 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 "toolbutton.h"
#include <QDir>
#include <QPainter>
#include <QPropertyAnimation>
#include <QStyleOptionGraphicsItem>
#include <QToolButton>
#include <kcolorutils.h>
#include <kicon.h>
#include <kiconeffect.h>
#include <kmimetype.h>
#include "animator.h"
#include "framesvg.h"
#include "paintutils.h"
#include "private/actionwidgetinterface_p.h"
#include "private/themedwidgetinterface_p.h"
#include "theme.h"
namespace Plasma
{
class ToolButtonPrivate : public ActionWidgetInterface<ToolButton>
{
public:
ToolButtonPrivate(ToolButton *toolButton)
: ActionWidgetInterface<ToolButton>(toolButton),
background(0),
svg(0),
underMouse(false)
{
}
~ToolButtonPrivate()
{
delete svg;
}
void setPixmap()
{
if (imagePath.isEmpty()) {
delete svg;
svg = 0;
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
QPixmap pm;
if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {
if (!svg || svg->imagePath() != absImagePath) {
delete svg;
svg = new Svg();
svg->setImagePath(imagePath);
QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap()));
if (!svgElement.isNull()) {
svg->setContainsMultipleImages(true);
}
}
//QPainter p(&pm);
if (!svgElement.isNull() && svg->hasElement(svgElement)) {
QSizeF elementSize = svg->elementSize(svgElement);
float scale = pm.width() / qMax(elementSize.width(), elementSize.height());
svg->resize(svg->size() * scale);
pm = svg->pixmap(svgElement);
} else {
svg->resize(pm.size());
pm = svg->pixmap();
}
} else {
delete svg;
svg = 0;
pm = QPixmap(absImagePath);
}
static_cast<QToolButton*>(q->widget())->setIcon(KIcon(pm));
}
void syncActiveRect();
void syncBorders();
void animationUpdate(qreal progress);
FrameSvg *background;
QPropertyAnimation *animation;
qreal opacity;
QRectF activeRect;
QString imagePath;
QString absImagePath;
Svg *svg;
QString svgElement;
bool underMouse;
};
void ToolButtonPrivate::syncActiveRect()
{
background->setElementPrefix("normal");
qreal left, top, right, bottom;
background->getMargins(left, top, right, bottom);
background->setElementPrefix("active");
qreal activeLeft, activeTop, activeRight, activeBottom;
background->getMargins(activeLeft, activeTop, activeRight, activeBottom);
activeRect = QRectF(QPointF(0, 0), q->size());
activeRect.adjust(left - activeLeft, top - activeTop,
-(right - activeRight), -(bottom - activeBottom));
background->setElementPrefix("normal");
}
void ToolButtonPrivate::syncBorders()
{
//set margins from the normal element
qreal left, top, right, bottom;
background->setElementPrefix("normal");
background->getMargins(left, top, right, bottom);
q->setContentsMargins(left, top, right, bottom);
//calc the rect for the over effect
syncActiveRect();
}
void ToolButtonPrivate::animationUpdate(qreal progress)
{
opacity = progress;
// explicit update
q->update();
}
ToolButton::ToolButton(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new ToolButtonPrivate(this))
{
d->background = new FrameSvg(this);
d->background->setImagePath("widgets/button");
d->background->setCacheAllRenderedFrames(true);
d->background->setElementPrefix("normal");
QToolButton *native = new QToolButton;
connect(native, SIGNAL(clicked()), this, SIGNAL(clicked()));
connect(native, SIGNAL(pressed()), this, SIGNAL(pressed()));
connect(native, SIGNAL(released()), this, SIGNAL(released()));
setWidget(native);
native->setWindowIcon(QIcon());
native->setAttribute(Qt::WA_NoSystemBackground);
native->setAutoRaise(true);
d->syncBorders();
setAcceptHoverEvents(true);
connect(d->background, SIGNAL(repaintNeeded()), SLOT(syncBorders()));
d->animation = new QPropertyAnimation(this, "animationUpdate");
d->animation->setStartValue(0);
d->animation->setEndValue(1);
d->initTheming();
}
ToolButton::~ToolButton()
{
delete d->animation;
delete d;
}
void ToolButton::setAnimationUpdate(qreal progress)
{
d->animationUpdate(progress);
}
qreal ToolButton::animationUpdate() const
{
return d->opacity;
}
void ToolButton::setAction(QAction *action)
{
d->setAction(action);
}
QAction *ToolButton::action() const
{
return d->action;
}
void ToolButton::setAutoRaise(bool raise)
{
nativeWidget()->setAutoRaise(raise);
}
bool ToolButton::autoRaise() const
{
return nativeWidget()->autoRaise();
}
void ToolButton::setText(const QString &text)
{
static_cast<QToolButton*>(widget())->setText(text);
updateGeometry();
}
QString ToolButton::text() const
{
return static_cast<QToolButton*>(widget())->text();
}
void ToolButton::setImage(const QString &path)
{
if (d->imagePath == path) {
return;
}
delete d->svg;
d->svg = 0;
d->imagePath = path;
bool absolutePath = !path.isEmpty() &&
#ifdef Q_WS_WIN
!QDir::isRelativePath(path)
#else
(path[0] == '/' || path.startsWith(QLatin1String(":/")))
#endif
;
if (absolutePath) {
d->absImagePath = path;
} else {
//TODO: package support
d->absImagePath = Theme::defaultTheme()->imagePath(path);
}
d->setPixmap();
}
void ToolButton::setImage(const QString &path, const QString &elementid)
{
d->svgElement = elementid;
setImage(path);
}
void ToolButton::setIcon(const QIcon &icon)
{
nativeWidget()->setIcon(icon);
}
QIcon ToolButton::icon() const
{
return nativeWidget()->icon();
}
QString ToolButton::image() const
{
return d->imagePath;
}
void ToolButton::setDown(bool down)
{
nativeWidget()->setDown(down);
}
bool ToolButton::isDown() const
{
return nativeWidget()->isDown();
}
void ToolButton::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString ToolButton::styleSheet()
{
return widget()->styleSheet();
}
QToolButton *ToolButton::nativeWidget() const
{
return static_cast<QToolButton*>(widget());
}
void ToolButton::resizeEvent(QGraphicsSceneResizeEvent *event)
{
d->setPixmap();
if (d->background) {
//resize all four panels
d->background->setElementPrefix("pressed");
d->background->resizeFrame(size());
d->background->setElementPrefix("focus");
d->background->resizeFrame(size());
d->syncActiveRect();
d->background->setElementPrefix("active");
d->background->resizeFrame(d->activeRect.size());
d->background->setElementPrefix("normal");
d->background->resizeFrame(size());
}
QGraphicsProxyWidget::resizeEvent(event);
}
void ToolButton::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
if (!styleSheet().isNull() || Theme::defaultTheme()->useNativeWidgetStyle()) {
QGraphicsProxyWidget::paint(painter, option, widget);
return;
}
QToolButton *button = nativeWidget();
QStyleOptionToolButton buttonOpt;
buttonOpt.initFrom(button);
buttonOpt.icon = button->icon();
buttonOpt.text = button->text();
buttonOpt.iconSize = button->iconSize();
buttonOpt.toolButtonStyle = button->toolButtonStyle();
bool animationState = (d->animation->state() == QAbstractAnimation::Running)? \
1:0;
if (button->isEnabled() && (animationState || !button->autoRaise() || d->underMouse || (buttonOpt.state & QStyle::State_On) || button->isChecked() || button->isDown())) {
if (button->isDown() || (buttonOpt.state & QStyle::State_On) || button->isChecked()) {
d->background->setElementPrefix("pressed");
} else {
d->background->setElementPrefix("normal");
}
d->background->resizeFrame(size());
if (animationState) {
QPixmap buffer = d->background->framePixmap();
QPainter bufferPainter(&buffer);
bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
QColor alphaColor(Qt::black);
alphaColor.setAlphaF(qMin(qreal(0.95), d->opacity));
bufferPainter.fillRect(buffer.rect(), alphaColor);
bufferPainter.end();
painter->drawPixmap(QPoint(0,0), buffer);
buttonOpt.palette.setColor(QPalette::ButtonText, KColorUtils::mix(Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor), Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor), 1-d->opacity));
} else {
d->background->paintFrame(painter);
buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor));
}
} else {
buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
}
buttonOpt.font = font();
painter->setFont(buttonOpt.font);
button->style()->drawControl(QStyle::CE_ToolButtonLabel, &buttonOpt, painter, button);
}
void ToolButton::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
d->underMouse = true;
if (nativeWidget()->isDown() || !nativeWidget()->autoRaise()) {
return;
}
const int FadeInDuration = 75;
if (d->animation->state() != QAbstractAnimation::Stopped) {
d->animation->stop();
}
d->animation->setDuration(FadeInDuration);
d->animation->setDirection(QAbstractAnimation::Forward);
d->animation->start();
d->background->setElementPrefix("active");
QGraphicsProxyWidget::hoverEnterEvent(event);
}
void ToolButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
d->underMouse = false;
if (nativeWidget()->isDown() || !nativeWidget()->autoRaise()) {
return;
}
const int FadeOutDuration = 150;
if (d->animation->state() != QAbstractAnimation::Stopped) {
d->animation->stop();
}
d->animation->setDuration(FadeOutDuration);
d->animation->setDirection(QAbstractAnimation::Backward);
d->animation->start();
d->background->setElementPrefix("active");
QGraphicsProxyWidget::hoverLeaveEvent(event);
}
void ToolButton::changeEvent(QEvent *event)
{
d->changeEvent(event);
if (event->type() == QEvent::EnabledChange && !isEnabled()) {
d->underMouse = false;
}
QGraphicsProxyWidget::changeEvent(event);
}
QVariant ToolButton::itemChange(GraphicsItemChange change, const QVariant &value)
{
//If the widget is hidden while it's hovered and then we show it again
//we have to disable the hover otherwise it will remain hovered.
if (change == ItemVisibleHasChanged){
d->underMouse = false;
}
return QGraphicsProxyWidget::itemChange(change, value);
}
QSizeF ToolButton::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
QSizeF hint = QGraphicsProxyWidget::sizeHint(which, constraint);
return hint;
}
} // namespace Plasma
-#include <toolbutton.moc>
+
+
+#include "moc_toolbutton.cpp"
diff --git a/plasma/widgets/treeview.cpp b/plasma/widgets/treeview.cpp
index ca77066023..797f16828c 100644
--- a/plasma/widgets/treeview.cpp
+++ b/plasma/widgets/treeview.cpp
@@ -1,88 +1,90 @@
/*
* 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 "treeview.h"
#include <QTreeView>
#include <QHeaderView>
#include <QScrollBar>
#include <kiconloader.h>
#include "private/style_p.h"
namespace Plasma
{
class TreeViewPrivate
{
public:
Plasma::Style::Ptr style;
};
TreeView::TreeView(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new TreeViewPrivate)
{
QTreeView *native = new QTreeView;
setWidget(native);
native->setWindowIcon(QIcon());
native->setAttribute(Qt::WA_NoSystemBackground);
native->setFrameStyle(QFrame::NoFrame);
d->style = Plasma::Style::sharedStyle();
native->verticalScrollBar()->setStyle(d->style.data());
native->horizontalScrollBar()->setStyle(d->style.data());
}
TreeView::~TreeView()
{
delete d;
Plasma::Style::doneWithSharedStyle();
}
void TreeView::setModel(QAbstractItemModel *model)
{
nativeWidget()->setModel(model);
}
QAbstractItemModel *TreeView::model()
{
return nativeWidget()->model();
}
void TreeView::setStyleSheet(const QString &stylesheet)
{
widget()->setStyleSheet(stylesheet);
}
QString TreeView::styleSheet()
{
return widget()->styleSheet();
}
QTreeView *TreeView::nativeWidget() const
{
return static_cast<QTreeView*>(widget());
}
}
-#include <treeview.moc>
+
+
+#include "moc_treeview.cpp"
diff --git a/plasma/widgets/videowidget.cpp b/plasma/widgets/videowidget.cpp
index d79a9fd957..360ad68656 100644
--- a/plasma/widgets/videowidget.cpp
+++ b/plasma/widgets/videowidget.cpp
@@ -1,639 +1,641 @@
/*
* Copyright 2009 Marco Martin <notmart@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "videowidget.h"
#include "config-plasma.h"
#include <QUrl>
#include <QTimer>
#include <QGraphicsLinearLayout>
#include <QGraphicsSceneResizeEvent>
#include <kicon.h>
#include <kiconloader.h>
#ifndef PLASMA_NO_KIO
#include <kfiledialog.h>
#else
#include <QFileDialog>
#endif
#include <phonon/videowidget.h>
#include <phonon/mediaobject.h>
#include <phonon/mediasource.h>
#include <phonon/audiooutput.h>
#include <plasma/animations/animation.h>
#include <plasma/widgets/iconwidget.h>
#include <plasma/widgets/slider.h>
#include <plasma/widgets/frame.h>
namespace Plasma
{
class VideoWidgetPrivate
{
public:
VideoWidgetPrivate(VideoWidget *video)
: q(video),
ticking(false),
forceControlsVisible(false),
animation(0),
hideTimer(0),
shownControls(VideoWidget::NoControls),
controlsWidget(0),
previousButton(0),
playButton(0),
pauseButton(0),
stopButton(0),
playPauseButton(0),
nextButton(0),
progress(0),
volume(0),
openFileButton(0)
{
}
~VideoWidgetPrivate()
{
}
void playPause();
void ticked(qint64 progress);
void totalTimeChanged(qint64 time);
void setPosition(int newProgress);
void setVolume(int value);
void volumeChanged(qreal value);
void showOpenFileDialog();
void openFile(const QString &path);
void stateChanged(Phonon::State newState, Phonon::State oldState);
void animateControlWidget(bool show);
void hideControlWidget();
void slidingCompleted();
bool spaceForControlsAvailable();
VideoWidget *q;
Phonon::VideoWidget *videoWidget;
Phonon::AudioOutput *audioOutput;
Phonon::MediaObject *media;
bool ticking;
bool forceControlsVisible;
//control widgets
Plasma::Animation *animation;
QTimer *hideTimer;
VideoWidget::Controls shownControls;
Plasma::Frame *controlsWidget;
IconWidget *previousButton;
IconWidget *playButton;
IconWidget *pauseButton;
IconWidget *stopButton;
IconWidget *playPauseButton;
IconWidget *nextButton;
Slider *progress;
Slider *volume;
IconWidget *openFileButton;
};
void VideoWidgetPrivate::playPause()
{
if (media->state() == Phonon::PlayingState) {
media->pause();
} else {
media->play();
}
}
void VideoWidgetPrivate::ticked(qint64 newProgress)
{
ticking = true;
progress->setValue(newProgress);
ticking = false;
}
void VideoWidgetPrivate::totalTimeChanged(qint64 time)
{
ticking = true;
//FIXME: this will break for veeery long stuff, butPhonon::SeekSlider seems to have the same problem
progress->setRange(0, time);
ticking = false;
}
void VideoWidgetPrivate::setPosition(int progress)
{
if (!ticking) {
media->seek(progress);
}
}
void VideoWidgetPrivate::setVolume(int value)
{
audioOutput->setVolume(qreal(value)/100.0);
}
void VideoWidgetPrivate::volumeChanged(qreal value)
{
volume->setValue(value*100);
}
void VideoWidgetPrivate::showOpenFileDialog()
{
#ifndef PLASMA_NO_KIO
openFile(KFileDialog::getOpenFileName());
#else
openFile(QFileDialog::getOpenFileName());
#endif
}
void VideoWidgetPrivate::openFile(const QString &path)
{
media->setCurrentSource(Phonon::MediaSource(path));
media->play();
}
void VideoWidgetPrivate::stateChanged(Phonon::State newState, Phonon::State oldState)
{
Q_UNUSED(oldState)
if (playPauseButton) {
if (newState == Phonon::PlayingState) {
playPauseButton->setIcon("media-playback-pause");
} else {
playPauseButton->setIcon("media-playback-start");
}
}
}
void VideoWidgetPrivate::animateControlWidget(bool show)
{
if (!controlsWidget || controlsWidget->isVisible() == show) {
return;
}
const int distance = controlsWidget->size().height();
if (!controlsWidget->isVisible()) {
controlsWidget->setPos(0, -distance);
controlsWidget->show();
}
//clip only when animating
q->setFlags(q->flags()|QGraphicsItem::ItemClipsChildrenToShape);
if (!animation) {
animation = Plasma::Animator::create(Plasma::Animator::SlideAnimation, q);
animation->setTargetWidget(controlsWidget);
animation->setProperty("movementDirection", Animation::MoveDown);
q->connect(animation, SIGNAL(finished()), q, SLOT(slidingCompleted()));
}
animation->setProperty("distance", distance);
animation->setProperty("direction", show? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
animation->start();
}
void VideoWidgetPrivate::hideControlWidget()
{
animateControlWidget(false);
}
void VideoWidgetPrivate::slidingCompleted()
{
if (!controlsWidget) {
return;
}
//usually don't clip
q->setFlags(q->flags()^QGraphicsItem::ItemClipsChildrenToShape);
if (controlsWidget->pos().y() < 0) {
controlsWidget->hide();
} else if (!forceControlsVisible) {
hideTimer->start(3000);
}
}
bool VideoWidgetPrivate::spaceForControlsAvailable()
{
if (controlsWidget) {
QSize hint = controlsWidget->effectiveSizeHint(Qt::MinimumSize).toSize();
return (q->size().width() >= hint.width()) &&
(q->size().height() >= hint.height());
} else {
return true;
}
}
VideoWidget::VideoWidget(QGraphicsWidget *parent)
: QGraphicsProxyWidget(parent),
d(new VideoWidgetPrivate(this))
{
d->videoWidget = new Phonon::VideoWidget;
d->audioOutput = new Phonon::AudioOutput(this);
d->media = new Phonon::MediaObject(this);
//it appears that the path has to be created BEFORE setting the proxy
Phonon::createPath(d->media, d->videoWidget);
Phonon::createPath(d->media, d->audioOutput);
setWidget(d->videoWidget);
d->videoWidget->setWindowIcon(QIcon());
setAcceptHoverEvents(true);
connect(d->media, SIGNAL(tick(qint64)), this, SIGNAL(tick(qint64)));
connect(d->media, SIGNAL(aboutToFinish()), this, SIGNAL(aboutToFinish()));
}
VideoWidget::~VideoWidget()
{
delete d;
}
Phonon::MediaObject *VideoWidget::mediaObject() const
{
return d->media;
}
Phonon::AudioOutput *VideoWidget::audioOutput() const
{
return d->audioOutput;
}
void VideoWidget::setUrl(const QString &url)
{
QString fileUrl;
if (url.startsWith('/')) {
fileUrl = "file://" % url;
} else {
fileUrl = url;
}
if (fileUrl == d->media->currentSource().url().toString()) {
return;
}
d->media->setCurrentSource(Phonon::MediaSource(fileUrl));
}
QString VideoWidget::url() const
{
return d->media->currentSource().url().toString();
}
void VideoWidget::setUsedControls(const Controls controls)
{
if (controls == d->shownControls) {
return;
}
d->shownControls = controls;
//kDebug()<<"Setting used controls"<<controls;
QGraphicsLinearLayout *controlsLayout = 0;
if (controls != NoControls && d->controlsWidget == 0) {
d->controlsWidget = new Plasma::Frame(this);
d->controlsWidget->setFrameShadow(Plasma::Frame::Raised);
controlsLayout = new QGraphicsLinearLayout(Qt::Horizontal, d->controlsWidget);
d->hideTimer = new QTimer(this);
connect(d->hideTimer, SIGNAL(timeout()), this, SLOT(hideControlWidget()));
//controls == NoControls
} else if (d->controlsWidget != 0) {
d->controlsWidget->deleteLater();
d->hideTimer->deleteLater();
d->controlsWidget = 0;
//disconnect all the stuff that wasn't automatically disconnected 'cause widget deaths
disconnect(d->media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State)));
disconnect(d->media, SIGNAL(tick(qint64)), this, SLOT(ticked(qint64)));
disconnect(d->media, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
disconnect(d->audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
return;
}
Q_ASSERT(controlsLayout);
//empty the layout
while (controlsLayout->count() > 0) {
controlsLayout->removeAt(0);
}
if (controls&Previous) {
if (!d->previousButton) {
d->previousButton = new IconWidget(d->controlsWidget);
d->previousButton->setIcon("media-playback-start");
connect(d->playButton, SIGNAL(clicked()), this, SLOT(PreviousRequested()));
}
controlsLayout->addItem(d->previousButton);
} else {
d->previousButton->deleteLater();
d->previousButton = 0;
}
if (controls&Play) {
if (!d->playButton) {
d->playButton = new IconWidget(d->controlsWidget);
d->playButton->setIcon("media-playback-start");
connect(d->playButton, SIGNAL(clicked()), this, SLOT(play()));
}
controlsLayout->addItem(d->playButton);
} else {
d->playButton->deleteLater();
d->playButton = 0;
}
if (controls&Pause) {
if (!d->pauseButton) {
d->pauseButton = new IconWidget(d->controlsWidget);
d->pauseButton->setIcon("media-playback-pause");
connect(d->pauseButton, SIGNAL(clicked()), this, SLOT(pause()));
}
controlsLayout->addItem(d->pauseButton);
} else {
d->pauseButton->deleteLater();
d->pauseButton = 0;
}
if (controls&Stop) {
if (!d->stopButton) {
d->stopButton = new IconWidget(d->controlsWidget);
d->stopButton->setIcon("media-playback-stop");
connect(d->stopButton, SIGNAL(clicked()), this, SLOT(stop()));
}
controlsLayout->addItem(d->stopButton);
} else {
d->stopButton->deleteLater();
d->stopButton = 0;
}
if (controls&PlayPause) {
if (!d->playPauseButton) {
d->playPauseButton = new IconWidget(d->controlsWidget);
d->playPauseButton->setIcon("media-playback-start");
connect(d->playPauseButton, SIGNAL(clicked()), this, SLOT(playPause()));
}
controlsLayout->addItem(d->playPauseButton);
} else {
d->playPauseButton->deleteLater();
d->playPauseButton = 0;
}
if (controls&Next) {
if (!d->nextButton) {
d->nextButton = new IconWidget(d->nextButton);
d->nextButton->setIcon("media-playback-start");
connect(d->nextButton, SIGNAL(clicked()), this, SIGNAL(nextRequested()));
}
controlsLayout->addItem(d->nextButton);
} else {
d->nextButton->deleteLater();
d->nextButton = 0;
}
connect(d->media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State)));
if (controls&Progress) {
if (!d->progress) {
d->progress = new Slider(d->controlsWidget);
d->progress->setMinimum(0);
d->progress->setMaximum(100);
d->progress->setOrientation(Qt::Horizontal);
controlsLayout->setStretchFactor(d->progress, 4);
d->progress->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
connect(d->media, SIGNAL(tick(qint64)), this, SLOT(ticked(qint64)));
connect(d->media, SIGNAL(totalTimeChanged(qint64)), SLOT(totalTimeChanged(qint64)));
connect(d->progress, SIGNAL(valueChanged(int)), this, SLOT(setPosition(int)));
}
controlsLayout->addItem(d->progress);
} else {
d->progress->deleteLater();
d->progress = 0;
}
if (controls&Volume) {
if (!d->volume) {
d->volume = new Slider(d->controlsWidget);
d->volume->setMinimum(0);
d->volume->setMaximum(100);
d->volume->setValue(100);
d->volume->setOrientation(Qt::Horizontal);
d->volume->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
connect(d->volume, SIGNAL(valueChanged(int)), SLOT(setVolume(int)));
connect(d->audioOutput, SIGNAL(volumeChanged(qreal)), SLOT(volumeChanged(qreal)));
}
controlsLayout->addItem(d->volume);
} else {
d->volume->deleteLater();
d->volume = 0;
}
if (controls&OpenFile) {
if (!d->openFileButton) {
d->openFileButton = new IconWidget(d->controlsWidget);
d->openFileButton->setIcon(KIcon("document-open"));
connect(d->openFileButton, SIGNAL(clicked()), this, SLOT(showOpenFileDialog()));
}
controlsLayout->addItem(d->openFileButton);
} else {
d->openFileButton->deleteLater();
d->openFileButton = 0;
}
controlsLayout->activate();
d->controlsWidget->setPos(0,-d->controlsWidget->size().height());
d->controlsWidget->resize(size().width(), d->controlsWidget->size().height());
d->controlsWidget->hide();
}
VideoWidget::Controls VideoWidget::usedControls() const
{
return d->shownControls;
}
void VideoWidget::play()
{
if (d->media->state() == Phonon::PlayingState) {
return;
}
d->media->play();
}
void VideoWidget::pause()
{
if (d->media->state() == Phonon::PausedState) {
return;
}
d->media->pause();
}
void VideoWidget::stop()
{
if (d->media->state() == Phonon::StoppedState) {
return;
}
d->media->stop();
}
void VideoWidget::seek(qint64 time)
{
if (d->media->currentTime() == time) {
return;
}
d->media->seek(time);
}
qint64 VideoWidget::currentTime() const
{
return d->media->currentTime();
}
qint64 VideoWidget::totalTime() const
{
return d->media->totalTime();
}
qint64 VideoWidget::remainingTime() const
{
return d->media->remainingTime();
}
void VideoWidget::setControlsVisible(bool visible)
{
if (d->controlsWidget) {
d->forceControlsVisible = visible;
d->animateControlWidget(visible);
}
}
bool VideoWidget::controlsVisible() const
{
return d->controlsWidget != 0 && d->controlsWidget->isVisible();
}
void VideoWidget::setTickInterval(qint64 interval)
{
d->media->setTickInterval(interval);
}
qint64 VideoWidget::tickInterval() const
{
return d->media->tickInterval();
}
void VideoWidget::setStyleSheet(const QString &stylesheet)
{
d->videoWidget->setStyleSheet(stylesheet);
}
QString VideoWidget::styleSheet()
{
return d->videoWidget->styleSheet();
}
Phonon::VideoWidget *VideoWidget::nativeWidget() const
{
return d->videoWidget;
}
void VideoWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
{
QGraphicsProxyWidget::resizeEvent(event);
if (d->controlsWidget) {
QSize newControlsSize(event->newSize().width(), d->controlsWidget->size().height());
int newHeight = event->newSize().height();
qreal leftMargin, topMargin, rightMargin, bottomMargin;
d->controlsWidget->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
if (newHeight/5 >= KIconLoader::SizeEnormous) {
newControlsSize.setHeight(KIconLoader::SizeEnormous+topMargin+bottomMargin);
} else if (newHeight/5 >= KIconLoader::SizeHuge) {
newControlsSize.setHeight(KIconLoader::SizeHuge+topMargin+bottomMargin);
} else if (newHeight/5 >= KIconLoader::SizeLarge) {
newControlsSize.setHeight(KIconLoader::SizeLarge+topMargin+bottomMargin);
} else if (newHeight/5 >= KIconLoader::SizeMedium) {
newControlsSize.setHeight(KIconLoader::SizeMedium+topMargin+bottomMargin);
} else {
newControlsSize.setHeight(KIconLoader::SizeSmallMedium+topMargin+bottomMargin);
}
d->controlsWidget->resize(newControlsSize);
if (d->spaceForControlsAvailable()) {
d->animateControlWidget(false);
}
}
}
void VideoWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
if (d->controlsWidget &&
!d->forceControlsVisible &&
d->spaceForControlsAvailable()) {
d->animateControlWidget(true);
}
}
void VideoWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
if (d->controlsWidget && !d->forceControlsVisible) {
d->hideTimer->start(1000);
}
}
void VideoWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
if (d->forceControlsVisible || !d->controlsWidget) {
return;
}
d->hideTimer->start(3000);
if (!d->controlsWidget->isVisible() &&
d->spaceForControlsAvailable()) {
d->animateControlWidget(true);
}
}
} // namespace Plasma
-#include <videowidget.moc>
+
+
+#include "moc_videowidget.cpp"
diff --git a/plasma/widgets/webview.cpp b/plasma/widgets/webview.cpp
index 85777691b4..a76e82ca0a 100644
--- a/plasma/widgets/webview.cpp
+++ b/plasma/widgets/webview.cpp
@@ -1,336 +1,339 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
* Copyright 2010 Davide Bettio <davide.bettio@kdemail.net>
*
* 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 <QApplication>
#include <QStyleOptionGraphicsItem>
#include <fixx11h.h>
#include <QtWebKit/QWebFrame>
#include <QtWebKit/QWebPage>
#include <QtCore/QTimer>
#include <config-plasma.h>
#ifndef PLASMA_NO_KIO
#include <kio/accessmanager.h>
#endif
#include <kdebug.h>
#include "animator.h"
#include "plasma.h"
#include "widgets/webview.h"
#include "widgets/scrollwidget.h"
#include "private/animablegraphicswebview_p.h"
namespace Plasma
{
class WebViewPrivate
{
public:
WebViewPrivate(WebView *parent)
: q(parent)
{
}
void loadingFinished(bool success);
void dragTimeoutExpired();
WebView *q;
AnimableGraphicsWebView *webView;
ScrollWidget *scrollWidget;
bool loaded;
};
WebView::WebView(QGraphicsItem *parent)
: QGraphicsWidget(parent),
d(new WebViewPrivate(this))
{
d->loaded = false;
setAcceptTouchEvents(true);
setAcceptsHoverEvents(true);
setFlags(QGraphicsItem::ItemIsFocusable);
d->scrollWidget = new Plasma::ScrollWidget(this);
d->webView = new AnimableGraphicsWebView(d->scrollWidget);
d->scrollWidget->setWidget(d->webView);
d->scrollWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
d->scrollWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setDragToScroll(false);
QPalette palette = qApp->palette();
palette.setBrush(QPalette::Base, Qt::transparent);
d->webView->page()->setPalette(palette);
#ifndef PLASMA_NO_KIO
d->webView->page()->setNetworkAccessManager(new KIO::AccessManager(d->webView->page()));
#endif
connect(d->webView, SIGNAL(loadProgress(int)),
this, SIGNAL(loadProgress(int)));
connect(d->webView, SIGNAL(loadFinished(bool)),
this, SLOT(loadingFinished(bool)));
connect(d->webView, SIGNAL(urlChanged(const QUrl &)),
this, SIGNAL(urlChanged(const QUrl &)));
}
WebView::~WebView()
{
delete d;
}
void WebView::setUrl(const KUrl &url)
{
d->loaded = false;
d->webView->load(url);
}
KUrl WebView::url() const
{
return d->webView->url();
}
void WebView::setHtml(const QByteArray &html, const KUrl &baseUrl)
{
d->loaded = false;
d->webView->setContent(html, QString(), baseUrl);
}
void WebView::setHtml(const QString &html, const KUrl &baseUrl)
{
d->loaded = false;
d->webView->setHtml(html, baseUrl);
}
QString WebView::html() const
{
return d->webView->page()->mainFrame()->toHtml();
}
QRectF WebView::geometry() const
{
if (d->loaded) {
return QRectF(pos(), d->webView->page()->mainFrame()->geometry().size());
} else {
return QGraphicsWidget::geometry();
}
}
QSizeF WebView::contentsSize() const
{
return d->webView->page()->mainFrame()->contentsSize();
}
void WebView::setScrollPosition(const QPointF &position)
{
d->webView->setScrollPosition(position);
}
QPointF WebView::scrollPosition() const
{
return d->webView->scrollPosition();
}
QRectF WebView::viewportGeometry() const
{
return d->webView->page()->mainFrame()->geometry();
}
qreal WebView::zoomFactor() const
{
return d->webView->zoomFactor();
}
void WebView::setZoomFactor(const qreal zoom)
{
d->webView->setZoomFactor(zoom);
}
void WebView::setPage(QWebPage *page)
{
d->webView->setPage(page);
}
QWebPage *WebView::page() const
{
return d->webView->page();
}
QWebFrame *WebView::mainFrame() const
{
return d->webView->page()->mainFrame();
}
void WebView::setDragToScroll(bool drag)
{
// enable / disable scrollbars
if (drag) {
mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
} else {
mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded);
mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded);
}
d->webView->setDragToScroll(drag);
d->scrollWidget->setFiltersChildEvents(drag);
}
bool WebView::dragToScroll()
{
return d->webView->dragToScroll();
}
void WebView::back()
{
d->webView->back();
}
void WebView::forward()
{
d->webView->forward();
}
void WebView::reload()
{
d->webView->reload();
}
void WebView::stop()
{
d->webView->stop();
}
void WebView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QGraphicsWidget::paint(painter, option, widget);
}
void WebView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget::mouseMoveEvent(event);
}
void WebView::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
QGraphicsWidget::hoverMoveEvent(event);
}
void WebView::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget::mousePressEvent(event);
}
void WebView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget::mouseDoubleClickEvent(event);
}
void WebView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget::mouseReleaseEvent(event);
}
void WebView::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
QGraphicsWidget::contextMenuEvent(event);
}
void WebView::wheelEvent(QGraphicsSceneWheelEvent *event)
{
QGraphicsWidget::wheelEvent(event);
}
void WebView::keyPressEvent(QKeyEvent * event)
{
QGraphicsWidget::keyPressEvent(event);
}
void WebView::keyReleaseEvent(QKeyEvent * event)
{
QGraphicsWidget::keyReleaseEvent(event);
}
void WebView::focusInEvent(QFocusEvent * event)
{
QGraphicsWidget::focusInEvent(event);
}
void WebView::focusOutEvent(QFocusEvent * event)
{
QGraphicsWidget::focusOutEvent(event);
}
void WebView::dragEnterEvent(QGraphicsSceneDragDropEvent * event)
{
QGraphicsWidget::dragEnterEvent(event);
}
void WebView::dragLeaveEvent(QGraphicsSceneDragDropEvent * event)
{
QGraphicsWidget::dragLeaveEvent(event);
}
void WebView::dragMoveEvent(QGraphicsSceneDragDropEvent * event)
{
QGraphicsWidget::dragMoveEvent(event);
}
void WebView::dropEvent(QGraphicsSceneDragDropEvent * event)
{
QGraphicsWidget::dropEvent(event);
}
QVariant WebView::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == QGraphicsItem::ItemSceneHasChanged) {
//FIXME: QWebPage _requires_ a QWidget view to not crash in places such as
// WebCore::PopupMenu::show() due to hostWindow()->platformPageClient() == NULL
// because QWebPage::d->client is NULL
//d->webView->page()->setView(viewFor(this));
}
return QGraphicsWidget::itemChange(change, value);
}
void WebView::setGeometry(const QRectF &geometry)
{
QGraphicsWidget::setGeometry(geometry);
d->scrollWidget->setGeometry(QRectF(0, 0, geometry.width(), geometry.height()));
d->webView->setGeometry(d->scrollWidget->viewportGeometry());
}
QSizeF WebView::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
{
if (which == Qt::PreferredSize) {
return d->webView->page()->mainFrame()->contentsSize();
} else {
return QGraphicsWidget::sizeHint(which, constraint);
}
}
void WebViewPrivate::loadingFinished(bool success)
{
loaded = success;
q->updateGeometry();
emit q->loadFinished(success);
q->update();
}
} // namespace Plasma
+
+
+#include "moc_webview.cpp"

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 9:03 AM (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
24/d4/dfcf506f9ba235efb21afdbdd0c2
Default Alt Text
(981 KB)

Event Timeline