22 #include "private/popupapplet_p.h"
23 #include "private/dialog_p.h"
25 #include <QApplication>
26 #include <QGraphicsProxyWidget>
27 #include <QGraphicsLinearLayout>
29 #include <QVBoxLayout>
30 #include <QDeclarativeItem>
37 #include <kiconloader.h>
38 #include <kwindowsystem.h>
39 #include <kglobalsettings.h>
42 #include "plasma/private/applet_p.h"
43 #include "plasma/private/extenderitemmimedata_p.h"
46 #include "plasma/private/containment_p.h"
60 : Plasma::
Applet(parent, args),
61 d(new PopupAppletPrivate(this))
66 : Plasma::
Applet(packagePath, appletId, args),
67 d(new PopupAppletPrivate(this))
91 d->createIconWidget();
92 d->icon->setIcon(icon);
100 if (!file.isEmpty()) {
107 QString
name = QString(
"icons/") + iconName.split(
"-").first();
109 d->createIconWidget();
110 d->icon->setSvg(name, iconName);
111 if (d->icon->svg().isEmpty()) {
124 return d->icon ? d->icon->icon() : QIcon();
138 QVBoxLayout *lay = 0;
140 QLayout *existingLayout = dialog->layout();
141 if (existingLayout) {
142 lay =
dynamic_cast<QVBoxLayout *
>(existingLayout);
144 delete existingLayout;
149 lay =
new QVBoxLayout;
150 dialog->setLayout(lay);
153 lay->removeWidget(d->widget);
154 lay->addWidget(widget);
155 }
else if (d->proxy) {
156 d->proxy.data()->setWidget(widget);
165 if (d->graphicsWidget) {
166 return d->graphicsWidget.data();
168 return static_cast<Applet*
>(
this)->d->extender.data();
174 if (d->graphicsWidget) {
176 d->dialogPtr.data()->setGraphicsWidget(graphicsWidget);
177 }
else if (layout()) {
178 QGraphicsLinearLayout *lay =
static_cast<QGraphicsLinearLayout *
>(layout());
180 if (graphicsWidget) {
181 lay->addItem(graphicsWidget);
195 }
else if (q->location() ==
TopEdge) {
202 dialogPtr.data()->setGraphicsWidget(extender);
207 void PopupAppletPrivate::popupConstraintsEvent(Plasma::Constraints constraints)
212 checkExtenderAppearance(f);
219 QGraphicsLinearLayout *lay =
dynamic_cast<QGraphicsLinearLayout *
>(q->layout());
221 if (icon && lay && lay->count() > 0) {
230 QWidget *qWidget = q->widget();
233 minimum = gWidget->minimumSize();
235 lay =
dynamic_cast<QGraphicsLinearLayout *
>(q->layout());
238 checkExtenderAppearance(f);
240 }
else if (qWidget) {
241 minimum = qWidget->minimumSizeHint();
246 QDeclarativeItem *di = qobject_cast<QDeclarativeItem *>(q->parentObject());
247 if (q->parentLayoutItem()) {
248 parentSize = q->parentLayoutItem()->geometry().size();
249 }
else if (q->parentWidget()) {
250 parentSize = q->parentWidget()->size();
252 parentSize = QSizeF(di->width(), di->height());
259 while (candidateParentApplet) {
260 candidateParentApplet = candidateParentApplet->parentWidget();
261 parentApplet = qobject_cast<
Plasma::Applet *>(candidateParentApplet);
270 if ((gWidget && gWidget->size().height() > q->size().height() / 2) ||
271 (qWidget && qWidget->size().height() > q->size().height() / 2)) {
272 popupAlignment = Qt::AlignCenter;
274 popupAlignment = Qt::AlignLeft;
277 if ((gWidget && gWidget->size().width() > q->size().width() / 2) ||
278 (qWidget && qWidget->size().width() > q->size().width() / 2)) {
279 popupAlignment = Qt::AlignCenter;
281 popupAlignment = Qt::AlignLeft;
289 (!q->parentWidget() || (q->parentWidget()->size().width() >= minimum.width() && q->parentWidget()->size().height() >= minimum.height()))))) {
304 Dialog *dialog = dialogPtr.data();
306 if (dialog->layout() && qWidget) {
308 dialog->layout()->removeWidget(qWidget);
312 qWidget->setParent(0);
319 lay =
new QGraphicsLinearLayout();
320 lay->setContentsMargins(0, 0, 0, 0);
330 proxy.data()->setWidget(0);
334 Corona *corona = qobject_cast<Corona *>(gWidget->scene());
337 corona->removeOffscreenWidget(gWidget);
340 lay->addItem(gWidget);
341 prefSize = gWidget->preferredSize().toSize();
342 }
else if (qWidget) {
345 proxy.data()->setWidget(qWidget);
346 proxy.data()->show();
349 lay->addItem(proxy.data());
350 prefSize = qWidget->sizeHint();
356 minimum.setHeight(0);
361 qreal left, top, right, bottom;
362 q->getContentsMargins(&left, &top, &right, &bottom);
363 QSizeF oldSize(q->size());
366 if (oldSize.width() < q->minimumSize().width() || oldSize.height() < q->minimumSize().height()) {
368 emit q->appletTransformedItself();
377 if (!qWidget && !gWidget) {
378 delete dialogPtr.data();
388 proxy.data()->setWidget(0);
393 savedAspectRatio = q->aspectRatioMode();
400 Dialog *dialog =
new Dialog();
401 dialog->d->appletPtr = q;
405 dialog->setAspectRatioMode(savedAspectRatio);
414 Corona *corona = qobject_cast<Corona *>(gWidget->scene());
416 corona = qobject_cast<Corona *>(q->scene());
420 corona->addOffscreenWidget(gWidget);
424 dialog->setGraphicsWidget(gWidget);
425 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (gWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
426 }
else if (qWidget) {
427 QVBoxLayout *l_layout =
new QVBoxLayout(dialog);
428 l_layout->setSpacing(0);
429 l_layout->setMargin(0);
430 l_layout->addWidget(qWidget);
431 dialog->adjustSize();
432 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (qWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
434 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
438 KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
439 dialog->installEventFilter(q);
441 QObject::connect(dialog, SIGNAL(dialogResized()), q, SLOT(dialogSizeChanged()));
442 QObject::connect(dialog, SIGNAL(dialogVisible(
bool)), q, SLOT(dialogStatusChanged(
bool)));
447 updateDialogPosition();
453 emit q->sizeHintChanged(Qt::PreferredSize);
457 void PopupAppletPrivate::appletActivated()
459 internalTogglePopup(
true);
464 if (!d->dialogPtr || which != Qt::PreferredSize) {
471 const int size = IconSize(KIconLoader::Panel);
472 return QSizeF(size, size);
479 return QSizeF(size, size);
484 if (!d->icon && !d->popupLostFocus && event->buttons() == Qt::LeftButton) {
485 d->clicked = scenePos().toPoint();
486 event->setAccepted(
true);
489 d->popupLostFocus =
false;
490 Applet::mousePressEvent(event);
497 (d->clicked - scenePos().toPoint()).manhattanLength() < KGlobalSettings::dndEventDelay()) {
498 d->internalTogglePopup();
500 Applet::mouseReleaseEvent(event);
506 if (!d->passive && watched == d->dialogPtr.data() && (
event->type() == QEvent::WindowDeactivate)) {
507 d->popupLostFocus =
true;
508 QTimer::singleShot(100,
this, SLOT(clearPopupLostFocus()));
511 if (watched == d->dialogPtr.data() &&
event->type() == QEvent::ContextMenu) {
518 Dialog *dialog = d->dialogPtr.data();
520 int left, top, right, bottom;
521 dialog->getContentsMargins(&left, &top, &right, &bottom);
522 const QPoint eventPos =
static_cast<QContextMenuEvent*
>(event)->pos() - QPoint(left, top);
525 if (
Applet *actual = c->d->appletAt(pos)) {
531 c->d->addAppletActions(desktopMenu, applet, event);
533 if (!desktopMenu.isEmpty()) {
534 desktopMenu.exec(static_cast<QContextMenuEvent*>(event)->globalPos());
548 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
549 const ExtenderItemMimeData *mimeData =
550 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
560 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
561 const ExtenderItemMimeData *mimeData =
562 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
566 if (d->dialogPtr && !d->dialogPtr.data()->geometry().contains(event->screenPos()) &&
579 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
580 const ExtenderItemMimeData *mimeData =
581 qobject_cast<
const ExtenderItemMimeData*>(
event->mimeData());
583 mimeData->extenderItem()->setExtender(
extender());
584 QApplication::restoreOverrideCursor();
592 if (popupDuration > 0 || d->autohideTimer) {
593 if (!d->autohideTimer) {
594 d->autohideTimer =
new QTimer(
this);
595 d->autohideTimer->setSingleShot(
true);
596 connect(d->autohideTimer, SIGNAL(timeout()),
this, SLOT(hideTimedPopup()));
599 d->autohideTimer->stop();
600 d->autohideTimer->setInterval(popupDuration);
604 d->delayedShowTimer.start(0,
this);
609 if (event->timerId() == d->delayedShowTimer.timerId()) {
610 d->delayedShowTimer.stop();
611 Dialog *dialog = d->dialogPtr.data();
615 if (!dialog->isVisible()) {
616 d->internalTogglePopup();
619 const int popupDuration = d->autohideTimer ? d->autohideTimer->interval() : 0;
621 if (popupDuration > 0) {
622 d->autohideTimer->start();
623 }
else if (d->autohideTimer) {
624 d->autohideTimer->stop();
627 }
else if (event->timerId() == d->showDialogTimer.timerId()) {
628 d->showDialogTimer.stop();
637 d->showDialogTimer.stop();
638 d->delayedShowTimer.stop();
640 Dialog *dialog = d->dialogPtr.data();
641 if (dialog && dialog->isVisible()) {
652 d->internalTogglePopup();
657 return d->popupPlacement;
662 d->popupAlignment = alignment;
667 return d->popupAlignment;
672 if (Applet::d->script) {
673 emit Applet::d->script->popupEvent(popped);
679 d->passive = passive;
689 return d->dialogPtr && d->dialogPtr.data()->isVisible();
697 PopupAppletPrivate::PopupAppletPrivate(
PopupApplet *applet)
702 popupAlignment(Qt::AlignLeft),
706 popupLostFocus(false),
710 q->resize(iconSize, iconSize);
711 q->setAcceptDrops(
true);
712 QObject::disconnect(q, SIGNAL(
activate()), static_cast<Applet*>(q), SLOT(setFocus()));
713 QObject::connect(q, SIGNAL(
activate()), q, SLOT(appletActivated()));
714 QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(
int)), q, SLOT(iconSizeChanged(
int)));
717 PopupAppletPrivate::~PopupAppletPrivate()
720 proxy.data()->setWidget(0);
723 delete dialogPtr.data();
727 void PopupAppletPrivate::iconSizeChanged(
int group)
734 void PopupAppletPrivate::internalTogglePopup(
bool fromActivatedSignal)
737 autohideTimer->stop();
740 delayedShowTimer.stop();
744 q->setFocus(Qt::ShortcutFocusReason);
745 if (!fromActivatedSignal) {
746 QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
748 QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
757 if (dialog->isVisible()) {
764 dialog->clearFocus();
766 if (q->graphicsWidget() &&
767 q->graphicsWidget() ==
static_cast<Applet*
>(q)->d->extender.data() &&
768 static_cast<Applet*
>(q)->d->extender.data()->isEmpty()) {
770 if (!fromActivatedSignal) {
771 QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
773 QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
779 showDialogTimer.start(0, q);
783 void PopupAppletPrivate::showDialog()
790 updateDialogPosition();
792 KWindowSystem::setOnAllDesktops(dialog->winId(),
true);
793 KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
805 if (!(dialog->windowFlags() & Qt::X11BypassWindowManagerHint)) {
806 KWindowSystem::activateWindow(dialog->winId());
810 void PopupAppletPrivate::hideTimedPopup()
812 autohideTimer->stop();
816 void PopupAppletPrivate::clearPopupLostFocus()
818 if (!icon || !icon->isDown()) {
822 popupLostFocus =
false;
825 KConfigGroup PopupAppletPrivate::popupConfigGroup()
827 KConfigGroup *mainGroup =
static_cast<Applet*
>(q)->d->mainConfigGroup();
828 return KConfigGroup(mainGroup,
"PopupApplet");
831 void PopupAppletPrivate::dialogSizeChanged()
836 KConfigGroup sizeGroup = popupConfigGroup();
837 sizeGroup.writeEntry(
"DialogHeight", dialog->height());
838 sizeGroup.writeEntry(
"DialogWidth", dialog->width());
842 emit q->configNeedsSaving();
843 emit q->appletTransformedByUser();
847 void PopupAppletPrivate::dialogStatusChanged(
bool shown)
850 preShowStatus = q->status();
854 Qt::UniqueConnection);
858 q->setStatus(preShowStatus);
861 q->popupEvent(shown);
866 preShowStatus = status;
869 void PopupAppletPrivate::createIconWidget()
876 QObject::connect(icon, SIGNAL(clicked()), q, SLOT(internalTogglePopup()));
878 QGraphicsLinearLayout *layout =
new QGraphicsLinearLayout();
879 layout->setContentsMargins(0, 0, 0, 0);
880 layout->setSpacing(0);
882 layout->addItem(icon);
883 layout->setAlignment(icon, Qt::AlignCenter);
884 q->setLayout(layout);
887 void PopupAppletPrivate::restoreDialogSize()
894 Corona *corona = qobject_cast<Corona *>(q->scene());
899 KConfigGroup sizeGroup = popupConfigGroup();
901 int preferredWidth = 0;
902 int preferredHeight = 0;
905 preferredWidth = gWidget->preferredSize().width();
906 preferredHeight = gWidget->preferredSize().height();
909 const int width = qMin(sizeGroup.readEntry(
"DialogWidth", preferredWidth),
910 corona->screenGeometry(-1).width() - 50);
911 const int height = qMin(sizeGroup.readEntry(
"DialogHeight", preferredHeight),
912 corona->screenGeometry(-1).height() - 50);
914 QSize saved(width, height);
916 if (saved.isNull()) {
917 saved = dialog->sizeHint();
919 saved = saved.expandedTo(dialog->minimumSizeHint());
922 if (saved.width() != dialog->width() || saved.height() != dialog->height()) {
923 dialog->resize(saved);
930 void PopupAppletPrivate::updateDialogPosition(
bool move)
937 Corona *corona = qobject_cast<Corona *>(q->scene());
947 const QPoint appletPos = view->mapToGlobal(view->mapFromScene(q->scenePos()));
949 QPoint dialogPos = dialog->pos();
951 if (!q->containment() || view == q->containment()->view()) {
952 dialogPos = corona->popupPosition(q, dialog->size(), popupAlignment);
954 dialogPos = corona->popupPosition(q->parentItem(), dialog->size(), popupAlignment);
958 bool reverse =
false;
960 reverse = (appletPos.y() + (q->size().height() / 2)) < (dialogPos.y() + (dialog->size().height() / 2));
963 reverse = (appletPos.x() + (q->size().width() / 2)) < (dialogPos.x() + (dialog->size().width() / 2));
968 switch (q->location()) {
995 dialog->move(dialogPos);
1001 #include "popupapplet.moc"