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

Plasma

  • plasma
popupapplet.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 by Montel Laurent <montel@kde.org>
3  * Copyright 2008 by Marco Martin <notmart@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301 USA
19  */
20 
21 #include "popupapplet.h"
22 #include "private/popupapplet_p.h"
23 #include "private/dialog_p.h"
24 
25 #include <QApplication>
26 #include <QGraphicsProxyWidget>
27 #include <QGraphicsLinearLayout>
28 #include <QTimer>
29 #include <QVBoxLayout>
30 
31 #ifdef Q_WS_X11
32 #include <QX11Info>
33 #endif
34 
35 #include <kicon.h>
36 #include <kiconloader.h>
37 #include <kwindowsystem.h>
38 #include <kglobalsettings.h>
39 #include <netwm.h>
40 
41 #include "plasma/private/applet_p.h"
42 #include "plasma/private/extenderitemmimedata_p.h"
43 #include "plasma/corona.h"
44 #include "plasma/containment.h"
45 #include "plasma/private/containment_p.h"
46 #include "plasma/dialog.h"
47 #include "plasma/extenders/extender.h"
48 #include "plasma/extenders/extenderitem.h"
49 #include "plasma/package.h"
50 #include "plasma/theme.h"
51 #include "plasma/scripting/appletscript.h"
52 #include "plasma/tooltipmanager.h"
53 #include "plasma/widgets/iconwidget.h"
54 
55 namespace Plasma
56 {
57 
58 PopupApplet::PopupApplet(QObject *parent, const QVariantList &args)
59  : Plasma::Applet(parent, args),
60  d(new PopupAppletPrivate(this))
61 {
62 }
63 
64 PopupApplet::PopupApplet(const QString &packagePath, uint appletId, const QVariantList &args)
65  : Plasma::Applet(packagePath, appletId, args),
66  d(new PopupAppletPrivate(this))
67 {
68 }
69 
70 PopupApplet::~PopupApplet()
71 {
72  delete widget();
73  delete d;
74 }
75 
76 void PopupApplet::setPopupIcon(const QIcon &icon)
77 {
78  if (icon.isNull()) {
79  if (d->icon) {
80  delete d->icon;
81  d->icon = 0;
82  setLayout(0);
83  setAspectRatioMode(d->savedAspectRatio);
84  d->popupConstraintsEvent(FormFactorConstraint);
85  }
86 
87  return;
88  }
89 
90  d->createIconWidget();
91  d->icon->setIcon(icon);
92 }
93 
94 void PopupApplet::setPopupIcon(const QString &iconName)
95 {
96  // Attempt 1: is it in the plasmoid package?
97  if (package()) {
98  const QString file = package()->filePath("images", iconName);
99  if (!file.isEmpty()) {
100  setPopupIcon(KIcon(file));
101  return;
102  }
103  }
104 
105  // Attempt 2: is it a svg in the icons directory?
106  QString name = QString("icons/") + iconName.split("-").first();
107  if (!Plasma::Theme::defaultTheme()->imagePath(name).isEmpty()) {
108  d->createIconWidget();
109  d->icon->setSvg(name, iconName);
110  if (d->icon->svg().isEmpty()) {
111  setPopupIcon(KIcon(iconName));
112  }
113 
114  return;
115  }
116 
117  // Final Attempt: use KIcon
118  setPopupIcon(KIcon(iconName));
119 }
120 
121 QIcon PopupApplet::popupIcon() const
122 {
123  return d->icon ? d->icon->icon() : QIcon();
124 }
125 
126 QWidget *PopupApplet::widget()
127 {
128  return d->widget;
129 }
130 
131 void PopupApplet::setWidget(QWidget *widget)
132 {
133  if (d->widget) {
134  Plasma::Dialog *dialog = d->dialogPtr.data();
135  if (dialog) {
136  dialog->setGraphicsWidget(0);
137  QVBoxLayout *lay = 0;
138 
139  QLayout *existingLayout = dialog->layout();
140  if (existingLayout) {
141  lay = dynamic_cast<QVBoxLayout *>(existingLayout);
142  if (!lay) {
143  delete existingLayout;
144  }
145  }
146 
147  if (!lay) {
148  lay = new QVBoxLayout;
149  dialog->setLayout(lay);
150  }
151 
152  lay->removeWidget(d->widget);
153  lay->addWidget(widget);
154  } else if (d->proxy) {
155  d->proxy.data()->setWidget(widget);
156  }
157  }
158 
159  d->widget = widget;
160 }
161 
162 QGraphicsWidget *PopupApplet::graphicsWidget()
163 {
164  if (d->graphicsWidget) {
165  return d->graphicsWidget.data();
166  } else {
167  return static_cast<Applet*>(this)->d->extender.data();
168  }
169 }
170 
171 void PopupApplet::setGraphicsWidget(QGraphicsWidget *graphicsWidget)
172 {
173  if (d->graphicsWidget) {
174  if (d->dialogPtr) {
175  d->dialogPtr.data()->setGraphicsWidget(graphicsWidget);
176  } else if (layout()) {
177  QGraphicsLinearLayout *lay = static_cast<QGraphicsLinearLayout *>(layout());
178  lay->removeAt(0);
179  if (graphicsWidget) {
180  lay->addItem(graphicsWidget);
181  }
182  }
183  }
184 
185  d->graphicsWidget = graphicsWidget;
186 }
187 
188 void PopupAppletPrivate::checkExtenderAppearance(Plasma::FormFactor f)
189 {
190  Extender *extender = qobject_cast<Extender*>(q->graphicsWidget());
191  if (extender) {
192  if (f != Plasma::Horizontal && f != Plasma::Vertical) {
193  extender->setAppearance(Extender::NoBorders);
194  } else if (q->location() == TopEdge) {
195  extender->setAppearance(Extender::TopDownStacked);
196  } else {
197  extender->setAppearance(Extender::BottomUpStacked);
198  }
199 
200  if (dialogPtr) {
201  dialogPtr.data()->setGraphicsWidget(extender);
202  }
203  }
204 }
205 
206 void PopupAppletPrivate::popupConstraintsEvent(Plasma::Constraints constraints)
207 {
208  Plasma::FormFactor f = q->formFactor();
209 
210  if (constraints & Plasma::LocationConstraint) {
211  checkExtenderAppearance(f);
212  }
213 
214  if (constraints & Plasma::FormFactorConstraint ||
215  constraints & Plasma::StartupCompletedConstraint ||
216  (constraints & Plasma::SizeConstraint &&
217  (f == Plasma::Vertical || f == Plasma::Horizontal))) {
218  QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout *>(q->layout());
219 
220  if (icon && lay && lay->count() > 0) {
221  lay->removeAt(0);
222  }
223 
224  QSizeF minimum;
225  QSizeF parentSize;
226 
227  QGraphicsWidget *gWidget = q->graphicsWidget();
228  //kDebug() << "graphics widget is" << (QObject*)gWidget;
229  QWidget *qWidget = q->widget();
230 
231  if (gWidget) {
232  minimum = gWidget->minimumSize();
233  // our layout may have been replaced on us in the call to graphicsWidget!
234  lay = dynamic_cast<QGraphicsLinearLayout *>(q->layout());
235 
236  if (!(constraints & LocationConstraint)) {
237  checkExtenderAppearance(f);
238  }
239  } else if (qWidget) {
240  minimum = qWidget->minimumSizeHint();
241  }
242 
243  //99% of the times q->parentWidget() is the containment, but using it we can also manage the applet-in-applet case (i.e. systray)
244  //there are also cases where the parentlayoutitem is bigger than the containment (e.g. newspaper)
245  if (q->parentLayoutItem()) {
246  parentSize = q->parentLayoutItem()->geometry().size();
247  } else if (q->parentWidget()) {
248  parentSize = q->parentWidget()->size();
249  }
250 
251  //check if someone did the nasty trick of applets in applets, in this case we always want to be collapsed
252  QGraphicsWidget *candidateParentApplet = q;
253  Plasma::Applet *parentApplet = 0;
254  //this loop should be executed normally a single time, at most 2-3 times for quite complex containments
255  while (candidateParentApplet) {
256  candidateParentApplet = candidateParentApplet->parentWidget();
257  parentApplet = qobject_cast<Plasma::Applet *>(candidateParentApplet);
258  if (parentApplet) {
259  break;
260  }
261  }
262 
263  //Applet on desktop
264  if ((!parentApplet || parentApplet->isContainment() ) && icon && (!icon->svg().isEmpty() || !icon->icon().isNull()) && ((f != Plasma::Vertical && f != Plasma::Horizontal) ||
265  ((f == Plasma::Vertical && parentSize.width() >= minimum.width()) ||
266  (f == Plasma::Horizontal && parentSize.height() >= minimum.height())))) {
267  //kDebug() << "we are expanding the popupapplet";
268 
269 
270  // we only switch to expanded if we aren't horiz/vert constrained and
271  // this applet has an icon.
272  // otherwise, we leave it up to the applet itself to figure it out
273  if (icon) {
274  icon->hide();
275  }
276 
277  if (savedAspectRatio != Plasma::InvalidAspectRatioMode) {
278  q->setAspectRatioMode(savedAspectRatio);
279  }
280 
281  Dialog *dialog = dialogPtr.data();
282  if (dialog) {
283  if (dialog->layout() && qWidget) {
284  //we don't want to delete Widget inside the dialog layout
285  dialog->layout()->removeWidget(qWidget);
286  }
287 
288  if (qWidget) {
289  qWidget->setParent(0);
290  }
291 
292  delete dialog;
293  }
294 
295  if (!lay) {
296  lay = new QGraphicsLinearLayout();
297  lay->setContentsMargins(0, 0, 0, 0);
298  lay->setSpacing(0);
299  lay->setOrientation(Qt::Horizontal);
300  q->setLayout(lay);
301  }
302 
303  QSize prefSize;
304 
305  if (gWidget) {
306  if (proxy) {
307  proxy.data()->setWidget(0);
308  delete proxy.data();
309  }
310 
311  Corona *corona = qobject_cast<Corona *>(gWidget->scene());
312 
313  if (corona) {
314  corona->removeOffscreenWidget(gWidget);
315  }
316 
317  lay->addItem(gWidget);
318  prefSize = gWidget->preferredSize().toSize();
319  } else if (qWidget) {
320  if (!proxy) {
321  proxy = new QGraphicsProxyWidget(q);
322  proxy.data()->setWidget(qWidget);
323  proxy.data()->show();
324  }
325 
326  lay->addItem(proxy.data());
327  prefSize = qWidget->sizeHint();
328  }
329 
330  //we could be on a big panel, but in that case we will be able to resize
331  //more than the natural minimum size, because we'll transform into an icon
332  if (f == Plasma::Horizontal) {
333  minimum.setHeight(0);
334  } else if (f == Plasma::Vertical) {
335  minimum.setWidth(0);
336  }
337 
338  qreal left, top, right, bottom;
339  q->getContentsMargins(&left, &top, &right, &bottom);
340  QSizeF oldSize(q->size());
341 
342  //size not saved/invalid size saved
343  if (oldSize.width() < q->minimumSize().width() || oldSize.height() < q->minimumSize().height()) {
344  q->resize(prefSize);
345  emit q->appletTransformedItself();
346  }
347  } else {
348  //Applet on popup
349  if (icon && lay) {
350  lay->addItem(icon);
351  }
352 
353  //kDebug() << "about to switch to a popup";
354  if (!qWidget && !gWidget) {
355  delete dialogPtr.data();
356  return;
357  }
358 
359  //there was already a dialog? don't make the switch again
360  if (dialogPtr) {
361  return;
362  }
363 
364  if (proxy) {
365  proxy.data()->setWidget(0); // prevent it from deleting our widget!
366  delete proxy.data();
367  }
368 
369  //save the aspect ratio mode in case we drag'n drop in the Desktop later
370  savedAspectRatio = q->aspectRatioMode();
371 
372  if (icon) {
373  icon->show();
374  q->setAspectRatioMode(Plasma::ConstrainedSquare);
375  }
376 
377  Dialog *dialog = new Dialog();
378  dialog->d->appletPtr = q;
379  dialogPtr = dialog;
380 
381  if (icon) {
382  dialog->setAspectRatioMode(savedAspectRatio);
383  }
384 
385  //no longer use Qt::Popup since that seems to cause a lot of problem when you drag
386  //stuff out of your Dialog (extenders). Monitor WindowDeactivate events so we can
387  //emulate the same kind of behavior as Qt::Popup (close when you click somewhere
388  //else.
389 
390  if (gWidget) {
391  Corona *corona = qobject_cast<Corona *>(gWidget->scene());
392  if (!corona) {
393  corona = qobject_cast<Corona *>(q->scene());
394  }
395 
396  if (corona) {
397  corona->addOffscreenWidget(gWidget);
398  }
399 
400  gWidget->show();
401  dialog->setGraphicsWidget(gWidget);
402  dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (gWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
403  } else if (qWidget) {
404  QVBoxLayout *l_layout = new QVBoxLayout(dialog);
405  l_layout->setSpacing(0);
406  l_layout->setMargin(0);
407  l_layout->addWidget(qWidget);
408  dialog->adjustSize();
409  dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (qWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
410  } else {
411  dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
412  }
413 
414  restoreDialogSize();
415  KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
416  dialog->installEventFilter(q);
417 
418  QObject::connect(dialog, SIGNAL(dialogResized()), q, SLOT(dialogSizeChanged()));
419  QObject::connect(dialog, SIGNAL(dialogVisible(bool)), q, SLOT(dialogStatusChanged(bool)));
420  }
421  }
422 
423  if (constraints & Plasma::PopupConstraint) {
424  updateDialogPosition();
425  }
426 
427  if (icon) {
428  // emit the size hint changing stuff for our applet as we are handling
429  // the size changings
430  emit q->sizeHintChanged(Qt::PreferredSize);
431  }
432 }
433 
434 void PopupAppletPrivate::appletActivated()
435 {
436  internalTogglePopup(true);
437 }
438 
439 QSizeF PopupApplet::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
440 {
441  if (!d->dialogPtr || which != Qt::PreferredSize) {
442  return Applet::sizeHint(which, constraint);
443  }
444 
445  switch (formFactor()) {
446  case Vertical:
447  case Horizontal: {
448  const int size = IconSize(KIconLoader::Panel);
449  return QSizeF(size, size);
450  }
451  default:
452  break;
453  }
454 
455  const int size = IconSize(KIconLoader::Desktop);
456  return QSizeF(size, size);
457 }
458 
459 void PopupApplet::mousePressEvent(QGraphicsSceneMouseEvent *event)
460 {
461  if (!d->icon && !d->popupLostFocus && event->buttons() == Qt::LeftButton) {
462  d->clicked = scenePos().toPoint();
463  event->setAccepted(true);
464  return;
465  } else {
466  d->popupLostFocus = false;
467  Applet::mousePressEvent(event);
468  }
469 }
470 
471 void PopupApplet::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
472 {
473  if (!d->icon &&
474  (d->clicked - scenePos().toPoint()).manhattanLength() < KGlobalSettings::dndEventDelay()) {
475  d->internalTogglePopup();
476  } else {
477  Applet::mouseReleaseEvent(event);
478  }
479 }
480 
481 bool PopupApplet::eventFilter(QObject *watched, QEvent *event)
482 {
483  if (!d->passive && watched == d->dialogPtr.data() && (event->type() == QEvent::WindowDeactivate)) {
484  d->popupLostFocus = true;
485  QTimer::singleShot(100, this, SLOT(clearPopupLostFocus()));
486  }
487 
488  if (watched == d->dialogPtr.data() && event->type() == QEvent::ContextMenu) {
489  //pass it up to the applet
490  //well, actually we have to pass it to the *containment*
491  //because all the code for showing an applet's contextmenu is actually in Containment.
492  Containment *c = containment();
493  if (c) {
494  Applet *applet = this;
495  Dialog *dialog = d->dialogPtr.data();
496  if (dialog && dialog->graphicsWidget()) {
497  int left, top, right, bottom;
498  dialog->getContentsMargins(&left, &top, &right, &bottom);
499  const QPoint eventPos = static_cast<QContextMenuEvent*>(event)->pos() - QPoint(left, top);
500  QPointF pos = dialog->graphicsWidget()->mapToScene(eventPos);
501 
502  if (Applet *actual = c->d->appletAt(pos)) {
503  applet = actual;
504  }
505  }
506 
507  KMenu desktopMenu;
508  c->d->addAppletActions(desktopMenu, applet, event);
509 
510  if (!desktopMenu.isEmpty()) {
511  desktopMenu.exec(static_cast<QContextMenuEvent*>(event)->globalPos());
512  return true;
513  }
514 
515  return false;
516  }
517  }
518 
519  return Applet::eventFilter(watched, event);
520 }
521 
522 //FIXME: some duplication between the drag events... maybe add some simple helper function?
523 void PopupApplet::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
524 {
525  if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
526  const ExtenderItemMimeData *mimeData =
527  qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
528  if (mimeData && qobject_cast<Extender*>(graphicsWidget())) {
529  event->accept();
530  showPopup();
531  }
532  }
533 }
534 
535 void PopupApplet::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
536 {
537  if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
538  const ExtenderItemMimeData *mimeData =
539  qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
540  if (mimeData && qobject_cast<Extender*>(graphicsWidget())) {
541  //We want to hide the popup if we're not moving onto the popup AND it is not the popup
542  //we started.
543  if (d->dialogPtr && !d->dialogPtr.data()->geometry().contains(event->screenPos()) &&
544  mimeData->extenderItem()->extender() != qobject_cast<Extender*>(graphicsWidget())) {
545  //We actually try to hide the popup, with a call to showPopup, with a smal timeout,
546  //so if the user moves into the popup fast enough, it remains open (the extender
547  //will call showPopup which will cancel the timeout.
548  showPopup(250);
549  }
550  }
551  }
552 }
553 
554 void PopupApplet::dropEvent(QGraphicsSceneDragDropEvent *event)
555 {
556  if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
557  const ExtenderItemMimeData *mimeData =
558  qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
559  if (mimeData && qobject_cast<Extender*>(graphicsWidget())) {
560  mimeData->extenderItem()->setExtender(extender());
561  QApplication::restoreOverrideCursor();
562  }
563  }
564 }
565 
566 void PopupApplet::showPopup(uint popupDuration)
567 {
568  // use autohideTimer to store when the next show should be
569  if (popupDuration > 0 || d->autohideTimer) {
570  if (!d->autohideTimer) {
571  d->autohideTimer = new QTimer(this);
572  d->autohideTimer->setSingleShot(true);
573  connect(d->autohideTimer, SIGNAL(timeout()), this, SLOT(hideTimedPopup()));
574  }
575 
576  d->autohideTimer->stop();
577  d->autohideTimer->setInterval(popupDuration);
578  }
579 
580  //kDebug() << "starting delayed show, duration for popup is" << popupDuration;
581  d->delayedShowTimer.start(0, this);
582 }
583 
584 void PopupApplet::timerEvent(QTimerEvent *event)
585 {
586  if (event->timerId() == d->delayedShowTimer.timerId()) {
587  d->delayedShowTimer.stop();
588  Dialog *dialog = d->dialogPtr.data();
589  if (dialog) {
590  // move the popup before its fist show, even if the show isn't triggered by
591  // a click, this should fix the first random position seen in some widgets
592  if (!dialog->isVisible()) {
593  d->internalTogglePopup();
594  }
595 
596  const int popupDuration = d->autohideTimer ? d->autohideTimer->interval() : 0;
597  //kDebug() << "popupDuration is:" << (d->autohideTimer ? d->autohideTimer->interval() : 0);
598  if (popupDuration > 0) {
599  d->autohideTimer->start();
600  } else if (d->autohideTimer) {
601  d->autohideTimer->stop();
602  }
603  }
604  } else if (event->timerId() == d->showDialogTimer.timerId()) {
605  d->showDialogTimer.stop();
606  d->showDialog();
607  } else {
608  Applet::timerEvent(event);
609  }
610 }
611 
612 void PopupApplet::hidePopup()
613 {
614  d->showDialogTimer.stop();
615  d->delayedShowTimer.stop();
616 
617  Dialog *dialog = d->dialogPtr.data();
618  if (dialog && dialog->isVisible()) {
619  if (location() != Floating) {
620  dialog->animatedHide(locationToInverseDirection(location()));
621  } else {
622  dialog->hide();
623  }
624  }
625 }
626 
627 void PopupApplet::togglePopup()
628 {
629  d->internalTogglePopup();
630 }
631 
632 Plasma::PopupPlacement PopupApplet::popupPlacement() const
633 {
634  return d->popupPlacement;
635 }
636 
637 void PopupApplet::setPopupAlignment(Qt::AlignmentFlag alignment)
638 {
639  d->popupAlignment = alignment;
640 }
641 
642 Qt::AlignmentFlag PopupApplet::popupAlignment() const
643 {
644  return d->popupAlignment;
645 }
646 
647 void PopupApplet::popupEvent(bool popped)
648 {
649  if (Applet::d->script) {
650  emit Applet::d->script->popupEvent(popped);
651  }
652 }
653 
654 void PopupApplet::setPassivePopup(bool passive)
655 {
656  d->passive = passive;
657 }
658 
659 bool PopupApplet::isPassivePopup() const
660 {
661  return d->passive;
662 }
663 
664 bool PopupApplet::isPopupShowing() const
665 {
666  return d->dialogPtr && d->dialogPtr.data()->isVisible();
667 }
668 
669 bool PopupApplet::isIconified() const
670 {
671  return d->dialogPtr;
672 }
673 
674 PopupAppletPrivate::PopupAppletPrivate(PopupApplet *applet)
675  : q(applet),
676  icon(0),
677  widget(0),
678  popupPlacement(Plasma::FloatingPopup),
679  popupAlignment(Qt::AlignLeft),
680  savedAspectRatio(Plasma::InvalidAspectRatioMode),
681  autohideTimer(0),
682  preShowStatus(UnknownStatus),
683  popupLostFocus(false),
684  passive(false)
685 {
686  int iconSize = IconSize(KIconLoader::Desktop);
687  q->resize(iconSize, iconSize);
688  q->setAcceptDrops(true);
689  QObject::disconnect(q, SIGNAL(activate()), static_cast<Applet*>(q), SLOT(setFocus()));
690  QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
691  QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconSizeChanged(int)));
692 }
693 
694 PopupAppletPrivate::~PopupAppletPrivate()
695 {
696  if (proxy) {
697  proxy.data()->setWidget(0);
698  }
699 
700  delete dialogPtr.data();
701  delete icon;
702 }
703 
704 void PopupAppletPrivate::iconSizeChanged(int group)
705 {
706  if (icon && (group == KIconLoader::Desktop || group == KIconLoader::Panel)) {
707  q->updateGeometry();
708  }
709 }
710 
711 void PopupAppletPrivate::internalTogglePopup(bool fromActivatedSignal)
712 {
713  if (autohideTimer) {
714  autohideTimer->stop();
715  }
716 
717  delayedShowTimer.stop();
718 
719  Plasma::Dialog *dialog = dialogPtr.data();
720  if (!dialog) {
721  q->setFocus(Qt::ShortcutFocusReason);
722  if (!fromActivatedSignal) {
723  QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
724  emit q->activate();
725  QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
726  }
727  return;
728  }
729 
730  if (!q->view()) {
731  return;
732  }
733 
734  if (dialog->isVisible()) {
735  if (q->location() != Floating) {
736  dialog->animatedHide(locationToInverseDirection(q->location()));
737  } else {
738  dialog->hide();
739  }
740 
741  dialog->clearFocus();
742  } else {
743  if (q->graphicsWidget() &&
744  q->graphicsWidget() == static_cast<Applet*>(q)->d->extender.data() &&
745  static_cast<Applet*>(q)->d->extender.data()->isEmpty()) {
746  // we have nothing to show, so let's not.
747  if (!fromActivatedSignal) {
748  QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
749  emit q->activate();
750  QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
751  }
752  return;
753  }
754 
755  ToolTipManager::self()->hide(q);
756  showDialogTimer.start(0, q);
757  }
758 }
759 
760 void PopupAppletPrivate::showDialog()
761 {
762  Plasma::Dialog *dialog = dialogPtr.data();
763  if (!dialog) {
764  return;
765  }
766 
767  updateDialogPosition();
768 
769  KWindowSystem::setOnAllDesktops(dialog->winId(), true);
770  KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
771 
772  if (icon) {
773  dialog->setAspectRatioMode(savedAspectRatio);
774  }
775 
776  if (q->location() != Floating) {
777  dialog->animatedShow(locationToDirection(q->location()));
778  } else {
779  dialog->show();
780  }
781 
782  if (!(dialog->windowFlags() & Qt::X11BypassWindowManagerHint)) {
783  KWindowSystem::activateWindow(dialog->winId());
784  }
785 }
786 
787 void PopupAppletPrivate::hideTimedPopup()
788 {
789  autohideTimer->stop();
790  q->hidePopup();
791 }
792 
793 void PopupAppletPrivate::clearPopupLostFocus()
794 {
795  if (!icon || !icon->isDown()) {
796  q->hidePopup();
797  }
798 
799  popupLostFocus = false;
800 }
801 
802 KConfigGroup PopupAppletPrivate::popupConfigGroup()
803 {
804  KConfigGroup *mainGroup = static_cast<Applet*>(q)->d->mainConfigGroup();
805  return KConfigGroup(mainGroup, "PopupApplet");
806 }
807 
808 void PopupAppletPrivate::dialogSizeChanged()
809 {
810  //Reposition the dialog
811  Plasma::Dialog *dialog = dialogPtr.data();
812  if (dialog) {
813  KConfigGroup sizeGroup = popupConfigGroup();
814  sizeGroup.writeEntry("DialogHeight", dialog->height());
815  sizeGroup.writeEntry("DialogWidth", dialog->width());
816 
817  updateDialogPosition(!dialog->isUserResizing());
818 
819  emit q->configNeedsSaving();
820  emit q->appletTransformedByUser();
821  }
822 }
823 
824 void PopupAppletPrivate::dialogStatusChanged(bool shown)
825 {
826  if (shown) {
827  preShowStatus = q->status();
828  q->setStatus(NeedsAttentionStatus);
829  QObject::connect(q, SIGNAL(newStatus(Plasma::ItemStatus)),
830  q, SLOT(statusChangeWhileShown(Plasma::ItemStatus)),
831  Qt::UniqueConnection);
832  } else {
833  QObject::disconnect(q, SIGNAL(newStatus(Plasma::ItemStatus)),
834  q, SLOT(statusChangeWhileShown(Plasma::ItemStatus)));
835  q->setStatus(preShowStatus);
836  }
837 
838  q->popupEvent(shown);
839 }
840 
841 void PopupAppletPrivate::statusChangeWhileShown(Plasma::ItemStatus status)
842 {
843  preShowStatus = status;
844 }
845 
846 void PopupAppletPrivate::createIconWidget()
847 {
848  if (icon) {
849  return;
850  }
851 
852  icon = new Plasma::IconWidget(q);
853  QObject::connect(icon, SIGNAL(clicked()), q, SLOT(internalTogglePopup()));
854 
855  QGraphicsLinearLayout *layout = new QGraphicsLinearLayout();
856  layout->setContentsMargins(0, 0, 0, 0);
857  layout->setSpacing(0);
858  layout->setOrientation(Qt::Horizontal);
859  layout->addItem(icon);
860  layout->setAlignment(icon, Qt::AlignCenter);
861  q->setLayout(layout);
862 }
863 
864 void PopupAppletPrivate::restoreDialogSize()
865 {
866  Plasma::Dialog *dialog = dialogPtr.data();
867  if (!dialog) {
868  return;
869  }
870 
871  Corona *corona = qobject_cast<Corona *>(q->scene());
872  if (!corona) {
873  return;
874  }
875 
876  KConfigGroup sizeGroup = popupConfigGroup();
877 
878  int preferredWidth = 0;
879  int preferredHeight = 0;
880  QGraphicsWidget *gWidget = dialog->graphicsWidget();
881  if (gWidget) {
882  preferredWidth = gWidget->preferredSize().width();
883  preferredHeight = gWidget->preferredSize().height();
884  }
885 
886  const int width = qMin(sizeGroup.readEntry("DialogWidth", preferredWidth),
887  corona->screenGeometry(-1).width() - 50);
888  const int height = qMin(sizeGroup.readEntry("DialogHeight", preferredHeight),
889  corona->screenGeometry(-1).height() - 50);
890 
891  QSize saved(width, height);
892 
893  if (saved.isNull()) {
894  saved = dialog->sizeHint();
895  } else {
896  saved = saved.expandedTo(dialog->minimumSizeHint());
897  }
898 
899  if (saved.width() != dialog->width() || saved.height() != dialog->height()) {
900  dialog->resize(saved);
901  /*if (gWidget) {
902  gWidget->resize(saved);
903  }*/
904  }
905 }
906 
907 void PopupAppletPrivate::updateDialogPosition(bool move)
908 {
909  Plasma::Dialog *dialog = dialogPtr.data();
910  if (!dialog) {
911  return;
912  }
913 
914  Corona *corona = qobject_cast<Corona *>(q->scene());
915  if (!corona) {
916  return;
917  }
918 
919  QGraphicsView *view = q->view();
920  if (!view) {
921  return;
922  }
923 
924  const QPoint appletPos = view->mapToGlobal(view->mapFromScene(q->scenePos()));
925 
926  QPoint dialogPos = dialog->pos();
927  if (move) {
928  if (!q->containment() || view == q->containment()->view()) {
929  dialogPos = corona->popupPosition(q, dialog->size(), popupAlignment);
930  } else {
931  dialogPos = corona->popupPosition(q->parentItem(), dialog->size(), popupAlignment);
932  }
933  }
934 
935  bool reverse = false;
936  if (q->formFactor() == Plasma::Vertical) {
937  reverse = (appletPos.y() + (q->size().height() / 2)) < (dialogPos.y() + (dialog->size().height() / 2));
938  dialog->setMinimumResizeLimits(-1, appletPos.y(), -1, appletPos.y() + q->size().height());
939  } else {
940  reverse = (appletPos.x() + (q->size().width() / 2)) < (dialogPos.x() + (dialog->size().width() / 2));
941  dialog->setMinimumResizeLimits(appletPos.x(), -1, appletPos.x() + q->size().width(), -1);
942  }
943 
944  Dialog::ResizeCorners resizeCorners = Dialog::NoCorner;
945  switch (q->location()) {
946  case BottomEdge:
947  resizeCorners = Dialog::NorthEast | Dialog::NorthWest;
948  popupPlacement = reverse ? TopPosedLeftAlignedPopup : TopPosedRightAlignedPopup;
949  break;
950  case TopEdge:
951  resizeCorners = Dialog::SouthEast | Dialog::SouthWest;
952  popupPlacement = reverse ? Plasma::BottomPosedLeftAlignedPopup : Plasma::BottomPosedRightAlignedPopup;
953  break;
954  case LeftEdge:
955  resizeCorners = Dialog::SouthEast | Dialog::NorthEast;
956  popupPlacement = reverse ? RightPosedTopAlignedPopup : RightPosedBottomAlignedPopup;
957  break;
958 
959  case RightEdge:
960  resizeCorners = Dialog::SouthWest | Dialog::NorthWest;
961  popupPlacement = reverse ? LeftPosedTopAlignedPopup : LeftPosedBottomAlignedPopup;
962  break;
963 
964  default:
965  popupPlacement = FloatingPopup;
966  resizeCorners = Dialog::All;
967  break;
968  }
969 
970  dialog->setResizeHandleCorners(resizeCorners);
971  if (move) {
972  dialog->move(dialogPos);
973  }
974 }
975 
976 } // Plasma namespace
977 
978 #include "popupapplet.moc"
979 
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Nov 16 2012 14:55:56 by doxygen 1.8.1 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.8.5 API Reference

Skip menu "kdelibs-4.8.5 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