23 #include <QDesktopWidget> 25 #include <QGraphicsSceneDragDropEvent> 26 #include <QGraphicsGridLayout> 27 #include <QGraphicsLinearLayout> 44 #include "private/applet_p.h" 45 #include "private/applethandle_p.h" 46 #include "private/extender_p.h" 47 #include "private/extenderapplet_p.h" 48 #include "private/extenderitem_p.h" 49 #include "private/extenderitemmimedata_p.h" 50 #include "private/popupapplet_p.h" 55 Spacer::Spacer(QGraphicsItem *parent)
64 void Spacer::setMargins(qreal left, qreal top, qreal right, qreal bottom)
78 painter->setRenderHint(QPainter::Antialiasing);
80 contentsRect().adjusted(m_left, m_top, -m_right, -m_bottom), 4);
82 QColor c =
Plasma::Theme::defaultTheme()->color(
Plasma::Theme::TextColor);
84 painter->fillPath(p, c);
90 d(new ExtenderPrivate(applet, this))
94 if (applet->d->extender) {
95 kWarning() <<
"Applet already has an extender, and can have only one extender." 96 <<
"The previous extender will be destroyed.";
97 delete applet->d->extender.data();
98 }
else if (
PopupApplet *popup = qobject_cast<PopupApplet *>(applet)) {
99 if (!popup->d->graphicsWidget) {
105 applet->d->extender =
this;
106 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
109 d->scrollWidget->setOverflowBordersVisible(
false);
110 d->scrollWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
112 d->scrollWidget->setWidget(d->mainWidget);
113 d->mainWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
114 connect(d->scrollWidget, SIGNAL(viewportGeometryChanged(QRectF)),
115 this, SLOT(viewportGeometryChanged(QRectF)));
117 d->layout =
new QGraphicsLinearLayout(d->mainWidget);
119 d->layout->setContentsMargins(0, 0, 0, 0);
120 d->layout->setSpacing(0);
123 QGraphicsLinearLayout *lay =
new QGraphicsLinearLayout(
Qt::Vertical,
this);
124 lay->addItem(d->scrollWidget);
125 setContentsMargins(0, 0, 0, 0);
126 lay->setContentsMargins(0, 0, 0, 0);
128 d->loadExtenderItems();
130 setAcceptDrops(
true);
135 d->destroying =
true;
143 QList<QWeakPointer<ExtenderItem> > guardedItems;
146 guardedItems << QWeakPointer<ExtenderItem>(
item);
149 d->attachedExtenderItems.clear();
151 foreach (
const QWeakPointer<ExtenderItem> &guardedItem, guardedItems) {
154 item->disconnect(
this);
165 d->emptyExtenderMessage = message;
167 if (d->emptyExtenderLabel) {
168 d->emptyExtenderLabel->setText(message);
174 return d->emptyExtenderMessage;
179 QList<ExtenderItem*> result;
184 return QList<ExtenderItem*>();
187 Containment *containment = d->applet.data()->containment();
194 if (applet->d->extender) {
195 foreach (
ExtenderItem *
item, applet->d->extender.data()->d->attachedExtenderItems) {
196 if (item->d->sourceApplet == d->applet.data()) {
209 return d->attachedExtenderItems;
214 QList<ExtenderItem*> result;
219 return QList<ExtenderItem*>();
221 Containment *containment = d->applet.data()->containment();
228 if (applet->d->extender) {
230 if (item->d->sourceApplet == d->applet.data() && item->
isDetached()) {
245 if (item->d->sourceApplet == d->applet.data() && item->
name() == name) {
257 Containment *containment = d->applet.data()->containment();
262 QList<Containment *> containments;
263 if (containment->
corona()) {
266 containments << containment;
271 if (applet->d->extender) {
272 if (applet->d->extender.data() ==
this) {
277 if (!applet->d->extender) {
281 foreach (
ExtenderItem *item, applet->d->extender.data()->attachedItems()) {
282 if (item->d->sourceApplet == d->applet.data() && item->
name() == name) {
316 KConfigGroup extenderItemGroup(corona->
config(),
"DetachedExtenderItems");
317 foreach (
const QString &extenderItemId, extenderItemGroup.groupList()) {
318 KConfigGroup cg = extenderItemGroup.group(extenderItemId);
319 if (uint(cg.readEntry(
"sourceAppletId", 0)) == d->applet.data()->id() &&
320 cg.readEntry(
"extenderItemName",
"") == name &&
321 cg.readEntry(
"sourceAppletPluginName",
"") == d->applet.data()->pluginName()) {
331 if (d->appearance == appearance) {
341 return d->appearance;
346 QList<ExtenderGroup *> result;
348 if (item->
isGroup() && !result.contains(item->
group())) {
351 result.append(group);
360 return d->applet.data();
366 item->
config().writeEntry(
"extenderItemPosition", item->geometry().y());
372 if (change == QGraphicsItem::ItemPositionHasChanged) {
376 return QGraphicsWidget::itemChange(change, value);
381 QGraphicsWidget::resizeEvent(event);
394 if (
isEmpty() && popupApplet) {
401 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
404 const ExtenderItemMimeData *mimeData =
405 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
420 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
421 const ExtenderItemMimeData *mimeData =
422 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
427 d->setPositionFromDragPosition(event->scenePos());
434 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
435 const ExtenderItemMimeData *mimeData =
436 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
442 Extender *sourceExtender = mimeData->extenderItem()->d->extender;
448 if (popupApplet && sourceExtender !=
this) {
449 kDebug() <<
"leaving another extender then the extender we started, so hide the popup.";
454 if (popupApplet && sourceExtender ==
this && (
attachedItems().count() < 2)) {
455 kDebug() <<
"leaving the extender, and there are no more attached items so hide the popup.";
461 ExtenderApplet *extenderApplet = qobject_cast<ExtenderApplet*>(d->applet.data());
462 if (extenderApplet && sourceExtender ==
this &&
attachedItems().count() < 2 &&
465 kDebug() <<
"leaving the internal extender container, so hide the applet and it's handle.";
466 extenderApplet->hide();
467 AppletHandle *handle =
dynamic_cast<AppletHandle*
>(extenderApplet->parentItem());
478 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
479 const ExtenderItemMimeData *mimeData =
480 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
483 mimeData->extenderItem()->setExtender(
this, event->pos());
484 QApplication::restoreOverrideCursor();
493 if (group && group->
autoHide() && group->
items().isEmpty()) {
497 if (!item->
group()) {
498 if (pos == QPointF(-1, -1)) {
500 d->layout->removeItem(item);
504 d->layout->insertItem(0, item);
507 d->layout->addItem(item);
510 kDebug() <<
"inserting at" << pos << d->insertIndexFromPos(pos) << item->size();
511 d->layout->insertItem(d->insertIndexFromPos(pos),
item);
512 kDebug() << item->size();
516 d->adjustMinimumSize();
519 d->updateEmptyExtenderLabel();
531 d->layout->removeItem(item);
533 if (d->spacerWidget) {
534 d->layout->removeItem(d->spacerWidget);
535 delete d->spacerWidget;
539 d->adjustMinimumSize();
542 d->updateEmptyExtenderLabel();
545 d->layout->updateGeometry();
546 static_cast<QGraphicsLayoutItem *
>(d->scrollWidget)->updateGeometry();
559 if (d->spacerWidget && d->spacerWidget->geometry().contains(pos)) {
564 if (d->spacerWidget) {
565 d->layout->removeItem(d->spacerWidget);
568 int insertIndex = d->insertIndexFromPos(pos);
571 if (!d->spacerWidget) {
572 Spacer *widget =
new Spacer(
this);
573 qreal left, top, right, bottom;
574 d->background->getMargins(left, top, right, bottom);
575 widget->setMargins(left, 4, right, 4);
577 widget->setMinimumSize(item->minimumSize());
578 widget->setPreferredSize(item->preferredSize());
579 widget->setMaximumSize(item->maximumSize());
580 widget->setSizePolicy(item->sizePolicy());
581 d->spacerWidget = widget;
583 d->layout->insertItem(insertIndex, d->spacerWidget);
586 d->updateEmptyExtenderLabel();
593 if (d->spacerWidget) {
595 d->layout->removeItem(d->spacerWidget);
596 delete d->spacerWidget;
599 d->currentSpacerIndex = -1;
601 d->updateEmptyExtenderLabel();
607 if (d->layout->count() < 1) {
618 }
else if (d->appearance ==
TopDownStacked && bottomItem != item) {
628 if (d->scrollWidget->viewportGeometry().height() < d->mainWidget->boundingRect().height()) {
629 if (QApplication::layoutDirection() == Qt::RightToLeft) {
637 borders &= ~d->disabledBordersHint;
648 currentSpacerIndex(-1),
651 emptyExtenderLabel(0),
654 scrollbarVisible(
false)
656 background->setImagePath(
"widgets/extender-background");
659 ExtenderPrivate::~ExtenderPrivate()
663 void ExtenderPrivate::addExtenderItem(
ExtenderItem *
item,
const QPointF &pos)
665 if (attachedExtenderItems.contains(item)) {
666 pendingItems.remove(item);
667 q->itemAddedEvent(item, pos);
672 attachedExtenderItems.append(item);
673 q->itemHoverLeaveEvent(item);
674 pendingItems.insert(item, pos);
675 QTimer::singleShot(0, q, SLOT(delayItemAddedEvent()));
678 void ExtenderPrivate::removeExtenderItem(
ExtenderItem *item)
680 attachedExtenderItems.removeAll(item);
681 pendingItems.remove(item);
684 if (attachedExtenderItems.isEmpty()) {
691 q->itemRemovedEvent(item);
694 int ExtenderPrivate::insertIndexFromPos(
const QPointF &pos)
const 696 int insertIndex = -1;
699 if (pos != QPointF(-1, -1)) {
700 for (
int i = 0; i < layout->count(); ++i) {
701 QRectF siblingGeometry = layout->itemAt(i)->geometry();
702 qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
703 if (pos.y() < middle) {
706 }
else if (pos.y() <= siblingGeometry.bottom()) {
716 void ExtenderPrivate::loadExtenderItems()
722 KConfigGroup cg = applet.data()->
config(
"ExtenderItems");
726 QList<QPair<int, QString> > groupList;
727 foreach (
const QString &extenderItemId, cg.groupList()) {
728 KConfigGroup dg = cg.group(extenderItemId);
729 groupList.append(qMakePair(dg.readEntry(
"extenderItemPosition", 0), extenderItemId));
734 for (
int i = 0; i < groupList.count(); i++) {
735 QPair<int, QString> pair = groupList[i];
737 KConfigGroup dg = cg.group(pair.second);
740 QString extenderItemId = dg.name();
741 QString extenderItemName = dg.readEntry(
"extenderItemName",
"");
742 QString appletName = dg.readEntry(
"sourceAppletPluginName",
"");
743 uint sourceAppletId = dg.readEntry(
"sourceAppletId", 0);
745 bool temporarySourceApplet =
false;
747 kDebug() <<
"applet id = " << applet.data()->
id();
748 kDebug() <<
"sourceappletid = " << sourceAppletId;
752 if (applet.data()->
id() == sourceAppletId) {
754 sourceApplet = applet.data();
762 if (sourceAppletId == q->applet()->id()) {
763 sourceApplet = q->applet();
767 if (applet->
id() == sourceAppletId) {
779 kDebug() <<
"creating a temporary applet as factory";
781 temporarySourceApplet =
true;
787 kDebug() <<
"sourceApplet is null? appletName = " << appletName;
788 kDebug() <<
" extenderItemId = " << extenderItemId;
791 if (dg.readEntry(
"isGroup",
false)) {
797 item->d->sourceApplet = sourceApplet;
799 if (temporarySourceApplet) {
806 void ExtenderPrivate::updateBorders()
809 if (item && (item->d->background->enabledBorders() != q->enabledBordersForItem(item))) {
812 item->d->themeChanged();
817 void ExtenderPrivate::delayItemAddedEvent()
819 QHash<Plasma::ExtenderItem *, QPointF>::const_iterator i = pendingItems.constBegin();
820 while (i != pendingItems.constEnd()) {
821 q->itemAddedEvent(i.key(), i.value());
824 pendingItems.clear();
827 void ExtenderPrivate::updateEmptyExtenderLabel()
829 if (q->isEmpty() && !emptyExtenderLabel &&
832 emptyExtenderLabel =
new Label(q);
833 emptyExtenderLabel->setAlignment(Qt::AlignCenter);
836 qreal left, top, right, bottom;
837 background->getMargins(left, top, right, bottom);
838 emptyExtenderLabel->nativeWidget()->setMargin(left + right);
840 emptyExtenderLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
841 layout->addItem(emptyExtenderLabel);
842 }
else if (!q->isEmpty() && emptyExtenderLabel) {
844 layout->removeItem(emptyExtenderLabel);
845 delete emptyExtenderLabel;
846 emptyExtenderLabel = 0;
850 void ExtenderPrivate::adjustMinimumSize()
853 scrollWidget->setMinimumWidth(mainWidget->effectiveSizeHint(Qt::MinimumSize).width() + 32);
855 scrollWidget->setMinimumHeight(qMin((qreal)300, mainWidget->effectiveSizeHint(Qt::MinimumSize).height()));
858 void ExtenderPrivate::setPositionFromDragPosition(
const QPointF &pos)
860 const qreal ratio = (q->mapFromScene(pos).y()/scrollWidget->size().height());
862 mainWidget->setPos(mainWidget->pos().x(), 30 + (ratio *(scrollWidget->size().height() - mainWidget->size().height() - 30)));
865 ExtenderGroup *ExtenderPrivate::findGroup(
const QString &name)
const 878 pendingItems.remove(item);
880 if (attachedExtenderItems.contains(item)) {
882 removeExtenderItem(item);
886 void ExtenderPrivate::viewportGeometryChanged(
const QRectF &rect)
889 scrollbarVisible = (rect.height() > mainWidget->boundingRect().height());
893 bool scroll = !(rect.height() >= mainWidget->boundingRect().height());
895 if (scroll != scrollbarVisible) {
896 scrollbarVisible = scroll;
901 void ExtenderPrivate::setDisabledBordersHint(
const FrameSvg::EnabledBorders borders)
903 if (disabledBordersHint == borders) {
907 disabledBordersHint = borders;
909 item->d->themeChanged();
913 void ExtenderPrivate::adjustSize()
916 QSizeF size = mainWidget->effectiveSizeHint(Qt::PreferredSize);
919 if (containment && containment->
corona()) {
923 q->resize(qMin(screenRect.width()/3, (int)size.width()),
924 qMin(screenRect.height()/3, (int)size.height()));
930 foreach (
ExtenderItem *item, d->attachedExtenderItems) {
936 if (group && (!group->
autoHide() || group->
items().size() > 0)) {
947 #include "extender.moc"
the size of the applet was changed
QList< ExtenderItem * > items() const
Appearance
Description on how to render the extender's items.
The applet is constrained horizontally, but can expand vertically.
QList< ExtenderItem * > attachedItems() const
virtual QRect screenGeometry(int id) const
Returns the geometry of a given screen.
friend class ExtenderItem
Extends applets to allow detachable parts.
virtual void initExtenderItem(ExtenderItem *item)
Gets called when an extender item has to be initialized after a plasma restart.
Draws no borders on the extender's items.
QList< ExtenderItem * > items() const
KConfigGroup config() const
fetch the configuration of this widget.
QList< Containment * > containments() const
void resizeEvent(QGraphicsSceneResizeEvent *event)
Reimplemented from QGraphicsWidget.
virtual void itemRemovedEvent(ExtenderItem *item)
Get's called after an item has been removed from this extender.
virtual FrameSvg::EnabledBorders enabledBordersForItem(ExtenderItem *item) const
This function get's called on every item to determine which background border's to render...
Applet::List applets() const
void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
Reimplemented from QGraphicsWidget.
Provides an SVG with borders.
The applet is constrained vertically, but can expand horizontally.
Namespace for everything in libplasma.
void dragMoveEvent(QGraphicsSceneDragDropEvent *event)
Reimplemented from QGraphicsWidget.
Corona * corona() const
Returns the Corona (if any) that this Containment is hosted by.
QVariant itemChange(GraphicsItemChange change, const QVariant &value)
Reimplemented from QGraphicsWidget.
Draws no borders on the bottom extenderitem, but draws the left, bottom and right border on subsequen...
QList< ExtenderGroup * > groups() const
KSharedConfig::Ptr config() const
Returns the config file used to store the configuration for this Corona.
QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
Returns a nicely rounded rectanglular path for painting.
Q_INVOKABLE ExtenderGroup * group(const QString &name) const
Extra convenience function for obtaining groups specified by name.
Appearance appearance() const
void mousePressEvent(QGraphicsSceneMouseEvent *event)
Reimplemented from QGraphicsWidget.
Provides a plasma-themed QLabel.
QString emptyExtenderMessage() const
virtual void itemHoverLeaveEvent(ExtenderItem *item)
Get's called when an ExtenderItem that was previously hovering over this extender moves away from thi...
virtual void itemHoverEnterEvent(ExtenderItem *item)
Get's called when an ExtenderItem that get's dragged enters this extender.
Draws no borders on the topmost extenderitem, but draws the left, top and right border on subsequent ...
void geometryChanged()
Fires when an extender's preferred size changes.
ExtenderGroup * group() const
Q_INVOKABLE ExtenderItem * item(const QString &name) const
This function can be used for obtaining the extender item specified by name.
Containment * containment() const
virtual void itemAddedEvent(ExtenderItem *item, const QPointF &pos=QPointF(-1,-1))
Get's called after an item has been added to this extender.
void setEmptyExtenderMessage(const QString &message)
KConfigGroup config() const
Returns the KConfigGroup to access the applets configuration.
void setAppearance(Appearance appearance)
Use this function to instruct the extender on how to render its items.
Q_INVOKABLE bool hasItem(const QString &name) const
This function can be used for easily determining if a certain item is already displayed in an extende...
virtual void saveState()
This function get's called for every extender when plasma exits.
Allows for grouping of extender items.
virtual void itemHoverMoveEvent(ExtenderItem *item, const QPointF &pos)
Gets called when an ExtenderItem is hovering over this extender.
QList< ExtenderItem * > detachedItems() const
void dropEvent(QGraphicsSceneDragDropEvent *event)
Reimplemented from QGraphicsWidget.
The base class for plugins that provide backgrounds and applet grouping containers.
friend class ExtenderGroup
void dragEnterEvent(QGraphicsSceneDragDropEvent *event)
Reimplemented from QGraphicsWidget.
Provides detachable items for an Extender.
A QGraphicsScene for Plasma::Applets.
static Applet * load(const QString &name, uint appletId=0, const QVariantList &args=QVariantList())
Attempts to load an applet.