2008-11-04 00:08:39 +01:00
|
|
|
/*
|
2009-03-12 18:19:45 +01:00
|
|
|
* Copyright 2008, 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
|
2008-11-04 00:08:39 +01:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "extender.h"
|
|
|
|
|
|
|
|
#include <QAction>
|
2009-04-30 02:34:49 +02:00
|
|
|
#include <QLabel>
|
2009-02-09 19:10:45 +01:00
|
|
|
#include <QGraphicsSceneDragDropEvent>
|
2008-11-04 00:08:39 +01:00
|
|
|
#include <QGraphicsGridLayout>
|
|
|
|
#include <QGraphicsLinearLayout>
|
2008-12-01 19:30:42 +01:00
|
|
|
#include <QPainter>
|
2008-11-04 00:08:39 +01:00
|
|
|
|
|
|
|
#include "applet.h"
|
|
|
|
#include "containment.h"
|
|
|
|
#include "corona.h"
|
2009-03-23 17:30:32 +01:00
|
|
|
#include "extendergroup.h"
|
2008-11-04 00:08:39 +01:00
|
|
|
#include "extenderitem.h"
|
|
|
|
#include "framesvg.h"
|
2008-12-01 19:30:42 +01:00
|
|
|
#include "paintutils.h"
|
2008-11-04 00:08:39 +01:00
|
|
|
#include "popupapplet.h"
|
|
|
|
#include "svg.h"
|
2008-12-01 19:30:42 +01:00
|
|
|
#include "theme.h"
|
2008-11-04 00:08:39 +01:00
|
|
|
#include "widgets/label.h"
|
|
|
|
|
|
|
|
#include "private/applet_p.h"
|
2009-02-09 19:10:45 +01:00
|
|
|
#include "private/applethandle_p.h"
|
2008-11-04 00:08:39 +01:00
|
|
|
#include "private/extender_p.h"
|
2009-02-09 19:10:45 +01:00
|
|
|
#include "private/extenderapplet_p.h"
|
2008-11-04 00:08:39 +01:00
|
|
|
#include "private/extenderitem_p.h"
|
2009-02-09 19:10:45 +01:00
|
|
|
#include "private/extenderitemmimedata_p.h"
|
2008-11-04 00:08:39 +01:00
|
|
|
|
|
|
|
namespace Plasma
|
|
|
|
{
|
|
|
|
|
2008-12-01 19:30:42 +01:00
|
|
|
//TODO: copied from panel containment. We'll probably want a spacer widget in libplasma for 4.3.
|
|
|
|
class Spacer : public QGraphicsWidget
|
|
|
|
{
|
|
|
|
public:
|
2009-04-30 02:34:49 +02:00
|
|
|
Spacer(Extender *parent)
|
2008-12-01 19:30:42 +01:00
|
|
|
: QGraphicsWidget(parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~Spacer()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-04-30 02:34:49 +02:00
|
|
|
void setMargins(qreal left, qreal top, qreal right, qreal bottom)
|
|
|
|
{
|
|
|
|
m_left = left;
|
|
|
|
m_top = top;
|
|
|
|
m_right = right;
|
|
|
|
m_bottom = bottom;
|
|
|
|
}
|
|
|
|
|
2008-12-01 19:30:42 +01:00
|
|
|
protected:
|
|
|
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * widget = 0)
|
|
|
|
{
|
|
|
|
Q_UNUSED(option)
|
|
|
|
Q_UNUSED(widget)
|
|
|
|
|
|
|
|
painter->setRenderHint(QPainter::Antialiasing);
|
2009-04-30 02:34:49 +02:00
|
|
|
QPainterPath p = Plasma::PaintUtils::roundedRectangle(
|
|
|
|
contentsRect().adjusted(m_left, m_top, -m_right, -m_bottom), 4);
|
2008-12-01 19:30:42 +01:00
|
|
|
|
|
|
|
QColor c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
|
|
|
|
c.setAlphaF(0.3);
|
|
|
|
painter->fillPath(p, c);
|
|
|
|
}
|
2009-04-30 02:34:49 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
qreal m_left;
|
|
|
|
qreal m_top;
|
|
|
|
qreal m_right;
|
|
|
|
qreal m_bottom;
|
2008-12-01 19:30:42 +01:00
|
|
|
};
|
|
|
|
|
2008-11-04 00:08:39 +01:00
|
|
|
Extender::Extender(Applet *applet)
|
|
|
|
: QGraphicsWidget(applet),
|
|
|
|
d(new ExtenderPrivate(applet, this))
|
|
|
|
{
|
|
|
|
//At multiple places in the extender code, we make the assumption that an applet doesn't have
|
|
|
|
//more then one extender. If a second extender is created, destroy the first one to avoid leaks.
|
|
|
|
if (applet->d->extender) {
|
|
|
|
kWarning() << "Applet already has an extender, and can have only one extender."
|
|
|
|
<< "The previous extender will be destroyed.";
|
|
|
|
delete applet->d->extender;
|
|
|
|
}
|
|
|
|
applet->d->extender = this;
|
|
|
|
|
|
|
|
setContentsMargins(0, 0, 0, 0);
|
|
|
|
d->layout = new QGraphicsLinearLayout(this);
|
|
|
|
d->layout->setOrientation(Qt::Vertical);
|
|
|
|
d->layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
d->layout->setSpacing(0);
|
|
|
|
setLayout(d->layout);
|
|
|
|
|
|
|
|
d->loadExtenderItems();
|
2009-02-09 19:10:45 +01:00
|
|
|
|
|
|
|
setAcceptDrops(true);
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Extender::~Extender()
|
|
|
|
{
|
|
|
|
d->applet->d->extender = 0;
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Extender::setEmptyExtenderMessage(const QString &message)
|
|
|
|
{
|
|
|
|
d->emptyExtenderMessage = message;
|
|
|
|
|
|
|
|
if (d->emptyExtenderLabel) {
|
|
|
|
d->emptyExtenderLabel->setText(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Extender::emptyExtenderMessage() const
|
|
|
|
{
|
|
|
|
return d->emptyExtenderMessage;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<ExtenderItem*> Extender::items() const
|
|
|
|
{
|
|
|
|
QList<ExtenderItem*> result;
|
|
|
|
|
|
|
|
//FIXME: a triple nested loop ... ew. there should be a more efficient way to do this
|
|
|
|
//iterate through all extenders we can find and check each extenders source applet.
|
2009-06-11 02:28:24 +02:00
|
|
|
Containment *containment = d->applet->containment();
|
|
|
|
if (!containment) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (Containment *c, containment->corona()->containments()) {
|
2008-11-04 00:08:39 +01:00
|
|
|
foreach (Applet *applet, c->applets()) {
|
|
|
|
if (applet->d->extender) {
|
|
|
|
foreach (ExtenderItem *item, applet->d->extender->attachedItems()) {
|
|
|
|
if (item->d->sourceApplet == d->applet) {
|
|
|
|
result.append(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<ExtenderItem*> Extender::attachedItems() const
|
|
|
|
{
|
|
|
|
return d->attachedExtenderItems;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<ExtenderItem*> Extender::detachedItems() const
|
|
|
|
{
|
|
|
|
QList<ExtenderItem*> result;
|
|
|
|
|
2009-06-11 01:27:35 +02:00
|
|
|
//FIXME: a triple nested loop ... ew. there should be a more efficient way to do this
|
|
|
|
//iterate through all extenders we can find and check each extenders source applet.
|
2009-06-11 02:28:24 +02:00
|
|
|
Containment *containment = d->applet->containment();
|
|
|
|
if (!containment) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (Containment *c, containment->corona()->containments()) {
|
2009-06-11 01:27:35 +02:00
|
|
|
foreach (Applet *applet, c->applets()) {
|
|
|
|
if (applet->d->extender) {
|
|
|
|
foreach (ExtenderItem *item, applet->d->extender->attachedItems()) {
|
|
|
|
if (item->d->sourceApplet == d->applet && item->isDetached()) {
|
|
|
|
result.append(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExtenderItem *Extender::item(const QString &name) const
|
|
|
|
{
|
2009-06-11 01:27:35 +02:00
|
|
|
// chances are the item is in our own extender, so check there first
|
|
|
|
foreach (ExtenderItem *item, d->attachedExtenderItems) {
|
|
|
|
if (item->d->sourceApplet == d->applet && item->name() == name) {
|
2008-11-04 00:08:39 +01:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-11 01:27:35 +02:00
|
|
|
// maybe it's been moved elsewhere, so lets search through the entire tree of elements
|
|
|
|
//FIXME: a triple nested loop ... ew. there should be a more efficient way to do this
|
|
|
|
//iterate through all extenders we can find and check each extenders source applet.
|
2009-06-11 02:28:24 +02:00
|
|
|
Containment *containment = d->applet->containment();
|
|
|
|
if (!containment) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (Containment *c, containment->corona()->containments()) {
|
2009-06-11 01:27:35 +02:00
|
|
|
foreach (Applet *applet, c->applets()) {
|
|
|
|
if (applet->d->extender) {
|
|
|
|
if (applet->d->extender == this) {
|
|
|
|
// skip it, we checked it already
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (ExtenderItem *item, applet->d->extender->attachedItems()) {
|
|
|
|
if (item->d->sourceApplet == d->applet && item->name() == name) {
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-04 00:08:39 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-26 19:03:15 +02:00
|
|
|
ExtenderGroup *Extender::group(const QString &name) const
|
|
|
|
{
|
|
|
|
return qobject_cast<ExtenderGroup*>(item(name));
|
|
|
|
}
|
|
|
|
|
2009-03-12 18:19:45 +01:00
|
|
|
bool Extender::hasItem(const QString &name) const
|
|
|
|
{
|
|
|
|
if (item(name)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//if item(name) returns false, that doesn't mean that the item doesn't exist, just that it has
|
2009-04-26 19:03:15 +02:00
|
|
|
//not been instantiated yet. check to see if there's mention of this item existing in the
|
|
|
|
//plasma config's section DetachedExtenderItems
|
2009-06-11 02:28:24 +02:00
|
|
|
Corona *corona = qobject_cast<Corona *>(scene());
|
|
|
|
if (!corona) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-03-12 18:19:45 +01:00
|
|
|
KConfigGroup extenderItemGroup(corona->config(), "DetachedExtenderItems");
|
|
|
|
foreach (const QString &extenderItemId, extenderItemGroup.groupList()) {
|
|
|
|
KConfigGroup cg = extenderItemGroup.group(extenderItemId);
|
2009-04-09 07:55:36 +02:00
|
|
|
if (uint(cg.readEntry("sourceAppletId", 0)) == d->applet->id() &&
|
2009-03-12 18:19:45 +01:00
|
|
|
cg.readEntry("extenderItemName", "") == name &&
|
|
|
|
cg.readEntry("sourceAppletPluginName", "") == d->applet->pluginName()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-11-04 00:08:39 +01:00
|
|
|
void Extender::setAppearance(Appearance appearance)
|
|
|
|
{
|
|
|
|
if (d->appearance == appearance) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->appearance = appearance;
|
|
|
|
d->updateBorders();
|
|
|
|
}
|
|
|
|
|
|
|
|
Extender::Appearance Extender::appearance() const
|
|
|
|
{
|
|
|
|
return d->appearance;
|
|
|
|
}
|
|
|
|
|
2009-03-23 17:30:32 +01:00
|
|
|
QList<ExtenderGroup*> Extender::groups() const
|
|
|
|
{
|
|
|
|
QList<ExtenderGroup*> result;
|
2009-05-06 16:21:05 +02:00
|
|
|
foreach (ExtenderItem *item, d->attachedExtenderItems) {
|
2009-03-23 17:30:32 +01:00
|
|
|
if (item->isGroup() && !result.contains(item->group())) {
|
|
|
|
result.append(item->group());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-11-04 00:08:39 +01:00
|
|
|
void Extender::saveState()
|
|
|
|
{
|
|
|
|
foreach (ExtenderItem *item, attachedItems()) {
|
|
|
|
item->config().writeEntry("extenderItemPosition", item->geometry().y());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant Extender::itemChange(GraphicsItemChange change, const QVariant &value)
|
|
|
|
{
|
|
|
|
if (change == QGraphicsItem::ItemPositionHasChanged) {
|
2008-11-30 17:16:25 +01:00
|
|
|
emit geometryChanged();
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return QGraphicsWidget::itemChange(change, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Extender::resizeEvent(QGraphicsSceneResizeEvent *event)
|
|
|
|
{
|
|
|
|
QGraphicsWidget::resizeEvent(event);
|
|
|
|
emit geometryChanged();
|
|
|
|
}
|
|
|
|
|
2008-12-01 19:30:42 +01:00
|
|
|
void Extender::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|
|
|
{
|
2008-12-08 19:05:17 +01:00
|
|
|
Q_UNUSED(event)
|
2008-12-01 19:30:42 +01:00
|
|
|
PopupApplet *popupApplet = qobject_cast<PopupApplet*>(d->applet);
|
2009-05-06 16:21:05 +02:00
|
|
|
if (isEmpty() && popupApplet) {
|
2008-12-01 19:30:42 +01:00
|
|
|
popupApplet->hidePopup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-09 19:10:45 +01:00
|
|
|
void Extender::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
|
|
|
|
{
|
|
|
|
if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
|
|
|
|
event->accept();
|
|
|
|
|
|
|
|
const ExtenderItemMimeData *mimeData =
|
|
|
|
qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
|
|
|
|
|
|
|
|
if (mimeData) {
|
|
|
|
itemHoverEnterEvent(mimeData->extenderItem());
|
2009-02-09 23:10:35 +01:00
|
|
|
|
|
|
|
PopupApplet *popupApplet = qobject_cast<PopupApplet*>(d->applet);
|
|
|
|
if (popupApplet) {
|
|
|
|
popupApplet->showPopup();
|
|
|
|
}
|
2009-02-09 19:10:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Extender::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
|
|
|
|
{
|
|
|
|
if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
|
|
|
|
const ExtenderItemMimeData *mimeData =
|
|
|
|
qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
|
|
|
|
|
|
|
|
if (mimeData) {
|
|
|
|
itemHoverMoveEvent(mimeData->extenderItem(), event->pos());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Extender::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
|
2008-11-04 00:08:39 +01:00
|
|
|
{
|
2009-02-09 19:10:45 +01:00
|
|
|
if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
|
|
|
|
const ExtenderItemMimeData *mimeData =
|
|
|
|
qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
|
|
|
|
|
|
|
|
if (mimeData) {
|
|
|
|
itemHoverLeaveEvent(mimeData->extenderItem());
|
|
|
|
|
2009-02-09 23:10:35 +01:00
|
|
|
//Some logic to conveniently show/hide popups or applets when logical.
|
|
|
|
Extender *sourceExtender = mimeData->extenderItem()->d->extender;
|
|
|
|
|
|
|
|
//Hide popups when they're not the extender where we started, and we're leaving the
|
|
|
|
//extender. Use a small timeout here, to avoid accidental hides of extenders we're
|
|
|
|
//targetting.
|
2009-02-09 19:10:45 +01:00
|
|
|
PopupApplet *popupApplet = qobject_cast<PopupApplet*>(d->applet);
|
2009-02-09 23:10:35 +01:00
|
|
|
if (popupApplet && sourceExtender != this) {
|
|
|
|
kDebug() << "leaving another extender then the extender we started, so hide the popup.";
|
|
|
|
popupApplet->showPopup(250);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Hide popups when we drag the last item away.
|
2009-04-30 02:34:49 +02:00
|
|
|
if (popupApplet && sourceExtender == this && (attachedItems().count() < 2)) {
|
2009-02-09 19:10:45 +01:00
|
|
|
kDebug() << "leaving the extender, and there are no more attached items so hide the popup.";
|
|
|
|
popupApplet->hidePopup();
|
|
|
|
}
|
|
|
|
|
|
|
|
//Hide empty internal extender containers when we drag the last item away. Avoids having
|
|
|
|
//an ugly empty applet on the desktop temporarily.
|
|
|
|
ExtenderApplet *extenderApplet = qobject_cast<ExtenderApplet*>(d->applet);
|
2009-03-11 15:41:37 +01:00
|
|
|
if (extenderApplet && sourceExtender == this && attachedItems().count() < 2 &&
|
|
|
|
extenderApplet->formFactor() != Plasma::Horizontal &&
|
|
|
|
extenderApplet->formFactor() != Plasma::Vertical) {
|
2009-02-09 19:10:45 +01:00
|
|
|
kDebug() << "leaving the internal extender container, so hide the applet and it's handle.";
|
|
|
|
extenderApplet->hide();
|
2009-03-11 15:41:37 +01:00
|
|
|
AppletHandle *handle = dynamic_cast<AppletHandle*>(extenderApplet->parentItem());
|
2009-02-09 19:10:45 +01:00
|
|
|
if (handle) {
|
|
|
|
handle->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Extender::dropEvent(QGraphicsSceneDragDropEvent *event)
|
|
|
|
{
|
|
|
|
if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
|
|
|
|
const ExtenderItemMimeData *mimeData =
|
|
|
|
qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
|
|
|
|
|
|
|
|
if (mimeData) {
|
|
|
|
mimeData->extenderItem()->setExtender(this, event->pos());
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-04 00:08:39 +01:00
|
|
|
|
2009-02-09 19:10:45 +01:00
|
|
|
void Extender::itemAddedEvent(ExtenderItem *item, const QPointF &pos)
|
|
|
|
{
|
2008-11-04 00:08:39 +01:00
|
|
|
if (pos == QPointF(-1, -1)) {
|
2009-04-26 19:03:15 +02:00
|
|
|
//if just plain adding an item, add it at a sane position:
|
2009-04-08 18:16:00 +02:00
|
|
|
if (!item->group()) {
|
|
|
|
if (appearance() == BottomUpStacked) {
|
2009-04-26 19:03:15 +02:00
|
|
|
//at the top
|
2009-04-08 18:16:00 +02:00
|
|
|
d->layout->insertItem(0, item);
|
|
|
|
} else {
|
2009-04-26 19:03:15 +02:00
|
|
|
//at the bottom
|
2009-04-08 18:16:00 +02:00
|
|
|
d->layout->addItem(item);
|
|
|
|
}
|
2009-03-12 19:45:45 +01:00
|
|
|
} else {
|
2009-04-26 19:03:15 +02:00
|
|
|
//at the top in the group it belongs to
|
2009-04-08 18:16:00 +02:00
|
|
|
d->layout->insertItem(d->insertIndexFromPos(item->group()->pos()) + 1, item);
|
2009-03-12 19:45:45 +01:00
|
|
|
}
|
2008-11-04 00:08:39 +01:00
|
|
|
} else {
|
|
|
|
d->layout->insertItem(d->insertIndexFromPos(pos), item);
|
|
|
|
}
|
|
|
|
|
|
|
|
//remove the empty extender message if needed.
|
2008-11-20 17:37:30 +01:00
|
|
|
d->updateEmptyExtenderLabel();
|
2009-04-08 18:16:00 +02:00
|
|
|
d->updateBorders();
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Extender::itemRemovedEvent(ExtenderItem *item)
|
|
|
|
{
|
|
|
|
d->layout->removeItem(item);
|
|
|
|
|
2008-11-20 17:37:30 +01:00
|
|
|
if (d->spacerWidget) {
|
|
|
|
d->layout->removeItem(d->spacerWidget);
|
|
|
|
delete d->spacerWidget;
|
|
|
|
d->spacerWidget = 0;
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
|
2008-11-20 17:37:30 +01:00
|
|
|
//add the empty extender message if needed.
|
|
|
|
d->updateEmptyExtenderLabel();
|
2009-04-08 18:16:00 +02:00
|
|
|
d->updateBorders();
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Extender::itemHoverEnterEvent(ExtenderItem *item)
|
|
|
|
{
|
|
|
|
itemHoverMoveEvent(item, QPointF(0, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Extender::itemHoverMoveEvent(ExtenderItem *item, const QPointF &pos)
|
|
|
|
{
|
2008-11-28 18:06:00 +01:00
|
|
|
if (d->spacerWidget && d->spacerWidget->geometry().contains(pos)) {
|
2008-11-04 00:08:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Make sure we remove any spacer that might already be in the layout.
|
2008-11-28 18:06:00 +01:00
|
|
|
if (d->spacerWidget) {
|
|
|
|
d->layout->removeItem(d->spacerWidget);
|
|
|
|
}
|
2008-11-04 00:08:39 +01:00
|
|
|
|
2008-11-28 18:06:00 +01:00
|
|
|
int insertIndex = d->insertIndexFromPos(pos);
|
2008-11-04 00:08:39 +01:00
|
|
|
|
|
|
|
//Create a widget that functions as spacer, and add that to the layout.
|
2008-11-28 18:06:00 +01:00
|
|
|
if (!d->spacerWidget) {
|
2008-12-01 19:30:42 +01:00
|
|
|
Spacer *widget = new Spacer(this);
|
2009-04-30 02:34:49 +02:00
|
|
|
qreal left, top, right, bottom;
|
|
|
|
d->background->getMargins(left, top, right, bottom);
|
|
|
|
widget->setMargins(left, 4, right, 4);
|
|
|
|
|
2008-11-28 18:06:00 +01:00
|
|
|
widget->setMinimumSize(item->minimumSize());
|
|
|
|
widget->setPreferredSize(item->preferredSize());
|
|
|
|
widget->setMaximumSize(item->maximumSize());
|
|
|
|
widget->setSizePolicy(item->sizePolicy());
|
|
|
|
d->spacerWidget = widget;
|
|
|
|
}
|
|
|
|
d->layout->insertItem(insertIndex, d->spacerWidget);
|
2008-11-04 00:08:39 +01:00
|
|
|
|
|
|
|
//Make sure we remove any 'no detachables' label that might be there, and update the layout.
|
2008-11-20 17:37:30 +01:00
|
|
|
d->updateEmptyExtenderLabel();
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-11-20 17:37:30 +01:00
|
|
|
d->updateEmptyExtenderLabel();
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FrameSvg::EnabledBorders Extender::enabledBordersForItem(ExtenderItem *item) const
|
|
|
|
{
|
2008-12-08 18:32:57 +01:00
|
|
|
if (d->layout->count() < 1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-04 00:08:39 +01:00
|
|
|
ExtenderItem *topItem = dynamic_cast<ExtenderItem*>(d->layout->itemAt(0));
|
|
|
|
ExtenderItem *bottomItem = dynamic_cast<ExtenderItem*>(d->layout->itemAt(d->layout->count() - 1));
|
2009-04-08 18:16:00 +02:00
|
|
|
if (item->group()) {
|
|
|
|
return FrameSvg::LeftBorder | FrameSvg::RightBorder;
|
|
|
|
} else if (d->appearance == TopDownStacked && bottomItem != item) {
|
2008-11-04 00:08:39 +01:00
|
|
|
return FrameSvg::LeftBorder | FrameSvg::BottomBorder | FrameSvg::RightBorder;
|
|
|
|
} else if (d->appearance == BottomUpStacked && topItem != item) {
|
|
|
|
return FrameSvg::LeftBorder | FrameSvg::TopBorder | FrameSvg::RightBorder;
|
|
|
|
} else if (d->appearance != NoBorders) {
|
|
|
|
return FrameSvg::LeftBorder | FrameSvg::RightBorder;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ExtenderPrivate::ExtenderPrivate(Applet *applet, Extender *extender) :
|
|
|
|
q(extender),
|
|
|
|
applet(applet),
|
2009-04-30 02:34:49 +02:00
|
|
|
background(new FrameSvg(extender)),
|
2008-11-04 00:08:39 +01:00
|
|
|
currentSpacerIndex(-1),
|
|
|
|
spacerWidget(0),
|
2008-11-20 17:37:30 +01:00
|
|
|
emptyExtenderMessage(QString()),
|
2008-11-04 00:08:39 +01:00
|
|
|
emptyExtenderLabel(0),
|
|
|
|
appearance(Extender::NoBorders)
|
|
|
|
{
|
2009-04-30 02:34:49 +02:00
|
|
|
background->setImagePath("widgets/extender-background");
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ExtenderPrivate::~ExtenderPrivate()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExtenderPrivate::addExtenderItem(ExtenderItem *item, const QPointF &pos)
|
|
|
|
{
|
|
|
|
attachedExtenderItems.append(item);
|
|
|
|
q->itemHoverLeaveEvent(item);
|
|
|
|
q->itemAddedEvent(item, pos);
|
|
|
|
emit q->itemAttached(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExtenderPrivate::removeExtenderItem(ExtenderItem *item)
|
|
|
|
{
|
|
|
|
attachedExtenderItems.removeOne(item);
|
|
|
|
|
|
|
|
//collapse the popupapplet if the last item is removed.
|
|
|
|
if (!q->attachedItems().count()) {
|
|
|
|
PopupApplet *popupApplet = qobject_cast<PopupApplet*>(applet);
|
|
|
|
if (popupApplet) {
|
|
|
|
popupApplet->hidePopup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
q->itemRemovedEvent(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
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];
|
2009-01-16 19:49:54 +01:00
|
|
|
|
2008-11-04 00:08:39 +01:00
|
|
|
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;
|
|
|
|
|
2008-11-28 18:06:00 +01:00
|
|
|
kDebug() << "applet id = " << applet->id();
|
|
|
|
kDebug() << "sourceappletid = " << sourceAppletId;
|
|
|
|
|
2009-01-16 19:49:54 +01:00
|
|
|
//find the source applet.
|
|
|
|
Applet *sourceApplet = 0;
|
2009-06-11 02:28:24 +02:00
|
|
|
if (applet->id() == sourceAppletId) {
|
|
|
|
// it's ours!
|
|
|
|
sourceApplet = applet;
|
|
|
|
} else {
|
|
|
|
Containment *containment = applet->containment();
|
|
|
|
|
|
|
|
if (containment) {
|
|
|
|
Corona *corona = containment->corona();
|
|
|
|
|
|
|
|
foreach (Containment *containment, corona->containments()) {
|
|
|
|
foreach (Applet *applet, containment->applets()) {
|
|
|
|
if (applet->id() == sourceAppletId) {
|
|
|
|
sourceApplet = applet;
|
|
|
|
}
|
|
|
|
}
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
}
|
2009-01-16 19:49:54 +01:00
|
|
|
}
|
2008-11-04 00:08:39 +01:00
|
|
|
|
2009-01-16 19:49:54 +01:00
|
|
|
//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.
|
|
|
|
}
|
2008-11-04 00:08:39 +01:00
|
|
|
|
2009-01-16 19:49:54 +01:00
|
|
|
if (!sourceApplet) {
|
|
|
|
kDebug() << "sourceApplet is null? appletName = " << appletName;
|
|
|
|
kDebug() << " extenderItemId = " << extenderItemId;
|
|
|
|
} else {
|
2009-03-23 17:30:32 +01:00
|
|
|
ExtenderItem *item;
|
|
|
|
if (dg.readEntry("isGroup", false)) {
|
|
|
|
item = new ExtenderGroup(q, extenderItemId.toInt());
|
|
|
|
} else {
|
|
|
|
item = new ExtenderItem(q, extenderItemId.toInt());
|
|
|
|
}
|
2009-01-16 19:49:54 +01:00
|
|
|
sourceApplet->initExtenderItem(item);
|
2008-11-04 00:08:39 +01:00
|
|
|
|
2009-01-16 19:49:54 +01:00
|
|
|
if (temporarySourceApplet) {
|
|
|
|
delete sourceApplet;
|
2008-11-04 00:08:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExtenderPrivate::updateBorders()
|
|
|
|
{
|
|
|
|
foreach (ExtenderItem *item, q->attachedItems()) {
|
|
|
|
if (item && (item->d->background->enabledBorders() != q->enabledBordersForItem(item))) {
|
|
|
|
//call themeChanged to change the backgrounds enabled borders, and move all contained
|
|
|
|
//widgets according to it's changed margins.
|
|
|
|
item->d->themeChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-20 17:37:30 +01:00
|
|
|
void ExtenderPrivate::updateEmptyExtenderLabel()
|
|
|
|
{
|
2009-05-06 16:21:05 +02:00
|
|
|
if (q->isEmpty() && !emptyExtenderLabel &&
|
|
|
|
!emptyExtenderMessage.isEmpty() && !spacerWidget ) {
|
2008-11-20 17:37:30 +01:00
|
|
|
//add the empty extender label.
|
|
|
|
emptyExtenderLabel = new Label(q);
|
2008-12-26 13:27:09 +01:00
|
|
|
emptyExtenderLabel->setAlignment(Qt::AlignCenter);
|
2008-11-20 17:37:30 +01:00
|
|
|
emptyExtenderLabel->setText(emptyExtenderMessage);
|
2009-04-30 02:34:49 +02:00
|
|
|
|
|
|
|
qreal left, top, right, bottom;
|
|
|
|
background->getMargins(left, top, right, bottom);
|
|
|
|
emptyExtenderLabel->nativeWidget()->setMargin(left + right);
|
|
|
|
|
2008-11-20 17:37:30 +01:00
|
|
|
emptyExtenderLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
|
|
|
layout->addItem(emptyExtenderLabel);
|
2009-05-06 16:21:05 +02:00
|
|
|
} else if (!q->isEmpty() && emptyExtenderLabel) {
|
2008-11-20 17:37:30 +01:00
|
|
|
//remove the empty extender label.
|
|
|
|
layout->removeItem(emptyExtenderLabel);
|
|
|
|
delete emptyExtenderLabel;
|
|
|
|
emptyExtenderLabel = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-23 17:30:32 +01:00
|
|
|
ExtenderGroup *ExtenderPrivate::findGroup(const QString &name) const
|
|
|
|
{
|
|
|
|
foreach (ExtenderItem *item, q->attachedItems()) {
|
|
|
|
if (item->isGroup() && item->name() == name) {
|
|
|
|
return qobject_cast<ExtenderGroup*>(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-06 16:21:05 +02:00
|
|
|
bool Extender::isEmpty() const
|
2009-04-30 02:34:49 +02:00
|
|
|
{
|
2009-05-06 16:21:05 +02:00
|
|
|
//If there are no items or only groups, consider this extender empty
|
|
|
|
foreach (ExtenderItem *item, d->attachedExtenderItems) {
|
|
|
|
if (!item->isGroup()) {
|
|
|
|
return false;
|
|
|
|
}
|
2009-04-30 02:34:49 +02:00
|
|
|
}
|
2009-05-06 16:21:05 +02:00
|
|
|
|
|
|
|
return true;
|
2009-04-30 02:34:49 +02:00
|
|
|
}
|
|
|
|
|
2008-11-04 00:08:39 +01:00
|
|
|
} // Plasma namespace
|
|
|
|
|
|
|
|
#include "extender.moc"
|