• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

Plasma

  • plasma
  • extenders
extender.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2008, 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301 USA
18 */
19
20#include "extender.h"
21
22#include <QAction>
23#include <QDesktopWidget>
24#include <QLabel>
25#include <QGraphicsSceneDragDropEvent>
26#include <QGraphicsGridLayout>
27#include <QGraphicsLinearLayout>
28#include <QPainter>
29
30#include "applet.h"
31#include "containment.h"
32#include "corona.h"
33#include "dialog.h"
34#include "extendergroup.h"
35#include "extenderitem.h"
36#include "framesvg.h"
37#include "paintutils.h"
38#include "popupapplet.h"
39#include "svg.h"
40#include "theme.h"
41#include "widgets/label.h"
42#include "widgets/scrollwidget.h"
43
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"
51
52namespace Plasma
53{
54
55Spacer::Spacer(QGraphicsItem *parent)
56 : QGraphicsWidget(parent)
57{
58}
59
60Spacer::~Spacer()
61{
62}
63
64void Spacer::setMargins(qreal left, qreal top, qreal right, qreal bottom)
65{
66 m_left = left;
67 m_top = top;
68 m_right = right;
69 m_bottom = bottom;
70}
71
72
73void Spacer::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
74{
75 Q_UNUSED(option)
76 Q_UNUSED(widget)
77
78 painter->setRenderHint(QPainter::Antialiasing);
79 QPainterPath p = Plasma::PaintUtils::roundedRectangle(
80 contentsRect().adjusted(m_left, m_top, -m_right, -m_bottom), 4);
81
82 QColor c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
83 c.setAlphaF(0.3);
84 painter->fillPath(p, c);
85}
86
87
88Extender::Extender(Applet *applet)
89 : QGraphicsWidget(applet),
90 d(new ExtenderPrivate(applet, this))
91{
92 //At multiple places in the extender code, we make the assumption that an applet doesn't have
93 //more then one extender. If a second extender is created, destroy the first one to avoid leaks.
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) {
100 // ensure the popup gets a dialog with us as the graphics widget
101 popup->d->popupConstraintsEvent(SizeConstraint);
102 }
103 }
104
105 applet->d->extender = this;
106 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
107
108 d->scrollWidget = new ScrollWidget(this);
109 d->scrollWidget->setOverflowBordersVisible(false);
110 d->scrollWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
111 d->mainWidget = new QGraphicsWidget(d->scrollWidget);
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)));
116
117 d->layout = new QGraphicsLinearLayout(d->mainWidget);
118 d->layout->setOrientation(Qt::Vertical);
119 d->layout->setContentsMargins(0, 0, 0, 0);
120 d->layout->setSpacing(0);
121
122
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);
127
128 d->loadExtenderItems();
129
130 setAcceptDrops(true);
131}
132
133Extender::~Extender()
134{
135 d->destroying = true;
136
137 // when deleting items that are connected to us, it can happen that
138 // other items which are in groups may get deleted as well. so we first
139 // build a new list of guarded pointers, and then use that list. that
140 // way when items are deleted behind our back, we are still safe.
141 // FIXME: having groups and items in the same collection is probably a mistake,
142 // so would be a good candidate for a refactoring exercise
143 QList<QWeakPointer<ExtenderItem> > guardedItems;
144
145 foreach (ExtenderItem *item, d->attachedExtenderItems) {
146 guardedItems << QWeakPointer<ExtenderItem>(item);
147 }
148
149 d->attachedExtenderItems.clear();
150
151 foreach (const QWeakPointer<ExtenderItem> &guardedItem, guardedItems) {
152 ExtenderItem *item = guardedItem.data();
153 if (item) {
154 item->disconnect(this);
155 delete item;
156 }
157 }
158
159
160 delete d;
161}
162
163void Extender::setEmptyExtenderMessage(const QString &message)
164{
165 d->emptyExtenderMessage = message;
166
167 if (d->emptyExtenderLabel) {
168 d->emptyExtenderLabel->setText(message);
169 }
170}
171
172QString Extender::emptyExtenderMessage() const
173{
174 return d->emptyExtenderMessage;
175}
176
177QList<ExtenderItem*> Extender::items() const
178{
179 QList<ExtenderItem*> result;
180
181 //FIXME: a triple nested loop ... ew. there should be a more efficient way to do this
182 //iterate through all extenders we can find and check each extenders source applet.
183 if (!d->applet) {
184 return QList<ExtenderItem*>();
185 }
186
187 Containment *containment = d->applet.data()->containment();
188 if (!containment) {
189 return result;
190 }
191
192 foreach (Containment *c, containment->corona()->containments()) {
193 foreach (Applet *applet, c->applets()) {
194 if (applet->d->extender) {
195 foreach (ExtenderItem *item, applet->d->extender.data()->d->attachedExtenderItems) {
196 if (item->d->sourceApplet == d->applet.data()) {
197 result.append(item);
198 }
199 }
200 }
201 }
202 }
203
204 return result;
205}
206
207QList<ExtenderItem*> Extender::attachedItems() const
208{
209 return d->attachedExtenderItems;
210}
211
212QList<ExtenderItem*> Extender::detachedItems() const
213{
214 QList<ExtenderItem*> result;
215
216 //FIXME: a triple nested loop ... ew. there should be a more efficient way to do this
217 //iterate through all extenders we can find and check each extenders source applet.
218 if (!d->applet) {
219 return QList<ExtenderItem*>();
220 }
221 Containment *containment = d->applet.data()->containment();
222 if (!containment) {
223 return result;
224 }
225
226 foreach (Containment *c, containment->corona()->containments()) {
227 foreach (Applet *applet, c->applets()) {
228 if (applet->d->extender) {
229 foreach (ExtenderItem *item, applet->d->extender.data()->attachedItems()) {
230 if (item->d->sourceApplet == d->applet.data() && item->isDetached()) {
231 result.append(item);
232 }
233 }
234 }
235 }
236 }
237
238 return result;
239}
240
241ExtenderItem *Extender::item(const QString &name) const
242{
243 // chances are the item is in our own extender, so check there first
244 foreach (ExtenderItem *item, d->attachedExtenderItems) {
245 if (item->d->sourceApplet == d->applet.data() && item->name() == name) {
246 return item;
247 }
248 }
249
250 // maybe it's been moved elsewhere, so lets search through the entire tree of elements
251 //FIXME: a triple nested loop ... ew. there should be a more efficient way to do this
252 //iterate through all extenders we can find and check each extenders source applet.
253 if (!d->applet) {
254 return 0;
255 }
256
257 Containment *containment = d->applet.data()->containment();
258 if (!containment) {
259 return 0;
260 }
261
262 QList<Containment *> containments;
263 if (containment->corona()) {
264 containments = containment->corona()->containments();
265 } else {
266 containments << containment;
267 }
268
269 foreach (Containment *c, containments) {
270 foreach (Applet *applet, c->applets()) {
271 if (applet->d->extender) {
272 if (applet->d->extender.data() == this) {
273 // skip it, we checked it already
274 continue;
275 }
276
277 if (!applet->d->extender) {
278 continue;
279 }
280
281 foreach (ExtenderItem *item, applet->d->extender.data()->attachedItems()) {
282 if (item->d->sourceApplet == d->applet.data() && item->name() == name) {
283 return item;
284 }
285 }
286 }
287 }
288 }
289
290 return 0;
291}
292
293ExtenderGroup *Extender::group(const QString &name) const
294{
295 return qobject_cast<ExtenderGroup*>(item(name));
296}
297
298bool Extender::hasItem(const QString &name) const
299{
300 if (item(name)) {
301 return true;
302 }
303
304 if (!d->applet) {
305 return false;
306 }
307
308 //if item(name) returns false, that doesn't mean that the item doesn't exist, just that it has
309 //not been instantiated yet. check to see if there's mention of this item existing in the
310 //plasma config's section DetachedExtenderItems
311 Corona *corona = qobject_cast<Corona *>(scene());
312 if (!corona) {
313 return false;
314 }
315
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()) {
322 return true;
323 }
324 }
325
326 return false;
327}
328
329void Extender::setAppearance(Appearance appearance)
330{
331 if (d->appearance == appearance) {
332 return;
333 }
334
335 d->appearance = appearance;
336 d->updateBorders();
337}
338
339Extender::Appearance Extender::appearance() const
340{
341 return d->appearance;
342}
343
344QList<ExtenderGroup*> Extender::groups() const
345{
346 QList<ExtenderGroup *> result;
347 foreach (ExtenderItem *item, d->attachedExtenderItems) {
348 if (item->isGroup() && !result.contains(item->group())) {
349 ExtenderGroup *group = qobject_cast<ExtenderGroup *>(item);
350 if (group) {
351 result.append(group);
352 }
353 }
354 }
355 return result;
356}
357
358Applet *Extender::applet() const
359{
360 return d->applet.data();
361}
362
363void Extender::saveState()
364{
365 foreach (ExtenderItem *item, attachedItems()) {
366 item->config().writeEntry("extenderItemPosition", item->geometry().y());
367 }
368}
369
370QVariant Extender::itemChange(GraphicsItemChange change, const QVariant &value)
371{
372 if (change == QGraphicsItem::ItemPositionHasChanged) {
373 emit geometryChanged();
374 }
375
376 return QGraphicsWidget::itemChange(change, value);
377}
378
379void Extender::resizeEvent(QGraphicsSceneResizeEvent *event)
380{
381 QGraphicsWidget::resizeEvent(event);
382 emit geometryChanged();
383}
384
385void Extender::mousePressEvent(QGraphicsSceneMouseEvent *event)
386{
387 Q_UNUSED(event)
388
389 if (!d->applet) {
390 return;
391 }
392
393 PopupApplet *popupApplet = qobject_cast<PopupApplet*>(d->applet.data());
394 if (isEmpty() && popupApplet) {
395 popupApplet->hidePopup();
396 }
397}
398
399void Extender::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
400{
401 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
402 event->accept();
403
404 const ExtenderItemMimeData *mimeData =
405 qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
406
407 if (mimeData) {
408 itemHoverEnterEvent(mimeData->extenderItem());
409
410 PopupApplet *popupApplet = qobject_cast<PopupApplet*>(d->applet.data());
411 if (popupApplet) {
412 popupApplet->showPopup();
413 }
414 }
415 }
416}
417
418void Extender::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
419{
420 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
421 const ExtenderItemMimeData *mimeData =
422 qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
423
424 if (mimeData) {
425 itemHoverMoveEvent(mimeData->extenderItem(), event->pos());
426
427 d->setPositionFromDragPosition(event->scenePos());
428 }
429 }
430}
431
432void Extender::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
433{
434 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
435 const ExtenderItemMimeData *mimeData =
436 qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
437
438 if (mimeData) {
439 itemHoverLeaveEvent(mimeData->extenderItem());
440
441 //Some logic to conveniently show/hide popups or applets when logical.
442 Extender *sourceExtender = mimeData->extenderItem()->d->extender;
443
444 //Hide popups when they're not the extender where we started, and we're leaving the
445 //extender. Use a small timeout here, to avoid accidental hides of extenders we're
446 //targetting.
447 PopupApplet *popupApplet = qobject_cast<PopupApplet*>(d->applet.data());
448 if (popupApplet && sourceExtender != this) {
449 kDebug() << "leaving another extender then the extender we started, so hide the popup.";
450 popupApplet->showPopup(250);
451 }
452
453 //Hide popups when we drag the last item away.
454 if (popupApplet && sourceExtender == this && (attachedItems().count() < 2)) {
455 kDebug() << "leaving the extender, and there are no more attached items so hide the popup.";
456 popupApplet->hidePopup();
457 }
458
459 //Hide empty internal extender containers when we drag the last item away. Avoids having
460 //an ugly empty applet on the desktop temporarily.
461 ExtenderApplet *extenderApplet = qobject_cast<ExtenderApplet*>(d->applet.data());
462 if (extenderApplet && sourceExtender == this && attachedItems().count() < 2 &&
463 extenderApplet->formFactor() != Plasma::Horizontal &&
464 extenderApplet->formFactor() != Plasma::Vertical) {
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());
468 if (handle) {
469 handle->hide();
470 }
471 }
472 }
473 }
474}
475
476void Extender::dropEvent(QGraphicsSceneDragDropEvent *event)
477{
478 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
479 const ExtenderItemMimeData *mimeData =
480 qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
481
482 if (mimeData) {
483 mimeData->extenderItem()->setExtender(this, event->pos());
484 QApplication::restoreOverrideCursor();
485 itemHoverLeaveEvent(0);
486 }
487 }
488}
489
490void Extender::itemAddedEvent(ExtenderItem *item, const QPointF &pos)
491{
492 ExtenderGroup *group = item->isGroup() ? static_cast<ExtenderGroup*>(item) : 0;
493 if (group && group->autoHide() && group->items().isEmpty()) {
494 return;
495 }
496
497 if (!item->group()) {
498 if (pos == QPointF(-1, -1)) {
499 //if it was already there, reposition
500 d->layout->removeItem(item);
501 //if just plain adding an item, add it at a sane position:
502 if (appearance() == BottomUpStacked) {
503 //at the top
504 d->layout->insertItem(0, item);
505 } else {
506 //at the bottom
507 d->layout->addItem(item);
508 }
509 } else {
510 kDebug() << "inserting at" << pos << d->insertIndexFromPos(pos) << item->size();
511 d->layout->insertItem(d->insertIndexFromPos(pos), item);
512 kDebug() << item->size();
513 }
514 }
515
516 d->adjustMinimumSize();
517
518 //remove the empty extender message if needed.
519 d->updateEmptyExtenderLabel();
520 d->updateBorders();
521
522 d->adjustSize();
523}
524
525void Extender::itemRemovedEvent(ExtenderItem *item)
526{
527 if (d->destroying) {
528 return;
529 }
530
531 d->layout->removeItem(item);
532
533 if (d->spacerWidget) {
534 d->layout->removeItem(d->spacerWidget);
535 delete d->spacerWidget;
536 d->spacerWidget = 0;
537 }
538
539 d->adjustMinimumSize();
540
541 //add the empty extender message if needed.
542 d->updateEmptyExtenderLabel();
543 d->updateBorders();
544
545 d->layout->updateGeometry();
546 static_cast<QGraphicsLayoutItem *>(d->scrollWidget)->updateGeometry();
547 updateGeometry();
548
549 d->adjustSize();
550}
551
552void Extender::itemHoverEnterEvent(ExtenderItem *item)
553{
554 itemHoverMoveEvent(item, QPointF(0, 0));
555}
556
557void Extender::itemHoverMoveEvent(ExtenderItem *item, const QPointF &pos)
558{
559 if (d->spacerWidget && d->spacerWidget->geometry().contains(pos)) {
560 return;
561 }
562
563 //Make sure we remove any spacer that might already be in the layout.
564 if (d->spacerWidget) {
565 d->layout->removeItem(d->spacerWidget);
566 }
567
568 int insertIndex = d->insertIndexFromPos(pos);
569
570 //Create a widget that functions as spacer, and add that to the layout.
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);
576
577 widget->setMinimumSize(item->minimumSize());
578 widget->setPreferredSize(item->preferredSize());
579 widget->setMaximumSize(item->maximumSize());
580 widget->setSizePolicy(item->sizePolicy());
581 d->spacerWidget = widget;
582 }
583 d->layout->insertItem(insertIndex, d->spacerWidget);
584
585 //Make sure we remove any 'no detachables' label that might be there, and update the layout.
586 d->updateEmptyExtenderLabel();
587}
588
589void Extender::itemHoverLeaveEvent(ExtenderItem *item)
590{
591 Q_UNUSED(item);
592
593 if (d->spacerWidget) {
594 //Remove any trace of the spacer widget.
595 d->layout->removeItem(d->spacerWidget);
596 delete d->spacerWidget;
597 d->spacerWidget = 0;
598
599 d->currentSpacerIndex = -1;
600
601 d->updateEmptyExtenderLabel();
602 }
603}
604
605FrameSvg::EnabledBorders Extender::enabledBordersForItem(ExtenderItem *item) const
606{
607 if (d->layout->count() < 1) {
608 return 0;
609 }
610
611 ExtenderItem *topItem = dynamic_cast<ExtenderItem*>(d->layout->itemAt(0));
612 ExtenderItem *bottomItem = dynamic_cast<ExtenderItem*>(d->layout->itemAt(d->layout->count() - 1));
613
614 FrameSvg::EnabledBorders borders = FrameSvg::NoBorder;
615
616 if (item->group()) {
617 return FrameSvg::NoBorder;
618 } else if (d->appearance == TopDownStacked && bottomItem != item) {
619 borders = FrameSvg::LeftBorder | FrameSvg::BottomBorder | FrameSvg::RightBorder;
620 } else if (d->appearance == BottomUpStacked && topItem != item) {
621 borders = FrameSvg::LeftBorder | FrameSvg::TopBorder | FrameSvg::RightBorder;
622 } else if (d->appearance != NoBorders) {
623 borders = FrameSvg::LeftBorder | FrameSvg::RightBorder;
624 } else {
625 return FrameSvg::NoBorder;
626 }
627
628 if (d->scrollWidget->viewportGeometry().height() < d->mainWidget->boundingRect().height()) {
629 if (QApplication::layoutDirection() == Qt::RightToLeft) {
630 borders &= ~FrameSvg::LeftBorder;
631 } else {
632 borders &= ~FrameSvg::RightBorder;
633 }
634 }
635
636 //someone (i.e. a Dialog) told the extender to disable some border?
637 borders &= ~d->disabledBordersHint;
638
639
640 return borders;
641}
642
643ExtenderPrivate::ExtenderPrivate(Applet *applet, Extender *extender) :
644 q(extender),
645 applet(applet),
646 background(new FrameSvg(extender)),
647 disabledBordersHint(FrameSvg::NoBorder),
648 currentSpacerIndex(-1),
649 spacerWidget(0),
650 emptyExtenderMessage(QString()),
651 emptyExtenderLabel(0),
652 appearance(Extender::NoBorders),
653 destroying(false),
654 scrollbarVisible(false)
655{
656 background->setImagePath("widgets/extender-background");
657}
658
659ExtenderPrivate::~ExtenderPrivate()
660{
661}
662
663void ExtenderPrivate::addExtenderItem(ExtenderItem *item, const QPointF &pos)
664{
665 if (attachedExtenderItems.contains(item)) {
666 pendingItems.remove(item);
667 q->itemAddedEvent(item, pos);
668 return;
669 }
670
671 QObject::connect(item, SIGNAL(destroyed(Plasma::ExtenderItem*)), q, SLOT(extenderItemDestroyed(Plasma::ExtenderItem*)));
672 attachedExtenderItems.append(item);
673 q->itemHoverLeaveEvent(item);
674 pendingItems.insert(item, pos);
675 QTimer::singleShot(0, q, SLOT(delayItemAddedEvent()));
676}
677
678void ExtenderPrivate::removeExtenderItem(ExtenderItem *item)
679{
680 attachedExtenderItems.removeAll(item);
681 pendingItems.remove(item);
682
683 //collapse the popupapplet if the last item is removed.
684 if (attachedExtenderItems.isEmpty()) {
685 PopupApplet *popupApplet = qobject_cast<PopupApplet*>(applet.data());
686 if (popupApplet) {
687 popupApplet->hidePopup();
688 }
689 }
690
691 q->itemRemovedEvent(item);
692}
693
694int ExtenderPrivate::insertIndexFromPos(const QPointF &pos) const
695{
696 int insertIndex = -1;
697
698 //XXX: duplicated from panel
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) {
704 insertIndex = i;
705 break;
706 } else if (pos.y() <= siblingGeometry.bottom()) {
707 insertIndex = i + 1;
708 break;
709 }
710 }
711 }
712
713 return insertIndex;
714}
715
716void ExtenderPrivate::loadExtenderItems()
717{
718 if (!applet) {
719 return;
720 }
721
722 KConfigGroup cg = applet.data()->config("ExtenderItems");
723
724 //first create a list of extenderItems, and then sort them on their position, so the items get
725 //recreated in the correct order.
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));
730 }
731 qSort(groupList);
732
733 //iterate over the extender items
734 for (int i = 0; i < groupList.count(); i++) {
735 QPair<int, QString> pair = groupList[i];
736
737 KConfigGroup dg = cg.group(pair.second);
738
739 //load the relevant settings.
740 QString extenderItemId = dg.name();
741 QString extenderItemName = dg.readEntry("extenderItemName", "");
742 QString appletName = dg.readEntry("sourceAppletPluginName", "");
743 uint sourceAppletId = dg.readEntry("sourceAppletId", 0);
744
745 bool temporarySourceApplet = false;
746
747 kDebug() << "applet id = " << applet.data()->id();
748 kDebug() << "sourceappletid = " << sourceAppletId;
749
750 //find the source applet.
751 Applet *sourceApplet = 0;
752 if (applet.data()->id() == sourceAppletId) {
753 // it's ours!
754 sourceApplet = applet.data();
755 } else {
756 // maybe it's foreign?
757 Containment *containment = applet.data()->containment();
758
759 if (containment) {
760 Corona *corona = containment->corona();
761
762 if (sourceAppletId == q->applet()->id()) {
763 sourceApplet = q->applet();
764 } else {
765 foreach (Containment *containment, corona->containments()) {
766 foreach (Applet *applet, containment->applets()) {
767 if (applet->id() == sourceAppletId) {
768 sourceApplet = applet;
769 }
770 }
771 }
772 }
773 }
774 }
775
776 //There is no source applet. We just instantiate one just for the sake of creating
777 //detachables.
778 if (!sourceApplet) {
779 kDebug() << "creating a temporary applet as factory";
780 sourceApplet = Applet::load(appletName);
781 temporarySourceApplet = true;
782 //TODO: maybe add an option to applet to indicate that it shouldn't be deleted after
783 //having used it as factory.
784 }
785
786 if (!sourceApplet) {
787 kDebug() << "sourceApplet is null? appletName = " << appletName;
788 kDebug() << " extenderItemId = " << extenderItemId;
789 } else {
790 ExtenderItem *item;
791 if (dg.readEntry("isGroup", false)) {
792 item = new ExtenderGroup(q, extenderItemId.toInt());
793 } else {
794 item = new ExtenderItem(q, extenderItemId.toInt());
795 }
796 sourceApplet->initExtenderItem(item);
797 item->d->sourceApplet = sourceApplet;
798
799 if (temporarySourceApplet) {
800 delete sourceApplet;
801 }
802 }
803 }
804}
805
806void ExtenderPrivate::updateBorders()
807{
808 foreach (ExtenderItem *item, attachedExtenderItems) {
809 if (item && (item->d->background->enabledBorders() != q->enabledBordersForItem(item))) {
810 //call themeChanged to change the backgrounds enabled borders, and move all contained
811 //widgets according to it's changed margins.
812 item->d->themeChanged();
813 }
814 }
815}
816
817void ExtenderPrivate::delayItemAddedEvent()
818{
819 QHash<Plasma::ExtenderItem *, QPointF>::const_iterator i = pendingItems.constBegin();
820 while (i != pendingItems.constEnd()) {
821 q->itemAddedEvent(i.key(), i.value());
822 ++i;
823 }
824 pendingItems.clear();
825}
826
827void ExtenderPrivate::updateEmptyExtenderLabel()
828{
829 if (q->isEmpty() && !emptyExtenderLabel &&
830 !emptyExtenderMessage.isEmpty() && !spacerWidget ) {
831 //add the empty extender label.
832 emptyExtenderLabel = new Label(q);
833 emptyExtenderLabel->setAlignment(Qt::AlignCenter);
834 emptyExtenderLabel->setText(emptyExtenderMessage);
835
836 qreal left, top, right, bottom;
837 background->getMargins(left, top, right, bottom);
838 emptyExtenderLabel->nativeWidget()->setMargin(left + right);
839
840 emptyExtenderLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
841 layout->addItem(emptyExtenderLabel);
842 } else if (!q->isEmpty() && emptyExtenderLabel) {
843 //remove the empty extender label.
844 layout->removeItem(emptyExtenderLabel);
845 delete emptyExtenderLabel;
846 emptyExtenderLabel = 0;
847 }
848}
849
850void ExtenderPrivate::adjustMinimumSize()
851{
852 //FIXME: hardcoded number for the scrollbar
853 scrollWidget->setMinimumWidth(mainWidget->effectiveSizeHint(Qt::MinimumSize).width() + 32);
854 //FIXME: hardcoded number
855 scrollWidget->setMinimumHeight(qMin((qreal)300, mainWidget->effectiveSizeHint(Qt::MinimumSize).height()));
856}
857
858void ExtenderPrivate::setPositionFromDragPosition(const QPointF &pos)
859{
860 const qreal ratio = (q->mapFromScene(pos).y()/scrollWidget->size().height());
861
862 mainWidget->setPos(mainWidget->pos().x(), 30 + (ratio *(scrollWidget->size().height() - mainWidget->size().height() - 30)));
863}
864
865ExtenderGroup *ExtenderPrivate::findGroup(const QString &name) const
866{
867 foreach (ExtenderItem *item, attachedExtenderItems) {
868 if (item->isGroup() && item->name() == name) {
869 return qobject_cast<ExtenderGroup*>(item);
870 }
871 }
872
873 return 0;
874}
875
876void ExtenderPrivate::extenderItemDestroyed(Plasma::ExtenderItem *item)
877{
878 pendingItems.remove(item);
879
880 if (attachedExtenderItems.contains(item)) {
881 // removeExtenderItem also removes the item from attachedExtenderItems
882 removeExtenderItem(item);
883 }
884}
885
886void ExtenderPrivate::viewportGeometryChanged(const QRectF &rect)
887{
888 if (appearance != Extender::TopDownStacked && appearance != Extender::BottomUpStacked) {
889 scrollbarVisible = (rect.height() > mainWidget->boundingRect().height());
890 return;
891 }
892
893 bool scroll = !(rect.height() >= mainWidget->boundingRect().height());
894
895 if (scroll != scrollbarVisible) {
896 scrollbarVisible = scroll;
897 updateBorders();
898 }
899}
900
901void ExtenderPrivate::setDisabledBordersHint(const FrameSvg::EnabledBorders borders)
902{
903 if (disabledBordersHint == borders) {
904 return;
905 }
906
907 disabledBordersHint = borders;
908 foreach (Plasma::ExtenderItem *item, attachedExtenderItems) {
909 item->d->themeChanged();
910 }
911}
912
913void ExtenderPrivate::adjustSize()
914{
915 QRect screenRect;
916 QSizeF size = mainWidget->effectiveSizeHint(Qt::PreferredSize);
917 if (applet) {
918 Containment *containment = applet.data()->containment();
919 if (containment && containment->corona()) {
920 screenRect = containment->corona()->screenGeometry(containment->screen());
921 }
922 }
923 q->resize(qMin(screenRect.width()/3, (int)size.width()),
924 qMin(screenRect.height()/3, (int)size.height()));
925}
926
927bool Extender::isEmpty() const
928{
929 //It's empty if it doesn't have items or has only group that are empty and autohide
930 foreach (ExtenderItem *item, d->attachedExtenderItems) {
931 if (!item->isGroup()) {
932 return false;
933 } else {
934 //a static_cast here should be safe, it's not the case apparently
935 ExtenderGroup *group = qobject_cast<ExtenderGroup *>(item);
936 if (group && (!group->autoHide() || group->items().size() > 0)) {
937 return false;
938 }
939 }
940 }
941
942 return true;
943}
944
945} // Plasma namespace
946
947#include "extender.moc"
applet.h
Plasma::Applet
The base Applet class.
Definition: applet.h:78
Plasma::Applet::id
uint id
Definition: applet.h:91
Plasma::Applet::config
KConfigGroup config() const
Returns the KConfigGroup to access the applets configuration.
Definition: applet.cpp:450
Plasma::Applet::containment
Containment * containment() const
Definition: applet.cpp:1518
Plasma::Containment
The base class for plugins that provide backgrounds and applet grouping containers.
Definition: containment.h:73
Plasma::Containment::corona
Corona * corona() const
Returns the Corona (if any) that this Containment is hosted by.
Definition: containment.cpp:525
Plasma::Containment::applets
Applet::List applets() const
Definition: containment.cpp:950
Plasma::Corona
A QGraphicsScene for Plasma::Applets.
Definition: corona.h:49
Plasma::Corona::containments
QList< Containment * > containments() const
Definition: corona.cpp:328
Plasma::Corona::config
KSharedConfig::Ptr config() const
Returns the config file used to store the configuration for this Corona.
Definition: corona.cpp:340
Plasma::Corona::screenGeometry
virtual QRect screenGeometry(int id) const
Returns the geometry of a given screen.
Definition: corona.cpp:445
Plasma::ExtenderGroup
Allows for grouping of extender items.
Definition: extendergroup.h:51
Plasma::ExtenderGroup::items
QList< ExtenderItem * > items() const
Definition: extendergroup.cpp:109
Plasma::ExtenderGroup::autoHide
bool autoHide
Definition: extendergroup.h:53
Plasma::ExtenderItem
Provides detachable items for an Extender.
Definition: extenderitem.h:81
Plasma::ExtenderItem::isDetached
bool isDetached() const
Definition: extenderitem.cpp:531
Plasma::ExtenderItem::name
QString name
Definition: extenderitem.h:85
Plasma::ExtenderItem::config
KConfigGroup config() const
fetch the configuration of this widget.
Definition: extenderitem.cpp:240
Plasma::ExtenderItem::isGroup
bool isGroup() const
Definition: extenderitem.cpp:488
Plasma::ExtenderItem::group
ExtenderGroup * group() const
Definition: extenderitem.cpp:483
Plasma::Extender
Extends applets to allow detachable parts.
Definition: extender.h:66
Plasma::Extender::applet
Applet * applet() const
Definition: extender.cpp:358
Plasma::Extender::attachedItems
QList< ExtenderItem * > attachedItems
Definition: extender.h:70
Plasma::Extender::isEmpty
bool isEmpty() const
Definition: extender.cpp:927
Plasma::Extender::item
Q_INVOKABLE ExtenderItem * item(const QString &name) const
This function can be used for obtaining the extender item specified by name.
Definition: extender.cpp:241
Plasma::Extender::Appearance
Appearance
Description on how to render the extender's items.
Definition: extender.h:79
Plasma::Extender::NoBorders
@ NoBorders
Draws no borders on the extender's items.
Definition: extender.h:80
Plasma::Extender::TopDownStacked
@ TopDownStacked
Draws no borders on the bottom extenderitem, but draws the left, bottom and right border on subsequen...
Definition: extender.h:89
Plasma::Extender::BottomUpStacked
@ BottomUpStacked
Draws no borders on the topmost extenderitem, but draws the left, top and right border on subsequent ...
Definition: extender.h:83
Plasma::Extender::geometryChanged
void geometryChanged()
Fires when an extender's preferred size changes.
Plasma::Extender::group
Q_INVOKABLE ExtenderGroup * group(const QString &name) const
Extra convenience function for obtaining groups specified by name.
Definition: extender.cpp:293
Plasma::Extender::itemHoverLeaveEvent
virtual void itemHoverLeaveEvent(ExtenderItem *item)
Get's called when an ExtenderItem that was previously hovering over this extender moves away from thi...
Definition: extender.cpp:589
Plasma::Extender::appearance
Appearance appearance() const
Definition: extender.cpp:339
Plasma::Extender::itemHoverEnterEvent
virtual void itemHoverEnterEvent(ExtenderItem *item)
Get's called when an ExtenderItem that get's dragged enters this extender.
Definition: extender.cpp:552
Plasma::Extender::itemHoverMoveEvent
virtual void itemHoverMoveEvent(ExtenderItem *item, const QPointF &pos)
Gets called when an ExtenderItem is hovering over this extender.
Definition: extender.cpp:557
Plasma::FrameSvg
Provides an SVG with borders.
Definition: framesvg.h:77
Plasma::FrameSvg::TopBorder
@ TopBorder
Definition: framesvg.h:89
Plasma::FrameSvg::NoBorder
@ NoBorder
Definition: framesvg.h:88
Plasma::FrameSvg::BottomBorder
@ BottomBorder
Definition: framesvg.h:90
Plasma::FrameSvg::LeftBorder
@ LeftBorder
Definition: framesvg.h:91
Plasma::FrameSvg::RightBorder
@ RightBorder
Definition: framesvg.h:92
Plasma::PopupApplet
Allows applets to automatically 'collapse' into an icon when put in an panel, and is a convenient bas...
Definition: popupapplet.h:53
Plasma::PopupApplet::hidePopup
void hidePopup()
Hides the popup.
Definition: popupapplet.cpp:635
Plasma::PopupApplet::showPopup
void showPopup(uint displayTime=0)
Shows the dialog showing the widget if the applet is in a panel.
Definition: popupapplet.cpp:589
Plasma::ScrollWidget
A container of widgets that can have scrollbars.
Definition: scrollwidget.h:44
Plasma::Theme::color
Q_INVOKABLE QColor color(ColorRole role) const
Returns the text color to be used by items resting on the background.
Definition: theme.cpp:918
Plasma::Theme::defaultTheme
static Theme * defaultTheme()
Singleton pattern accessor.
Definition: theme.cpp:544
Plasma::Theme::TextColor
@ TextColor
the text color to be used by items resting on the background
Definition: theme.h:63
QGraphicsWidget
QStyleOptionGraphicsItem
QWidget
containment.h
corona.h
dialog.h
extender.h
extendergroup.h
extenderitem.h
framesvg.h
label.h
Plasma::PaintUtils::roundedRectangle
QPainterPath roundedRectangle(const QRectF &rect, qreal radius)
Returns a nicely rounded rectanglular path for painting.
Definition: paintutils.cpp:159
Plasma
Namespace for everything in libplasma.
Definition: abstractdialogmanager.cpp:25
Plasma::SizeConstraint
@ SizeConstraint
the size of the applet was changed
Definition: plasma.h:49
Plasma::Horizontal
@ Horizontal
The applet is constrained vertically, but can expand horizontally.
Definition: plasma.h:75
Plasma::Vertical
@ Vertical
The applet is constrained horizontally, but can expand vertically.
Definition: plasma.h:77
paintutils.h
popupapplet.h
scrollwidget.h
svg.h
theme.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal