Extenders enter trunk! The implementation still has some rough edges and fixmes, but the api
is in quite nice shape and basides a couple of bugs, it basically works. So what are you still doing reading this? Port your favourite applet to extenders today! ;) svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=840978
This commit is contained in:
parent
db8bb180e8
commit
a6293d363f
@ -63,6 +63,8 @@ set(plasma_LIB_SRCS
|
||||
view.cpp
|
||||
widgets/checkbox.cpp
|
||||
widgets/combobox.cpp
|
||||
widgets/extender.cpp
|
||||
widgets/extenderitem.cpp
|
||||
widgets/flash.cpp
|
||||
widgets/groupbox.cpp
|
||||
widgets/icon.cpp
|
||||
@ -163,6 +165,8 @@ install(FILES
|
||||
install(FILES
|
||||
widgets/checkbox.h
|
||||
widgets/combobox.h
|
||||
widgets/extender.h
|
||||
widgets/extenderitem.h
|
||||
widgets/flash.h
|
||||
widgets/groupbox.h
|
||||
widgets/icon.h
|
||||
@ -203,6 +207,8 @@ includes/DataEngineManager
|
||||
includes/DataEngineScript
|
||||
includes/Delegate
|
||||
includes/Dialog
|
||||
includes/Extender
|
||||
includes/ExtenderItem
|
||||
includes/Flash
|
||||
includes/GroupBox
|
||||
includes/Icon
|
||||
|
20
applet.cpp
20
applet.cpp
@ -72,6 +72,8 @@
|
||||
#include "view.h"
|
||||
#include "widgets/label.h"
|
||||
#include "widgets/pushbutton.h"
|
||||
#include "widgets/extender.h"
|
||||
#include "widgets/extenderitem.h"
|
||||
#include "tooltipmanager.h"
|
||||
|
||||
#include "private/containment_p.h"
|
||||
@ -177,6 +179,11 @@ void Applet::save(KConfigGroup &g) const
|
||||
}
|
||||
|
||||
KConfigGroup appletConfigGroup(&group, "Configuration");
|
||||
|
||||
if (extender()) {
|
||||
extender()->saveState();
|
||||
}
|
||||
|
||||
//FIXME: we need a global save state too
|
||||
saveState(appletConfigGroup);
|
||||
|
||||
@ -186,6 +193,7 @@ void Applet::save(KConfigGroup &g) const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Applet::restore(KConfigGroup &group)
|
||||
{
|
||||
QList<qreal> m = group.readEntry("transform", QList<qreal>());
|
||||
@ -459,6 +467,17 @@ void Applet::constraintsEvent(Plasma::Constraints constraints)
|
||||
}
|
||||
}
|
||||
|
||||
void Applet::initExtenderItem(ExtenderItem *item)
|
||||
{
|
||||
Q_UNUSED(item)
|
||||
item->destroy();
|
||||
}
|
||||
|
||||
Extender *Applet::extender() const
|
||||
{
|
||||
return d->extender;
|
||||
}
|
||||
|
||||
QString Applet::name() const
|
||||
{
|
||||
if (!d->appletDescription.isValid()) {
|
||||
@ -1460,6 +1479,7 @@ bool Applet::isContainment() const
|
||||
AppletPrivate::AppletPrivate(KService::Ptr service, int uniqueID, Applet *applet)
|
||||
: appletId(uniqueID),
|
||||
q(applet),
|
||||
extender(0),
|
||||
backgroundHints(Applet::StandardBackground),
|
||||
appletDescription(service),
|
||||
package(0),
|
||||
|
30
applet.h
30
applet.h
@ -48,6 +48,8 @@ class Containment;
|
||||
class DataEngine;
|
||||
class Package;
|
||||
class AppletPrivate;
|
||||
class ExtenderItem;
|
||||
class Extender;
|
||||
|
||||
/**
|
||||
* @short The base Applet class
|
||||
@ -511,7 +513,7 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
||||
* can coordinate themselves with these changes if they desire.
|
||||
*/
|
||||
void geometryChanged();
|
||||
|
||||
|
||||
/**
|
||||
* Emitted by Applet subclasses when they change a sizeHint and wants to announce the change
|
||||
*/
|
||||
@ -583,6 +585,27 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
||||
**/
|
||||
virtual void init();
|
||||
|
||||
/**
|
||||
* Get's called when and extender item has to be initialized after a plasma restart. If you
|
||||
* create ExtenderItems in your applet, you should implement this function to again create
|
||||
* the widget that should be shown in this extender item. This function might look something
|
||||
* like this:
|
||||
*
|
||||
* @code
|
||||
* SuperCoolWidget *widget = new SuperCoolWidget();
|
||||
* dataEngine("engine")->connectSource(item->config("dataSourceName"), widget);
|
||||
* item->setWidget(widget);
|
||||
* @endcode
|
||||
*
|
||||
* You can also add one or more custom qactions to this extender item in this function.
|
||||
*/
|
||||
virtual void initExtenderItem(ExtenderItem *item);
|
||||
|
||||
/**
|
||||
* @return the extender this applet has.
|
||||
*/
|
||||
Extender *extender() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This constructor is to be used with the plugin loading systems
|
||||
@ -675,6 +698,7 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
||||
*/
|
||||
virtual void constraintsEvent(Plasma::Constraints constraints);
|
||||
|
||||
|
||||
/**
|
||||
* Register the widgets that manage mouse clicks but you still want
|
||||
* to be able to drag the applet around when holding the mouse pointer
|
||||
@ -771,6 +795,10 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
||||
friend class AppletScript;
|
||||
friend class AppletHandle;
|
||||
friend class AppletPrivate;
|
||||
|
||||
//FIXME: this shouldn't be necesarry.
|
||||
friend class Extender;
|
||||
friend class ExtenderItem;
|
||||
};
|
||||
|
||||
} // Plasma namespace
|
||||
|
42
corona.cpp
42
corona.cpp
@ -23,6 +23,7 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QGraphicsSceneDragDropEvent>
|
||||
#include <QGraphicsGridLayout>
|
||||
#include <QMimeData>
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
@ -50,7 +51,8 @@ public:
|
||||
: q(corona),
|
||||
immutability(Mutable),
|
||||
mimetype("text/x-plasmoidservicename"),
|
||||
config(0)
|
||||
config(0),
|
||||
offscreenLayout(0)
|
||||
{
|
||||
if (KGlobal::hasMainComponent()) {
|
||||
configName = KGlobal::mainComponent().componentName() + "-appletsrc";
|
||||
@ -171,6 +173,7 @@ public:
|
||||
KSharedConfigPtr config;
|
||||
QTimer configSyncTimer;
|
||||
QList<Containment*> containments;
|
||||
QGraphicsGridLayout *offscreenLayout;
|
||||
};
|
||||
|
||||
Corona::Corona(QObject *parent)
|
||||
@ -338,6 +341,43 @@ Containment* Corona::addContainmentDelayed(const QString& name, const QVariantLi
|
||||
return d->addContainment(name, args, 0, true);
|
||||
}
|
||||
|
||||
void Corona::addOffscreenWidget(QGraphicsWidget *widget)
|
||||
{
|
||||
kDebug() << "adding offscreen widget.";
|
||||
widget->setParentItem(0);
|
||||
if (!d->offscreenLayout) {
|
||||
kDebug() << "adding offscreen widget.";
|
||||
QGraphicsWidget *offscreenWidget = new QGraphicsWidget(0);
|
||||
addItem(offscreenWidget);
|
||||
d->offscreenLayout = new QGraphicsGridLayout(offscreenWidget);
|
||||
//FIXME: do this a nice way.
|
||||
offscreenWidget->setPos(-10000, -10000);
|
||||
offscreenWidget->setLayout(d->offscreenLayout);
|
||||
}
|
||||
|
||||
d->offscreenLayout->addItem(widget, d->offscreenLayout->rowCount() + 1,
|
||||
d->offscreenLayout->columnCount() + 1);
|
||||
|
||||
d->offscreenLayout->invalidate();
|
||||
|
||||
kDebug() << "current scenerect = " << widget->sceneBoundingRect();
|
||||
}
|
||||
|
||||
void Corona::removeOffscreenWidget(QGraphicsWidget *widget)
|
||||
{
|
||||
if (!d->offscreenLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < d->offscreenLayout->count(); i++) {
|
||||
QGraphicsWidget *foundWidget =
|
||||
dynamic_cast<QGraphicsWidget*>(d->offscreenLayout->itemAt(i));
|
||||
if (foundWidget == widget) {
|
||||
d->offscreenLayout->removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Corona::loadDefaultLayout()
|
||||
{
|
||||
}
|
||||
|
16
corona.h
16
corona.h
@ -27,6 +27,8 @@
|
||||
#include <plasma/plasma.h>
|
||||
#include <plasma/plasma_export.h>
|
||||
|
||||
class QGraphicsGridLayout;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
@ -93,6 +95,20 @@ public:
|
||||
*/
|
||||
Containment* containmentForScreen(int screen) const;
|
||||
|
||||
/**
|
||||
* Adds a widget in the topleft quadrant in the scene. Widgets in the topleft quadrant are
|
||||
* normally never shown unless you specifically aim a view at it, which makes it ideal for
|
||||
* toplevel views etc.
|
||||
* @param widget the widget to add.
|
||||
*/
|
||||
void addOffscreenWidget(QGraphicsWidget *widget);
|
||||
|
||||
/**
|
||||
* Removes a widget from the topleft quadrant in the scene.
|
||||
* @param widget the widget to remove.
|
||||
*/
|
||||
void removeOffscreenWidget(QGraphicsWidget *widget);
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Initializes the layout from a config file. This will first clear any existing
|
||||
|
2
includes/Extender
Normal file
2
includes/Extender
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/widgets/extender.h"
|
||||
|
2
includes/ExtenderItem
Normal file
2
includes/ExtenderItem
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../plasma/widgets/extenderitem.h"
|
||||
|
@ -75,6 +75,7 @@ public:
|
||||
// number of members at this point.
|
||||
uint appletId;
|
||||
Applet *q;
|
||||
Extender *extender;
|
||||
Applet::BackgroundHints backgroundHints;
|
||||
KPluginInfo appletDescription;
|
||||
Package* package;
|
||||
|
377
widgets/extender.cpp
Normal file
377
widgets/extender.cpp
Normal file
@ -0,0 +1,377 @@
|
||||
/***************************************************************************
|
||||
* Copyright 2008 by 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 General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, 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 "extender_p.h"
|
||||
#include "extender.h"
|
||||
|
||||
#include <QGraphicsLinearLayout>
|
||||
#include <QGraphicsGridLayout>
|
||||
#include <QAction>
|
||||
|
||||
#include "plasma/applet.h"
|
||||
#include "plasma/applet_p.h"
|
||||
#include "plasma/containment.h"
|
||||
#include "plasma/corona.h"
|
||||
#include "plasma/widgets/extenderitem.h"
|
||||
#include "plasma/widgets/label.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
Extender::Extender(Applet *applet)
|
||||
: QGraphicsWidget(applet),
|
||||
d(new ExtenderPrivate(applet, this))
|
||||
{
|
||||
applet->d->extender = this;
|
||||
d->layout = new QGraphicsLinearLayout();
|
||||
d->layout->setOrientation(Qt::Vertical);
|
||||
setLayout(d->layout);
|
||||
|
||||
d->emptyExtenderLabel = new Label(this);
|
||||
d->emptyExtenderLabel->setText(d->emptyExtenderMessage);
|
||||
d->emptyExtenderLabel->setMinimumSize(QSizeF(150, 24));
|
||||
d->emptyExtenderLabel->setPreferredSize(QSizeF(200, 48));
|
||||
d->emptyExtenderLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
d->layout->addItem(d->emptyExtenderLabel);
|
||||
|
||||
d->loadExtenderItems();
|
||||
}
|
||||
|
||||
Extender::~Extender()
|
||||
{
|
||||
//FIXME: this used to work, not anymore... fix.
|
||||
foreach (ExtenderItem *item, attachedItems()) {
|
||||
if (!item->isDetached() && item->autoExpireDelay()) {
|
||||
//destroy temporary extender items, so their configuration won't linger after a plasma
|
||||
//restart.
|
||||
item->destroy();
|
||||
}
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Extender::setEmptyExtenderMessage(const QString &message)
|
||||
{
|
||||
d->emptyExtenderMessage = message;
|
||||
|
||||
if (d->emptyExtenderLabel) {
|
||||
d->emptyExtenderLabel->setText(message);
|
||||
}
|
||||
}
|
||||
|
||||
QString Extender::emptyExtenderMessage() const
|
||||
{
|
||||
return d->emptyExtenderMessage;
|
||||
}
|
||||
|
||||
QList<ExtenderItem*> Extender::items() const
|
||||
{
|
||||
QList<ExtenderItem*> result;
|
||||
|
||||
//iterate through all extenders we can find and check each extenders source applet.
|
||||
foreach (Containment *c, d->applet->containment()->corona()->containments()) {
|
||||
foreach (Applet *applet, c->applets()) {
|
||||
if (applet->extender()) {
|
||||
foreach (ExtenderItem *item, applet->extender()->attachedItems()) {
|
||||
if (item->sourceAppletId() == d->applet->id()) {
|
||||
result.append(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<ExtenderItem*> Extender::attachedItems() const
|
||||
{
|
||||
return d->attachedExtenderItems;
|
||||
}
|
||||
|
||||
QList<ExtenderItem*> Extender::detachedItems() const
|
||||
{
|
||||
QList<ExtenderItem*> result;
|
||||
|
||||
foreach (ExtenderItem *item, items()) {
|
||||
if (item->isDetached()) {
|
||||
result.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ExtenderItem *Extender::item(const QString &name) const
|
||||
{
|
||||
foreach (ExtenderItem *item, items()) {
|
||||
if (item->config().readEntry("extenderItemName", "") == name) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Extender::saveState()
|
||||
{
|
||||
kDebug() << "saving state";
|
||||
foreach (ExtenderItem *item, attachedItems()) {
|
||||
item->config().writeEntry("extenderItemPosition", item->geometry().y());
|
||||
}
|
||||
}
|
||||
|
||||
void Extender::itemAddedEvent(ExtenderItem *item, const QPointF &pos)
|
||||
{
|
||||
kDebug() << "Adding item to layout.";
|
||||
|
||||
//this is a sane size policy imo.
|
||||
item->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
|
||||
if (pos == QPointF(-1, -1)) {
|
||||
d->layout->addItem(item);
|
||||
} else {
|
||||
d->layout->insertItem(d->insertIndexFromPos(pos), item);
|
||||
}
|
||||
|
||||
//remove the empty extender message if needed.
|
||||
if (d->emptyExtenderLabel) {
|
||||
d->layout->removeItem(d->emptyExtenderLabel);
|
||||
delete d->emptyExtenderLabel;
|
||||
d->emptyExtenderLabel = 0;
|
||||
}
|
||||
|
||||
d->adjustSizeHints();
|
||||
}
|
||||
|
||||
void Extender::itemRemovedEvent(ExtenderItem *item)
|
||||
{
|
||||
kDebug() << "Removing item from layout.";
|
||||
|
||||
d->layout->removeItem(item);
|
||||
|
||||
//add the empty extender message if needed.
|
||||
if (!attachedItems().count() && !d->emptyExtenderLabel) {
|
||||
d->emptyExtenderLabel = new Label(this);
|
||||
d->emptyExtenderLabel->setText(d->emptyExtenderMessage);
|
||||
d->layout->addItem(d->emptyExtenderLabel);
|
||||
}
|
||||
|
||||
d->adjustSizeHints();
|
||||
}
|
||||
|
||||
void Extender::itemHoverEnterEvent(ExtenderItem *item)
|
||||
{
|
||||
Q_UNUSED(item);
|
||||
}
|
||||
|
||||
void Extender::itemHoverMoveEvent(ExtenderItem *item, const QPointF &pos)
|
||||
{
|
||||
int insertIndex = d->insertIndexFromPos(pos);
|
||||
|
||||
if (insertIndex == d->currentSpacerIndex) {
|
||||
//relayouting is resource intensive, so don't do that when not necesarry
|
||||
return;
|
||||
}
|
||||
|
||||
//Make sure we remove any spacer that might allready be in the layout.
|
||||
itemHoverLeaveEvent(item);
|
||||
|
||||
d->currentSpacerIndex = insertIndex;
|
||||
|
||||
//Create a widget that functions as spacer, and add that to the layout.
|
||||
QGraphicsWidget *widget = new QGraphicsWidget(this);
|
||||
widget->setPreferredSize(QSizeF(150, item->size().height()));
|
||||
widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
d->spacerWidget = widget;
|
||||
d->layout->insertItem(insertIndex, widget);
|
||||
|
||||
//Make sure we remove any 'no detachables' label that might be there, and update the layout.
|
||||
//XXX: duplicated from itemAttachedEvent.
|
||||
if (d->emptyExtenderLabel) {
|
||||
d->layout->removeItem(d->emptyExtenderLabel);
|
||||
delete d->emptyExtenderLabel;
|
||||
d->emptyExtenderLabel = 0;
|
||||
}
|
||||
|
||||
d->adjustSizeHints();
|
||||
}
|
||||
|
||||
void Extender::itemHoverLeaveEvent(ExtenderItem *item)
|
||||
{
|
||||
Q_UNUSED(item);
|
||||
|
||||
if (d->spacerWidget) {
|
||||
//Remove any trace of the spacer widget.
|
||||
d->layout->removeItem(d->spacerWidget);
|
||||
delete d->spacerWidget;
|
||||
d->spacerWidget = 0;
|
||||
|
||||
d->currentSpacerIndex = -1;
|
||||
|
||||
//Make sure we add a 'no detachables' label when the layout is empty.
|
||||
if (!attachedItems().count() && !d->emptyExtenderLabel) {
|
||||
d->emptyExtenderLabel = new Label(this);
|
||||
d->emptyExtenderLabel->setText(d->emptyExtenderMessage);
|
||||
d->layout->addItem(d->emptyExtenderLabel);
|
||||
}
|
||||
|
||||
d->adjustSizeHints();
|
||||
}
|
||||
}
|
||||
|
||||
ExtenderPrivate::ExtenderPrivate(Applet *applet, Extender *extender) :
|
||||
q(extender),
|
||||
applet(applet),
|
||||
spacerWidget(0),
|
||||
emptyExtenderMessage(i18n("no items")),
|
||||
emptyExtenderLabel(0),
|
||||
popup(false)
|
||||
{
|
||||
}
|
||||
|
||||
ExtenderPrivate::~ExtenderPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
void ExtenderPrivate::addExtenderItem(ExtenderItem *item, const QPointF &pos)
|
||||
{
|
||||
attachedExtenderItems.append(item);
|
||||
item->action("returntosource")->setVisible(item->isDetached());
|
||||
q->itemAddedEvent(item, pos);
|
||||
q->itemHoverLeaveEvent(item);
|
||||
emit q->itemAttached(item);
|
||||
}
|
||||
|
||||
void ExtenderPrivate::removeExtenderItem(ExtenderItem *item)
|
||||
{
|
||||
attachedExtenderItems.removeOne(item);
|
||||
q->itemRemovedEvent(item);
|
||||
emit q->itemDetached(item);
|
||||
}
|
||||
|
||||
void ExtenderPrivate::adjustSizeHints()
|
||||
{
|
||||
if (!q->layout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
q->layout()->updateGeometry();
|
||||
|
||||
q->setMinimumSize(q->layout()->minimumSize());
|
||||
q->setPreferredSize(q->layout()->preferredSize());
|
||||
q->setMaximumSize(q->layout()->maximumSize());
|
||||
|
||||
q->updateGeometry();
|
||||
|
||||
emit q->geometryChanged();
|
||||
}
|
||||
|
||||
int ExtenderPrivate::insertIndexFromPos(const QPointF &pos) const
|
||||
{
|
||||
int insertIndex = -1;
|
||||
|
||||
//XXX: duplicated from panel
|
||||
if (pos != QPointF(-1, -1)) {
|
||||
for (int i = 0; i < layout->count(); ++i) {
|
||||
QRectF siblingGeometry = layout->itemAt(i)->geometry();
|
||||
qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
|
||||
if (pos.y() < middle) {
|
||||
insertIndex = i;
|
||||
break;
|
||||
} else if (pos.y() <= siblingGeometry.bottom()) {
|
||||
insertIndex = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return insertIndex;
|
||||
}
|
||||
|
||||
void ExtenderPrivate::loadExtenderItems()
|
||||
{
|
||||
KConfigGroup cg = applet->config("ExtenderItems");
|
||||
|
||||
//first create a list of extenderItems, and then sort them on their position, so the items get
|
||||
//recreated in the correct order.
|
||||
//TODO: this restoring of the correct order should now be done in itemAddedEvent instead of
|
||||
//here, to allow easy subclassing of Extender.
|
||||
QList<QPair<int, QString> > groupList;
|
||||
foreach (const QString &extenderItemId, cg.groupList()) {
|
||||
KConfigGroup dg = cg.group(extenderItemId);
|
||||
groupList.append(qMakePair(dg.readEntry("extenderItemPosition", 0), extenderItemId));
|
||||
}
|
||||
qSort(groupList);
|
||||
|
||||
//iterate over the extender items
|
||||
for (int i = 0; i < groupList.count(); i++) {
|
||||
QPair<int, QString> pair = groupList[i];
|
||||
KConfigGroup dg = cg.group(pair.second);
|
||||
|
||||
//load the relevant settings.
|
||||
QString extenderItemId = dg.name();
|
||||
QString extenderItemName = dg.readEntry("extenderItemName", "");
|
||||
QString appletName = dg.readEntry("sourceAppletPluginName", "");
|
||||
uint sourceAppletId = dg.readEntry("sourceAppletId", 0);
|
||||
|
||||
bool temporarySourceApplet = false;
|
||||
|
||||
//find the source applet.
|
||||
Corona *corona = applet->containment()->corona();
|
||||
Applet *sourceApplet = 0;
|
||||
foreach (Containment *containment, corona->containments()) {
|
||||
foreach (Applet *applet, containment->applets()) {
|
||||
if (applet->id() == sourceAppletId) {
|
||||
sourceApplet = applet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//There is no source applet. We just instantiate one just for the sake of creating
|
||||
//detachables.
|
||||
if (!sourceApplet) {
|
||||
kDebug() << "creating a temporary applet as factory";
|
||||
sourceApplet = Applet::load(appletName);
|
||||
temporarySourceApplet = true;
|
||||
//TODO: maybe add an option to applet to indicate that it shouldn't be deleted after
|
||||
//having used it as factory.
|
||||
}
|
||||
|
||||
if (!sourceApplet) {
|
||||
kDebug() << "sourceApplet is null? appletName = " << appletName;
|
||||
kDebug() << " extenderItemId = " << extenderItemId;
|
||||
} else {
|
||||
ExtenderItem *item = new ExtenderItem(q, extenderItemId.toInt());
|
||||
sourceApplet->initExtenderItem(item);
|
||||
|
||||
if (temporarySourceApplet) {
|
||||
delete sourceApplet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjustSizeHints();
|
||||
}
|
||||
|
||||
QGraphicsGridLayout *ExtenderPrivate::s_popupLayout = 0;
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "extender.moc"
|
177
widgets/extender.h
Normal file
177
widgets/extender.h
Normal file
@ -0,0 +1,177 @@
|
||||
/***************************************************************************
|
||||
* Copyright 2008 by 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 General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, 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 . *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EXTENDER_H
|
||||
#define EXTENDER_H
|
||||
|
||||
#include <QGraphicsWidget>
|
||||
|
||||
#include "plasma/plasma_export.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
class ExtenderPrivate;
|
||||
class ExtenderItem;
|
||||
class Applet;
|
||||
|
||||
/**
|
||||
* An extender is a widget where items can be added to. These so called ExtenderItems can be
|
||||
* detached by the user an dropped in other extenders or somewhere else, in which case a new
|
||||
* extenderapplet is created and the item is added there.
|
||||
* This widget allows using ExtenderItems in you applet. Extender takes care of the presentation
|
||||
* of a collection of extenderitems, and keeps track of extenderItems that originated in it.
|
||||
* This default extender displays extender items in a vertical layout, and shows spacers in this
|
||||
* layout when hovering with an extender item over it, which is probably good for most cases.
|
||||
* If you wish to have a different presentation of extender items, you can choose to subclass
|
||||
* this class. In this case you'll need to reimplement the extenderItem* events and optionally
|
||||
* the saveState function.
|
||||
*/
|
||||
class PLASMA_EXPORT Extender : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString emptyExtenderMessage READ emptyExtenderMessage
|
||||
WRITE setEmptyExtenderMessage)
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates an extender. Note that extender expects applet to have a config(), and needs a
|
||||
* scene because of that. So you should only instantiate an extender in init() or later, not
|
||||
* in an applet's constructor.
|
||||
* @param applet The applet this extender is part of. Null is not allowed here.
|
||||
*/
|
||||
explicit Extender(Applet *applet);
|
||||
|
||||
~Extender();
|
||||
|
||||
/**
|
||||
* @param emptyExtenderMessage The text to be shown whenever the applet's extender is empty.
|
||||
* Defaults to i18n'ed "no items".
|
||||
*/
|
||||
void setEmptyExtenderMessage(const QString &message);
|
||||
|
||||
/**
|
||||
* @return The text to be shown whenever the applet's layout is empty.
|
||||
*/
|
||||
QString emptyExtenderMessage() const;
|
||||
|
||||
/**
|
||||
* @returns a list of all extender items (attached AND detached) where the source applet is
|
||||
* this applet.
|
||||
*/
|
||||
QList<ExtenderItem*> items() const;
|
||||
|
||||
/**
|
||||
* @returns a list of all attached extender items.
|
||||
*/
|
||||
QList<ExtenderItem*> attachedItems() const;
|
||||
|
||||
/**
|
||||
* @returns a list of all detached extender items.
|
||||
*/
|
||||
QList<ExtenderItem*> detachedItems() const;
|
||||
|
||||
/**
|
||||
* This function can be used for easily determining if a certain item is allready displayed
|
||||
* in a extender item somewhere, so your applet doesn't duplicate this item. Say the applet
|
||||
* displays 'jobs', from an engine which add's a source for every job. In sourceAdded you
|
||||
* could do something like:
|
||||
* if (!extenderItem(source)) {
|
||||
* //add an extender item monitoring this source.
|
||||
* }
|
||||
*/
|
||||
ExtenderItem *item(const QString &name) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Get's called after an item has been added to this extender. The bookkeeping has allready
|
||||
* been done when this function get's called. The only thing left to do is put it somewhere
|
||||
* appropriate. The default implementation adds the extenderItem to the appropriate place in
|
||||
* a QGraphicsLinearLayout.
|
||||
* @param item The item that has just been added.
|
||||
* @param pos The location the item has been dropped in local coordinates.
|
||||
*/
|
||||
virtual void itemAddedEvent(ExtenderItem *item, const QPointF &pos);
|
||||
|
||||
/**
|
||||
* Get's called after an item has been removed from this extender. All bookkeeping has
|
||||
* allready been done when this function get's called.
|
||||
* @param item The item that has just been removed.
|
||||
*/
|
||||
virtual void itemRemovedEvent(ExtenderItem *item);
|
||||
|
||||
/**
|
||||
* Get's called when an ExtenderItem that get's dragged enters this extender. Default
|
||||
* implementation does nothing.
|
||||
*/
|
||||
virtual void itemHoverEnterEvent(ExtenderItem *item);
|
||||
|
||||
/**
|
||||
* Gets called when an ExtenderItem is hovering over this extender. Implement this function
|
||||
* to give some visual feedback about what will happen when the mouse button is released at
|
||||
* that position. The default implementation shows a spacer at the appropriate location in
|
||||
* the layout.
|
||||
* @param item The item that's hovering over this extender. Most usefull for obtaining the
|
||||
* size of the spacer.
|
||||
* @param pos The location the item is hovering.
|
||||
*/
|
||||
virtual void itemHoverMoveEvent(ExtenderItem *item, const QPointF &pos);
|
||||
|
||||
/**
|
||||
* Get's called when an ExtenderItem that was previously hovering over this extender moves
|
||||
* away from this extender. The default implementation removes any spacer from the layout.
|
||||
*/
|
||||
virtual void itemHoverLeaveEvent(ExtenderItem *item);
|
||||
|
||||
/**
|
||||
* This function get's called for every extender when plasma exits. Implement this function
|
||||
* to store the current state of this extender (position in a layout for example), so this
|
||||
* can be restored when applet starts again. The default implementation stores the y
|
||||
* coordinate of every extender item in the config field extenderItemPos.
|
||||
*/
|
||||
virtual void saveState();
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Fires when an extender item is added to this extender.
|
||||
*/
|
||||
void itemAttached(Plasma::ExtenderItem *);
|
||||
|
||||
/**
|
||||
* Fires when an extender item is removed from this extender.
|
||||
*/
|
||||
void itemDetached(Plasma::ExtenderItem *);
|
||||
|
||||
/**
|
||||
* Fires when an extender's preferred size changes.
|
||||
*/
|
||||
void geometryChanged();
|
||||
|
||||
private:
|
||||
ExtenderPrivate* const d;
|
||||
|
||||
friend class ExtenderPrivate;
|
||||
friend class ExtenderItem;
|
||||
friend class ExtenderItemPrivate;
|
||||
//applet should be able to call saveState();
|
||||
friend class Applet;
|
||||
|
||||
};
|
||||
} // Plasma namespace
|
||||
|
||||
#endif //EXTENDER_H
|
73
widgets/extender_p.h
Normal file
73
widgets/extender_p.h
Normal file
@ -0,0 +1,73 @@
|
||||
/***************************************************************************
|
||||
* Copyright 2008 by 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 General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, 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 . *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef LIBS_PLASMA_EXTENDER_P_H
|
||||
#define LIBS_PLASMA_EXTENDER_P_H
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QPointF>
|
||||
|
||||
class QGraphicsGridLayout;
|
||||
class QGraphicsLinearLayout;
|
||||
class QGraphicsWidget;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class Applet;
|
||||
class Extender;
|
||||
class ExtenderItem;
|
||||
class Label;
|
||||
|
||||
class ExtenderPrivate
|
||||
{
|
||||
public:
|
||||
ExtenderPrivate(Applet *applet, Extender *q);
|
||||
~ExtenderPrivate();
|
||||
|
||||
void addExtenderItem(ExtenderItem *item, const QPointF &pos = QPointF(-1, -1));
|
||||
void removeExtenderItem(ExtenderItem *item);
|
||||
void adjustSizeHints();
|
||||
int insertIndexFromPos(const QPointF &pos) const;
|
||||
void loadExtenderItems();
|
||||
|
||||
Extender *q;
|
||||
|
||||
Applet *applet;
|
||||
QGraphicsLinearLayout *layout;
|
||||
|
||||
int currentSpacerIndex;
|
||||
QGraphicsWidget *spacerWidget;
|
||||
|
||||
QString emptyExtenderMessage;
|
||||
Label *emptyExtenderLabel;
|
||||
|
||||
uint sourceAppletId;
|
||||
|
||||
QList<ExtenderItem*> attachedExtenderItems;
|
||||
|
||||
bool popup;
|
||||
|
||||
static QGraphicsGridLayout *s_popupLayout;
|
||||
};
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#endif // LIBS_PLASMA_EXTENDER_P_H
|
827
widgets/extenderitem.cpp
Normal file
827
widgets/extenderitem.cpp
Normal file
@ -0,0 +1,827 @@
|
||||
/***************************************************************************
|
||||
* Copyright 2008 by 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 General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, 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 "extenderitem.h"
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QGraphicsSceneResizeEvent>
|
||||
#include <QtGui/QGraphicsSceneMouseEvent>
|
||||
#include <QtGui/QGraphicsLinearLayout>
|
||||
#include <QApplication>
|
||||
#include <QAction>
|
||||
#include <QTimer>
|
||||
|
||||
#include <KDE/KDebug>
|
||||
#include <KDE/KIcon>
|
||||
#include <KDE/KWindowSystem>
|
||||
|
||||
#include "plasma/corona.h"
|
||||
#include "plasma/containment.h"
|
||||
#include "plasma/theme.h"
|
||||
#include "plasma/view.h"
|
||||
#include "plasma/applet.h"
|
||||
#include "plasma/applet_p.h"
|
||||
#include "plasma/panelsvg.h"
|
||||
#include "plasma/widgets/extender.h"
|
||||
#include "plasma/widgets/extender_p.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class ExtenderItemPrivate
|
||||
{
|
||||
public:
|
||||
ExtenderItemPrivate(ExtenderItem *extenderItem, Extender *hostExtender)
|
||||
: q(extenderItem),
|
||||
widget(0),
|
||||
toplevel(0),
|
||||
previousTargetExtender(0),
|
||||
extender(hostExtender),
|
||||
title(QString()),
|
||||
sourceAppletId(hostExtender->d->applet->id()),
|
||||
mousePressed(false),
|
||||
expirationTimer(0)
|
||||
{
|
||||
}
|
||||
|
||||
~ExtenderItemPrivate()
|
||||
{
|
||||
delete toplevel;
|
||||
delete appletBackground;
|
||||
delete dragger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Rect containing the area of the detachable where the draghandle can be drawn.
|
||||
*/
|
||||
QRectF dragHandleRect()
|
||||
{
|
||||
qreal left, top, right, bottom;
|
||||
dragger->getMargins(left, top, right, bottom);
|
||||
QRectF rect(0, 0, q->size().width(), top + bottom +
|
||||
dragger->elementSize("hint-preferred-icon-size").height());
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
QRectF titleRect()
|
||||
{
|
||||
qreal left, top, right, bottom;
|
||||
dragger->getMargins(left, top, right, bottom);
|
||||
return dragHandleRect().adjusted(left + collapseIcon->size().width(), top,
|
||||
-toolbox->size().width(), -bottom);
|
||||
}
|
||||
|
||||
//XXX kinda duplicated from applethandle.
|
||||
//returns true if the applet overlaps with a different view then the current one.
|
||||
bool leaveCurrentView(const QRect &rect)
|
||||
{
|
||||
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
|
||||
if (widget->geometry().intersects(rect)) {
|
||||
//is this widget a plasma view, a different view then our current one,
|
||||
//AND not a dashboardview?
|
||||
Plasma::View *v = qobject_cast<View*>(widget);
|
||||
Plasma::View *currentV = 0;
|
||||
|
||||
if (hostApplet()) {
|
||||
currentV = qobject_cast<View*>(hostApplet()->containment()->view());
|
||||
}
|
||||
if (v && v != currentV
|
||||
&& v->containment() != hostApplet()->containment()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QRect screenRect() {
|
||||
return hostApplet()->containment()->view()
|
||||
->mapFromScene(q->sceneBoundingRect()).boundingRect();
|
||||
}
|
||||
|
||||
void toggleCollapse() {
|
||||
q->setCollapsed(!q->isCollapsed());
|
||||
}
|
||||
|
||||
void updateToolBox() {
|
||||
if (toolbox && dragger && toolboxLayout) {
|
||||
kDebug() << "updating toolbox";
|
||||
//clean the layout.
|
||||
uint iconHeight = dragger->elementSize("hint-preferred-icon-size").height();
|
||||
|
||||
while (toolboxLayout->count()) {
|
||||
QGraphicsLayoutItem *icon = toolboxLayout->itemAt(0);
|
||||
QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget*>(icon);
|
||||
widget->deleteLater();
|
||||
toolboxLayout->removeAt(0);
|
||||
}
|
||||
|
||||
//add the actions that are actually set to visible.
|
||||
foreach (QAction *action, actions) {
|
||||
if (action->isVisible()) {
|
||||
Icon *icon = new Icon(q);
|
||||
icon->setAction(action);
|
||||
QSizeF iconSize = icon->sizeFromIconSize(iconHeight);
|
||||
icon->setMinimumSize(iconSize);
|
||||
icon->setMaximumSize(iconSize);
|
||||
toolboxLayout->addItem(icon);
|
||||
}
|
||||
}
|
||||
|
||||
toolboxLayout->updateGeometry();
|
||||
|
||||
qreal left, top, right, bottom;
|
||||
dragger->getMargins(left, top, right, bottom);
|
||||
|
||||
//position the toolbox correctly.
|
||||
QSizeF minimum = toolboxLayout->minimumSize();
|
||||
toolbox->setPos(q->size().width() - minimum.width(),
|
||||
((dragger->size().height() + top + bottom)/2) -
|
||||
(minimum.height()/2));
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: something like this as static function in corona might be a good idea.
|
||||
QPointF scenePosFromScreenPos(const QPoint &pos) const
|
||||
{
|
||||
//get the stacking order of the toplevel windows and remove the toplevel view that's
|
||||
//only here while dragging, since we're not interested in finding that.
|
||||
QList<WId> order = KWindowSystem::stackingOrder();
|
||||
if (toplevel) {
|
||||
order.removeOne(toplevel->winId());
|
||||
}
|
||||
|
||||
QGraphicsView *found = 0;
|
||||
foreach (QWidget *w, QApplication::topLevelWidgets()) {
|
||||
QGraphicsView *v = qobject_cast<QGraphicsView *>(w);
|
||||
if (v && v->isVisible() && v->geometry().contains(pos)) {
|
||||
if (found) {
|
||||
if (order.indexOf(found->winId()) < order.indexOf(v->winId())) {
|
||||
found = v;
|
||||
}
|
||||
} else {
|
||||
found = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Q_ASSERT(found);
|
||||
|
||||
return found->mapToScene(found->mapFromGlobal(pos));
|
||||
}
|
||||
|
||||
Applet *hostApplet() const
|
||||
{
|
||||
if (extender) {
|
||||
return extender->d->applet;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ExtenderItem *q;
|
||||
|
||||
QGraphicsWidget *widget;
|
||||
QGraphicsWidget *toolbox;
|
||||
QGraphicsLinearLayout *toolboxLayout;
|
||||
QGraphicsView *toplevel;
|
||||
|
||||
Extender *previousTargetExtender;
|
||||
Extender *extender;
|
||||
Applet *sourceApplet;
|
||||
|
||||
KConfigGroup config;
|
||||
|
||||
PanelSvg *dragger;
|
||||
PanelSvg *appletBackground;
|
||||
|
||||
Icon *collapseIcon;
|
||||
QAction *returnAction;
|
||||
QMap<QString, QAction*> actions;
|
||||
|
||||
QString title;
|
||||
QString name;
|
||||
|
||||
uint sourceAppletId;
|
||||
uint extenderItemId;
|
||||
|
||||
QPointF deltaScene;
|
||||
QPoint mousePos;
|
||||
|
||||
bool mousePressed;
|
||||
bool mouseOver;
|
||||
|
||||
QTimer *expirationTimer;
|
||||
|
||||
static uint s_maxExtenderItemId;
|
||||
};
|
||||
|
||||
uint ExtenderItemPrivate::s_maxExtenderItemId = 0;
|
||||
|
||||
ExtenderItem::ExtenderItem(Extender *hostExtender, uint extenderItemId)
|
||||
: QGraphicsWidget(hostExtender),
|
||||
d(new ExtenderItemPrivate(this, hostExtender))
|
||||
{
|
||||
Q_ASSERT(hostExtender);
|
||||
|
||||
//set the extenderId
|
||||
if (extenderItemId) {
|
||||
d->extenderItemId = extenderItemId;
|
||||
ExtenderItemPrivate::s_maxExtenderItemId =
|
||||
qMax(ExtenderItemPrivate::s_maxExtenderItemId, extenderItemId);
|
||||
} else {
|
||||
d->extenderItemId = ++ExtenderItemPrivate::s_maxExtenderItemId;
|
||||
}
|
||||
|
||||
d->sourceApplet = hostExtender->d->applet;
|
||||
|
||||
//create items's configgroup
|
||||
if (hostExtender->d->applet) {
|
||||
KConfigGroup cg = hostExtender->d->applet->config("ExtenderItems");
|
||||
KConfigGroup dg = KConfigGroup(&cg, QString::number(d->extenderItemId));
|
||||
|
||||
if (!dg.readEntry("sourceAppletId", 0)) {
|
||||
//The item is new
|
||||
dg.writeEntry("sourceAppletPluginName", hostExtender->d->applet->pluginName());
|
||||
dg.writeEntry("sourceAppletId", hostExtender->d->applet->id());
|
||||
d->sourceAppletId = hostExtender->d->applet->id();
|
||||
d->sourceApplet = hostExtender->d->applet;
|
||||
} else {
|
||||
//The item allready exists.
|
||||
d->name = dg.readEntry("extenderItemName", "");
|
||||
d->sourceAppletId = dg.readEntry("sourceAppletId", 0);
|
||||
//Set the sourceapplet.
|
||||
Corona *corona = hostExtender->d->applet->containment()->corona();
|
||||
foreach (Containment *containment, corona->containments()) {
|
||||
foreach (Applet *applet, containment->applets()) {
|
||||
if (applet->id() == d->sourceAppletId &&
|
||||
applet->pluginName() == dg.readEntry("sourceAppletPluginName", "")) {
|
||||
d->sourceApplet = applet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//create the dragger and standard applet background.
|
||||
d->dragger = new PanelSvg();
|
||||
d->dragger->setImagePath("widgets/dragger");
|
||||
|
||||
d->appletBackground = new PanelSvg();
|
||||
d->appletBackground->setImagePath("widgets/background");
|
||||
d->appletBackground->setEnabledBorders(0);
|
||||
|
||||
//create the toolbox.
|
||||
d->toolbox = new QGraphicsWidget(this);
|
||||
d->toolboxLayout = new QGraphicsLinearLayout();
|
||||
d->toolbox->setLayout(d->toolboxLayout);
|
||||
|
||||
//allow the theme to set the size of the icon.
|
||||
//TODO: discuss with others to determine details of the theming implementation. I don't really
|
||||
//like this approach, but it works...
|
||||
QSizeF iconSize = d->dragger->elementSize("hint-preferred-icon-size");
|
||||
|
||||
qreal left, top, right, bottom;
|
||||
d->dragger->getMargins(left, top, right, bottom);
|
||||
|
||||
//create the collapse/applet icon.
|
||||
d->collapseIcon = new Icon(KIcon(hostExtender->d->applet->icon()), "", this);
|
||||
d->collapseIcon->resize(d->collapseIcon->sizeFromIconSize(iconSize.height()));
|
||||
d->collapseIcon->setPos(left, (d->dragger->size().height() + top + bottom)/2 -
|
||||
d->collapseIcon->size().height()/2);
|
||||
connect(d->collapseIcon, SIGNAL(clicked()), this, SLOT(toggleCollapse()));
|
||||
|
||||
//Add the return to source action.
|
||||
d->returnAction = new QAction(this);
|
||||
d->returnAction->setIcon(KIcon("returntosource"));
|
||||
d->returnAction->setEnabled(true);
|
||||
d->returnAction->setVisible(true);
|
||||
connect(d->returnAction, SIGNAL(triggered()), this, SLOT(moveBackToSource()));
|
||||
addAction("returntosource", d->returnAction);
|
||||
|
||||
//set the extender we want to move to.
|
||||
setExtender(hostExtender);
|
||||
|
||||
setCollapsed(false); //sets the size hints.
|
||||
setAcceptHoverEvents(true);
|
||||
|
||||
d->updateToolBox();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
ExtenderItem::~ExtenderItem()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
KConfigGroup ExtenderItem::config() const
|
||||
{
|
||||
KConfigGroup cg = extender()->d->applet->config("ExtenderItems");
|
||||
return KConfigGroup(&cg, QString::number(d->extenderItemId));
|
||||
}
|
||||
|
||||
void ExtenderItem::setTitle(const QString &title)
|
||||
{
|
||||
d->title = title;
|
||||
update();
|
||||
}
|
||||
|
||||
QString ExtenderItem::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
void ExtenderItem::setName(const QString &name)
|
||||
{
|
||||
d->name = name;
|
||||
config().writeEntry("extenderItemName", name);
|
||||
}
|
||||
|
||||
QString ExtenderItem::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
void ExtenderItem::setWidget(QGraphicsWidget *widget)
|
||||
{
|
||||
widget->setParentItem(this);
|
||||
widget->setPos(QPointF(0, d->dragHandleRect().height()));
|
||||
d->widget = widget;
|
||||
setCollapsed(isCollapsed()); //updates the size hints.
|
||||
}
|
||||
|
||||
QGraphicsWidget *ExtenderItem::widget() const
|
||||
{
|
||||
return d->widget;
|
||||
}
|
||||
|
||||
void ExtenderItem::setIcon(const QIcon &icon)
|
||||
{
|
||||
d->collapseIcon->setIcon(icon);
|
||||
}
|
||||
|
||||
void ExtenderItem::setIcon(const QString &icon)
|
||||
{
|
||||
d->collapseIcon->setIcon(icon);
|
||||
}
|
||||
|
||||
QIcon ExtenderItem::icon() const
|
||||
{
|
||||
return d->collapseIcon->icon();
|
||||
}
|
||||
|
||||
void ExtenderItem::setExtender(Extender *extender, const QPointF &pos)
|
||||
{
|
||||
kDebug() << "setExtender";
|
||||
//We are switching extender...
|
||||
|
||||
//first remove this item from the old extender.
|
||||
if (d->extender) {
|
||||
d->extender->d->removeExtenderItem(this);
|
||||
}
|
||||
|
||||
//move the configuration.
|
||||
if (d->hostApplet() && (extender != d->extender)) {
|
||||
kDebug() << "moving configuration";
|
||||
KConfigGroup c = extender->d->applet->config("ExtenderItems");
|
||||
kDebug() << "hostAppletId is " << d->hostApplet()->id();
|
||||
kDebug() << "config name is " << config().name();
|
||||
config().reparent(&c);
|
||||
}
|
||||
|
||||
d->extender = extender;
|
||||
|
||||
//change parent.
|
||||
setParentItem(extender);
|
||||
extender->d->addExtenderItem(this, pos);
|
||||
|
||||
//cancel the timer.
|
||||
if (d->expirationTimer && isDetached()) {
|
||||
d->expirationTimer->stop();
|
||||
delete d->expirationTimer;
|
||||
d->expirationTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Extender *ExtenderItem::extender() const
|
||||
{
|
||||
return d->extender;
|
||||
}
|
||||
|
||||
bool ExtenderItem::isCollapsed() const
|
||||
{
|
||||
if (!d->widget) {
|
||||
return true;
|
||||
} else {
|
||||
return !d->widget->isVisible();
|
||||
}
|
||||
}
|
||||
|
||||
void ExtenderItem::setAutoExpireDelay(uint time)
|
||||
{
|
||||
if (!isDetached()) {
|
||||
d->expirationTimer = new QTimer(this);
|
||||
d->expirationTimer->setSingleShot(true);
|
||||
d->expirationTimer->setInterval(time);
|
||||
connect(d->expirationTimer, SIGNAL(timeout()), this, SLOT(destroy()));
|
||||
d->expirationTimer->start();
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtenderItem::autoExpireDelay() const
|
||||
{
|
||||
if (d->expirationTimer) {
|
||||
return d->expirationTimer->interval();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtenderItem::isDetached() const
|
||||
{
|
||||
if (d->hostApplet()) {
|
||||
return (sourceAppletId() != d->hostApplet()->id());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ExtenderItem::addAction(const QString &name, QAction *action)
|
||||
{
|
||||
|
||||
Q_ASSERT(action);
|
||||
|
||||
d->actions[name] = action;
|
||||
connect(action, SIGNAL(changed()), this, SLOT(updateToolBox()));
|
||||
d->updateToolBox();
|
||||
}
|
||||
|
||||
QAction *ExtenderItem::action(const QString &name) const
|
||||
{
|
||||
if (d->actions.contains(name)) {
|
||||
return d->actions[name];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint ExtenderItem::sourceAppletId() const
|
||||
{
|
||||
return d->sourceAppletId;
|
||||
}
|
||||
|
||||
void ExtenderItem::destroy()
|
||||
{
|
||||
kDebug() << "deleting config group.";
|
||||
d->hostApplet()->config("ExtenderItem").deleteGroup(QString::number(d->extenderItemId));
|
||||
if (d->extender) {
|
||||
d->extender->d->removeExtenderItem(this);
|
||||
}
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void ExtenderItem::setCollapsed(bool collapsed)
|
||||
{
|
||||
if (!d->widget) {
|
||||
setPreferredSize(QSizeF(200, d->dragHandleRect().height()));
|
||||
setMinimumSize(QSizeF(0, d->dragHandleRect().height()));
|
||||
//FIXME: wasn't there some sort of QWIDGETMAXSIZE thingy?
|
||||
setMaximumSize(QSizeF(1000, d->dragHandleRect().height()));
|
||||
updateGeometry();
|
||||
return;
|
||||
}
|
||||
|
||||
qreal left, top, right, bottom;
|
||||
d->dragger->getMargins(left, top, right, bottom);
|
||||
|
||||
d->widget->setVisible(!collapsed);
|
||||
|
||||
if (collapsed) {
|
||||
setPreferredSize(QSizeF(d->widget->preferredWidth(), d->dragHandleRect().height()));
|
||||
setMinimumSize(QSizeF(d->widget->minimumWidth(), d->dragHandleRect().height()));
|
||||
setMaximumSize(QSizeF(d->widget->maximumWidth(), d->dragHandleRect().height()));
|
||||
//FIXME: why don't tooltips work?
|
||||
//d->collapseIcon->setToolTip(i18n("Expand this widget"));
|
||||
} else {
|
||||
setPreferredSize(QSizeF(d->widget->preferredWidth(),
|
||||
d->widget->preferredHeight() + d->dragHandleRect().height()));
|
||||
setMinimumSize( QSizeF(d->widget->minimumWidth(),
|
||||
d->widget->minimumHeight() + d->dragHandleRect().height()));
|
||||
setMaximumSize( QSizeF(d->widget->maximumWidth(),
|
||||
d->widget->maximumHeight() + d->dragHandleRect().height()));
|
||||
//d->collapseIcon->setToolTip(i18n("Collapse this widget"));
|
||||
}
|
||||
|
||||
if (d->extender) {
|
||||
d->extender->d->adjustSizeHints();
|
||||
}
|
||||
}
|
||||
|
||||
void ExtenderItem::moveBackToSource()
|
||||
{
|
||||
if (!d->sourceApplet) {
|
||||
return;
|
||||
}
|
||||
setExtender(d->sourceApplet->d->extender);
|
||||
}
|
||||
|
||||
void ExtenderItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget)
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(widget);
|
||||
|
||||
painter->setRenderHint(QPainter::TextAntialiasing, true);
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
if (d->mousePressed) {
|
||||
//only paint the standard applet background when dragging the thing around.
|
||||
d->appletBackground->paintPanel(painter); //, QRectF(QPointF(0,0), size()));
|
||||
}
|
||||
d->dragger->paintPanel(painter); //, d->dragHandleRect());
|
||||
|
||||
//draw the title.
|
||||
Plasma::Theme *theme = Plasma::Theme::defaultTheme();
|
||||
QFont font = theme->font(Plasma::Theme::DefaultFont);
|
||||
font.setPointSize(font.pointSize() - 2);
|
||||
|
||||
//XXX: duplicated from windowtaskitem.
|
||||
//TODO: hmm, create something generic for this... there's probably more stuff that wants to have
|
||||
//this functionality
|
||||
QRectF rect = QRectF(d->titleRect().width() - 30, 0, 30, d->titleRect().height());
|
||||
|
||||
QPixmap pixmap(d->titleRect().size().toSize());
|
||||
pixmap.fill(Qt::transparent);
|
||||
|
||||
QPainter p(&pixmap);
|
||||
p.setPen(theme->color(Plasma::Theme::TextColor));
|
||||
p.setFont(font);
|
||||
p.drawText(QRectF(QPointF(0, 0), d->titleRect().size()),
|
||||
Qt::TextSingleLine | Qt::AlignVCenter | Qt::AlignLeft,
|
||||
d->title);
|
||||
|
||||
// Create the alpha gradient for the fade out effect
|
||||
QLinearGradient alphaGradient(0, 0, 1, 0);
|
||||
alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
|
||||
//TODO: correct handling of right to left text.
|
||||
alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
|
||||
alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||
p.fillRect(rect, alphaGradient);
|
||||
|
||||
p.end();
|
||||
|
||||
painter->drawPixmap(d->titleRect().topLeft(), pixmap);
|
||||
}
|
||||
|
||||
void ExtenderItem::resizeEvent(QGraphicsSceneResizeEvent *event)
|
||||
{
|
||||
qreal left, top, right, bottom;
|
||||
d->dragger->getMargins(left, top, right, bottom);
|
||||
|
||||
//resize the dragger
|
||||
QSizeF newDraggerSize = event->newSize();
|
||||
newDraggerSize.setHeight(d->dragger->elementSize("hint-preferred-icon-size").height() + top + bottom);
|
||||
d->dragger->resizePanel(newDraggerSize);
|
||||
|
||||
//resize the applet background
|
||||
d->appletBackground->resizePanel(event->newSize());
|
||||
|
||||
//resize the widget
|
||||
if (d->widget) {
|
||||
QSizeF newWidgetSize = event->newSize();
|
||||
newWidgetSize.setHeight(newWidgetSize.height() - d->dragger->size().height() - top - bottom);
|
||||
d->widget->resize(newWidgetSize);
|
||||
}
|
||||
|
||||
d->updateToolBox();
|
||||
}
|
||||
|
||||
void ExtenderItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (!(d->dragHandleRect().contains(event->pos()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->mousePressed = true;
|
||||
d->deltaScene = pos();
|
||||
|
||||
Applet *parentApplet = d->hostApplet();
|
||||
|
||||
QGraphicsView *v = parentApplet->view();
|
||||
QPoint localpos = v->mapFromScene(scenePos());
|
||||
d->mousePos = event->screenPos() - v->mapToGlobal(localpos);
|
||||
QPointF mousePos = v->mapToScene(v->mapFromGlobal(event->screenPos()));
|
||||
|
||||
parentApplet->raise();
|
||||
setZValue(parentApplet->zValue());
|
||||
|
||||
d->extender->d->removeExtenderItem(this);
|
||||
|
||||
if (d->extender) {
|
||||
d->extender->itemHoverEnterEvent(this);
|
||||
d->extender->itemHoverMoveEvent(this, d->extender->mapFromScene(mousePos));
|
||||
}
|
||||
|
||||
QApplication::setOverrideCursor(Qt::ClosedHandCursor);
|
||||
}
|
||||
|
||||
void ExtenderItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
if (!d->mousePressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
//keep track of the movement in scene coordinates. we use this to set the position of the
|
||||
//applet when remaining in the current view.
|
||||
d->deltaScene += event->scenePos() - event->lastScenePos();
|
||||
|
||||
//set a rect in screencoordinates so we can check when we need to move to a toplevel
|
||||
//view.
|
||||
QRect screenRect = QRect();
|
||||
screenRect.setTopLeft(event->screenPos() - d->mousePos);
|
||||
screenRect.setSize(d->screenRect().size());
|
||||
|
||||
if (d->leaveCurrentView(screenRect)) {
|
||||
//we're moving the applet to a toplevel view, so place it somewhere out of sight
|
||||
//first: in the topleft quadrant.
|
||||
|
||||
if (!d->toplevel) {
|
||||
//XXX duplication from applethandle
|
||||
//create a toplevel view and aim it at the applet.
|
||||
Corona *corona = d->hostApplet()->containment()->corona();
|
||||
d->toplevel = new QGraphicsView(corona, 0);
|
||||
//TODO: use addOffscreenWidget
|
||||
setParentItem(0);
|
||||
setPos(-12000, -12000);
|
||||
|
||||
d->toplevel->setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint
|
||||
| Qt::WindowStaysOnTopHint);
|
||||
d->toplevel->resize(screenRect.size());
|
||||
d->toplevel->setSceneRect(sceneBoundingRect());
|
||||
d->toplevel->centerOn(this);
|
||||
|
||||
//We might have to scale the view, because we might be zoomed out.
|
||||
qreal scale = screenRect.width() / boundingRect().width();
|
||||
d->toplevel->scale(scale, scale);
|
||||
|
||||
d->toplevel->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
d->toplevel->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
d->toplevel->update();
|
||||
d->toplevel->show();
|
||||
}
|
||||
|
||||
//move the toplevel view.
|
||||
d->toplevel->setGeometry(screenRect);
|
||||
} else {
|
||||
setParentItem(d->hostApplet());
|
||||
setPos(d->deltaScene);
|
||||
|
||||
//remove the toplevel view.
|
||||
if (d->toplevel) {
|
||||
delete d->toplevel;
|
||||
d->toplevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//let's insert spacers in applets we're hovering over for some usefull visual feedback.
|
||||
//check which view we're hovering over and use that information to get the mouse
|
||||
//position in scene coordinates (event->scenePos won't work, since it doesn't take in
|
||||
//consideration that you're leaving the current view).
|
||||
QPointF mousePos = d->scenePosFromScreenPos(event->screenPos());
|
||||
|
||||
//find the extender we're hovering over.
|
||||
Extender *targetExtender = 0;
|
||||
Corona *corona = qobject_cast<Corona*>(scene());
|
||||
foreach (Containment *containment, corona->containments()) {
|
||||
foreach (Applet *applet, containment->applets()) {
|
||||
if (applet->extender() && (applet->sceneBoundingRect().contains(mousePos)
|
||||
|| applet->extender()->sceneBoundingRect().contains(mousePos))) {
|
||||
targetExtender = applet->extender();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove any previous spacers.
|
||||
if (targetExtender != d->previousTargetExtender) {
|
||||
if (d->previousTargetExtender) {
|
||||
d->previousTargetExtender->itemHoverLeaveEvent(this);
|
||||
}
|
||||
d->previousTargetExtender = targetExtender;
|
||||
if (targetExtender) {
|
||||
targetExtender->itemHoverEnterEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
//insert a spacer if the applet accepts detachables.
|
||||
if (targetExtender) {
|
||||
if (targetExtender->sceneBoundingRect().contains(mousePos)) {
|
||||
targetExtender->itemHoverMoveEvent(this, targetExtender->mapFromScene(mousePos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtenderItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
if (d->titleRect().contains(event->pos())) {
|
||||
if (!d->mouseOver) {
|
||||
QApplication::setOverrideCursor(Qt::OpenHandCursor);
|
||||
d->mouseOver = true;
|
||||
}
|
||||
} else {
|
||||
if (d->mouseOver) {
|
||||
QApplication::restoreOverrideCursor();
|
||||
d->mouseOver = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtenderItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
if (d->mouseOver) {
|
||||
QApplication::restoreOverrideCursor();
|
||||
d->mouseOver = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ExtenderItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (d->mousePressed) {
|
||||
d->mousePressed = false;
|
||||
|
||||
//remove the toplevel view
|
||||
if (d->toplevel) {
|
||||
delete d->toplevel;
|
||||
d->toplevel = 0;
|
||||
}
|
||||
|
||||
//let's insert spacers in applets we're hovering over for some usefull visual feedback.
|
||||
//check which view we're hovering over and use that information to get the mouse
|
||||
//position in scene coordinates (event->scenePos won't work, since it doesn't take in
|
||||
//consideration that you're leaving the current view).
|
||||
QPointF mousePos = d->scenePosFromScreenPos(event->screenPos());
|
||||
|
||||
//find the extender we're hovering over.
|
||||
Extender *targetExtender = 0;
|
||||
Corona *corona = qobject_cast<Corona*>(scene());
|
||||
foreach (Containment *containment, corona->containments()) {
|
||||
foreach (Applet *applet, containment->applets()) {
|
||||
if (applet->extender() && (applet->sceneBoundingRect().contains(mousePos)
|
||||
|| applet->extender()->sceneBoundingRect().contains(mousePos))) {
|
||||
targetExtender = applet->extender();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//are we hovering over an applet that accepts extender items?
|
||||
if (targetExtender) {
|
||||
if (targetExtender->sceneBoundingRect().contains(mousePos)) {
|
||||
setExtender(targetExtender, targetExtender->mapFromScene(mousePos));
|
||||
} else {
|
||||
setExtender(targetExtender);
|
||||
}
|
||||
} else {
|
||||
//apparently, it is not, so instantiate a new ExtenderApplet.
|
||||
//TODO: maybe we alow the user to choose a default extenderapplet.
|
||||
kDebug() << "Instantiate a new ExtenderApplet";
|
||||
mousePos = d->scenePosFromScreenPos(event->screenPos() - d->mousePos);
|
||||
foreach (Containment *containment, corona->containments()) {
|
||||
if (containment->sceneBoundingRect().contains(mousePos)) {
|
||||
Applet *applet = containment->addApplet("extenderapplet",
|
||||
QVariantList(),
|
||||
QRectF(mousePos, size()));
|
||||
setExtender(applet->extender());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Plasma
|
||||
|
||||
#include "extenderitem.moc"
|
213
widgets/extenderitem.h
Normal file
213
widgets/extenderitem.h
Normal file
@ -0,0 +1,213 @@
|
||||
/***************************************************************************
|
||||
* Copyright 2008 by 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 General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, 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 . *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EXTENDERITEM_H
|
||||
#define EXTENDERITEM_H
|
||||
|
||||
#include <QtGui/QGraphicsWidget>
|
||||
|
||||
#include <KDE/KConfigGroup>
|
||||
#include <KDE/KIcon>
|
||||
|
||||
#include "plasma/plasma_export.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class Applet;
|
||||
class Extender;
|
||||
class ExtenderItemPrivate;
|
||||
|
||||
/**
|
||||
* This class wraps around a QGraphicsWidget and provides drag&drop handling, a draghandle,
|
||||
* title and ability to display qactions as a row of icon, ability to expand, collapse, return
|
||||
* to source and tracks configuration associated with this item for you.
|
||||
*/
|
||||
class PLASMA_EXPORT ExtenderItem : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QGraphicsWidget * widget READ widget WRITE setWidget)
|
||||
Q_PROPERTY(QString title READ title WRITE setTitle)
|
||||
Q_PROPERTY(QString name READ name WRITE setName)
|
||||
Q_PROPERTY(QIcon icon READ icon WRITE setIcon)
|
||||
Q_PROPERTY(Extender * extender READ extender WRITE setExtender)
|
||||
Q_PROPERTY(bool collapsed READ isCollapsed WRITE setCollapsed)
|
||||
Q_PROPERTY(bool detached READ isDetached)
|
||||
Q_PROPERTY(uint autoExpireDelay WRITE setAutoExpireDelay)
|
||||
|
||||
public:
|
||||
/**
|
||||
* The constructor takes care of adding this item to an extender.
|
||||
* @param hostExtender The extender where the extender item belongs to.
|
||||
* TODO: extenderItemId might not be necesarry in the constructor if I rewrite some
|
||||
* stuff.
|
||||
* @param extenderItemId the id of the extender item. Use the default 0 to assign a new,
|
||||
* unique id to this extender item.
|
||||
*/
|
||||
ExtenderItem(Extender *hostExtender, uint extenderItemId = 0);
|
||||
|
||||
~ExtenderItem();
|
||||
|
||||
/**
|
||||
* fetch the configuration of this widget.
|
||||
* @return the configuration of this widget.
|
||||
*/
|
||||
KConfigGroup config() const;
|
||||
|
||||
/**
|
||||
* @param widget The widget that should be wrapped into the extender item.
|
||||
*/
|
||||
void setWidget(QGraphicsWidget *widget);
|
||||
|
||||
/**
|
||||
* @return The widget that is wrapped into the extender item.
|
||||
*/
|
||||
QGraphicsWidget *widget() const;
|
||||
|
||||
/**
|
||||
* @param title the title that will be shown in the extender item's dragger. Default is
|
||||
* no title.
|
||||
*/
|
||||
void setTitle(const QString &title);
|
||||
|
||||
/**
|
||||
* @return the title shown in the extender item's dragger.
|
||||
*/
|
||||
QString title() const;
|
||||
|
||||
/**
|
||||
* You can assign names to extender items to look them up through the item() function.
|
||||
* Make sure you only use unique names.
|
||||
* @param name the name of the item. Defaults to an empty string.
|
||||
*/
|
||||
void setName(const QString &name);
|
||||
|
||||
/**
|
||||
* @return the name of the item.
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* @param icon the icon name to display in the extender item's drag handle. Defaults to
|
||||
* the source applet's icon.
|
||||
*/
|
||||
void setIcon(const QString &icon);
|
||||
|
||||
/**
|
||||
* @param icon the icon to display in the extender item's drag handle. Defaults to the
|
||||
* source applet's icon.
|
||||
*/
|
||||
void setIcon(const QIcon &icon);
|
||||
|
||||
/**
|
||||
* @return the icon being displayed in the extender item's drag handle.
|
||||
*/
|
||||
QIcon icon() const;
|
||||
|
||||
/**
|
||||
* @param extender the extender this item belongs to.
|
||||
* @param pos the position in the extender this item should be added. Defaults to 'just
|
||||
* append'.
|
||||
*/
|
||||
void setExtender(Extender *extender, const QPointF &pos = QPointF(-1, -1));
|
||||
|
||||
/**
|
||||
* @return the extender this items belongs to.
|
||||
*/
|
||||
Extender *extender() const;
|
||||
|
||||
/**
|
||||
* @param time (in ms) before this extender item destroys itself unless it is detached,
|
||||
* in which case this extender stays around. 0 means forever and is the default.
|
||||
*/
|
||||
void setAutoExpireDelay(uint time = 0);
|
||||
|
||||
/**
|
||||
* @return whether or not this extender item has an auto expire delay.
|
||||
*/
|
||||
bool autoExpireDelay() const;
|
||||
|
||||
/**
|
||||
* @return whether or not this item is detached from it's original source.
|
||||
*/
|
||||
bool isDetached() const;
|
||||
|
||||
/**
|
||||
* @return whether or not the extender item is collapsed.
|
||||
*/
|
||||
bool isCollapsed() const;
|
||||
|
||||
/**
|
||||
* @param name the name to store the action under in our collection.
|
||||
* @param action the action to add. Actions will be displayed as an icon in the drag
|
||||
* handle.
|
||||
*/
|
||||
void addAction(const QString &name, QAction *action);
|
||||
|
||||
/**
|
||||
* @return the QAction with the given name from our collection. By default the action
|
||||
* collection contains a "movebacktosource" action which will be only shown when the
|
||||
* item is detached.
|
||||
*/
|
||||
QAction *action(const QString &name) const;
|
||||
|
||||
/**
|
||||
* @return the id of the applet this item is created by.
|
||||
*/
|
||||
uint sourceAppletId() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Destroys the extender item. As opposed to calling delete on this class, destroy also
|
||||
* removes the config group associated with this item.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Collapse or expand the extender item. Defaults to false.
|
||||
*/
|
||||
void setCollapsed(bool collapsed);
|
||||
|
||||
/**
|
||||
* Returns the extender item to it's source applet.
|
||||
*/
|
||||
void moveBackToSource();
|
||||
|
||||
protected:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
||||
|
||||
void resizeEvent(QGraphicsSceneResizeEvent *event);
|
||||
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
|
||||
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
|
||||
private:
|
||||
Q_PRIVATE_SLOT(d, void toggleCollapse())
|
||||
Q_PRIVATE_SLOT(d, void updateToolBox())
|
||||
|
||||
ExtenderItemPrivate * const d;
|
||||
|
||||
friend class Extender;
|
||||
};
|
||||
} // namespace Plasma
|
||||
#endif // EXTENDERITEM_H
|
5
widgets/extenderitem_p.h
Normal file
5
widgets/extenderitem_p.h
Normal file
@ -0,0 +1,5 @@
|
||||
#ifndef WIDGETS_EXTENDERITEM_P_H
|
||||
#define WIDGETS_EXTENDERITEM_P_H
|
||||
|
||||
|
||||
#endif // WIDGETS_EXTENDERITEM_P_H
|
@ -231,9 +231,11 @@ void Meter::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Dat
|
||||
{
|
||||
Q_UNUSED(sourceName)
|
||||
|
||||
foreach (const QVariant &d, data) {
|
||||
if (d.canConvert(QVariant::Int)) {
|
||||
setValue(d.toInt());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user