22#include "private/popupapplet_p.h"
23#include "private/dialog_p.h"
25#include <QApplication>
26#include <QGraphicsProxyWidget>
27#include <QGraphicsLinearLayout>
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"
59PopupApplet::PopupApplet(
QObject *parent,
const QVariantList &args)
61 d(new PopupAppletPrivate(this))
65PopupApplet::PopupApplet(
const QString &packagePath, uint appletId,
const QVariantList &args)
67 d(new PopupAppletPrivate(this))
71PopupApplet::~PopupApplet()
77void PopupApplet::setPopupIcon(
const QIcon &icon)
91 d->createIconWidget();
92 d->icon->setIcon(
icon);
95void PopupApplet::setPopupIcon(
const QString &iconName)
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()) {
122QIcon PopupApplet::popupIcon()
const
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);
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) {
177 }
else if (layout()) {
178 QGraphicsLinearLayout *lay =
static_cast<QGraphicsLinearLayout *
>(layout());
191 Extender *extender = qobject_cast<Extender*>(q->graphicsWidget());
195 }
else if (q->location() == TopEdge) {
202 dialogPtr.data()->setGraphicsWidget(extender);
207void 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());
237 if (!(constraints & LocationConstraint)) {
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()))))) {
301 q->setAspectRatioMode(savedAspectRatio);
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);
322 lay->setOrientation(Qt::Horizontal);
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);
457void PopupAppletPrivate::appletActivated()
459 internalTogglePopup(
true);
462QSizeF PopupApplet::sizeHint(Qt::SizeHint which,
const QSizeF & constraint)
const
464 if (!d->dialogPtr || which != Qt::PreferredSize) {
471 const int size = IconSize(KIconLoader::Panel);
472 return QSizeF(size, size);
478 const int size = IconSize(KIconLoader::Desktop);
479 return QSizeF(size, size);
482void PopupApplet::mousePressEvent(QGraphicsSceneMouseEvent *event)
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);
494void PopupApplet::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
497 (d->clicked - scenePos().toPoint()).manhattanLength() < KGlobalSettings::dndEventDelay()) {
498 d->internalTogglePopup();
500 Applet::mouseReleaseEvent(event);
504bool PopupApplet::eventFilter(
QObject *watched, QEvent *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());
546void PopupApplet::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
548 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
549 const ExtenderItemMimeData *mimeData =
550 qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
558void PopupApplet::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
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()) &&
567 mimeData->extenderItem()->extender() != qobject_cast<Extender*>(
graphicsWidget())) {
577void PopupApplet::dropEvent(QGraphicsSceneDragDropEvent *event)
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();
589void PopupApplet::showPopup(uint popupDuration)
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);
607void PopupApplet::timerEvent(QTimerEvent *event)
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();
635void PopupApplet::hidePopup()
637 d->showDialogTimer.stop();
638 d->delayedShowTimer.stop();
640 Dialog *dialog = d->dialogPtr.data();
641 if (dialog && dialog->isVisible()) {
650void PopupApplet::togglePopup()
652 d->internalTogglePopup();
657 return d->popupPlacement;
660void PopupApplet::setPopupAlignment(Qt::AlignmentFlag alignment)
662 d->popupAlignment = alignment;
665Qt::AlignmentFlag PopupApplet::popupAlignment()
const
667 return d->popupAlignment;
670void PopupApplet::popupEvent(
bool popped)
672 if (Applet::d->script) {
673 emit Applet::d->script->popupEvent(popped);
677void PopupApplet::setPassivePopup(
bool passive)
679 d->passive = passive;
682bool PopupApplet::isPassivePopup()
const
687bool PopupApplet::isPopupShowing()
const
689 return d->dialogPtr && d->dialogPtr.data()->isVisible();
692bool PopupApplet::isIconified()
const
697PopupAppletPrivate::PopupAppletPrivate(
PopupApplet *applet)
702 popupAlignment(Qt::AlignLeft),
706 popupLostFocus(false),
709 int iconSize = IconSize(KIconLoader::Desktop);
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)));
717PopupAppletPrivate::~PopupAppletPrivate()
720 proxy.data()->setWidget(0);
723 delete dialogPtr.data();
727void PopupAppletPrivate::iconSizeChanged(
int group)
729 if (icon && (group == KIconLoader::Desktop || group == KIconLoader::Panel)) {
734void 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()) {
758 if (q->location() != Floating) {
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()));
778 ToolTipManager::self()->hide(q);
779 showDialogTimer.start(0, q);
783void PopupAppletPrivate::showDialog()
790 updateDialogPosition();
792 KWindowSystem::setOnAllDesktops(dialog->winId(),
true);
793 KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
799 if (q->location() != Floating) {
805 if (!(dialog->windowFlags() & Qt::X11BypassWindowManagerHint)) {
806 KWindowSystem::activateWindow(dialog->winId());
810void PopupAppletPrivate::hideTimedPopup()
812 autohideTimer->stop();
816void PopupAppletPrivate::clearPopupLostFocus()
818 if (!icon || !icon->isDown()) {
822 popupLostFocus =
false;
825KConfigGroup PopupAppletPrivate::popupConfigGroup()
827 KConfigGroup *mainGroup =
static_cast<Applet*
>(q)->d->mainConfigGroup();
828 return KConfigGroup(mainGroup,
"PopupApplet");
831void 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();
847void PopupAppletPrivate::dialogStatusChanged(
bool shown)
850 preShowStatus = q->status();
851 q->setStatus(NeedsAttentionStatus);
854 Qt::UniqueConnection);
858 q->setStatus(preShowStatus);
861 q->popupEvent(shown);
866 preShowStatus = status;
869void 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);
881 layout->setOrientation(Qt::Horizontal);
882 layout->addItem(icon);
883 layout->setAlignment(icon, Qt::AlignCenter);
884 q->setLayout(layout);
887void 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);
930void 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));
967 Dialog::ResizeCorners resizeCorners = Dialog::NoCorner;
968 switch (q->location()) {
970 resizeCorners = Dialog::NorthEast | Dialog::NorthWest;
974 resizeCorners = Dialog::SouthEast | Dialog::SouthWest;
978 resizeCorners = Dialog::SouthEast | Dialog::NorthEast;
983 resizeCorners = Dialog::SouthWest | Dialog::NorthWest;
989 resizeCorners = Dialog::All;
995 dialog->move(dialogPos);
1001#include "popupapplet.moc"
void timerEvent(QTimerEvent *event)
Reimplemented from QObject.
virtual FormFactor formFactor() const
Returns the current form factor the applet is being displayed in.
QString icon() const
Returns the icon related to this applet.
bool eventFilter(QObject *o, QEvent *e)
Containment * containment() const
Extender * extender() const
const Package * package() const
Accessor for the associated Package object if any.
void setAspectRatioMode(Plasma::AspectRatioMode)
Sets the preferred aspect ratio mode for placement and resizing.
virtual Location location() const
Returns the location of the scene which is displaying applet.
bool isContainment() const
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint=QSizeF()) const
Reimplemented from QGraphicsLayoutItem.
void activate()
Emitted when activation is requested due to, for example, a global keyboard shortcut.
The base class for plugins that provide backgrounds and applet grouping containers.
A dialog that uses the Plasma style.
void setMinimumResizeLimits(int left, int top, int right, int bottom)
Sets the minimum values that each of four sides of the rect may expand to or from.
bool isUserResizing() const
void setResizeHandleCorners(ResizeCorners corners)
void setAspectRatioMode(Plasma::AspectRatioMode mode)
Sets the preferred aspect ratio mode for placement and resizing.
void setGraphicsWidget(QGraphicsWidget *widget)
Sets a QGraphicsWidget to be shown as the content in this dialog.
void animatedShow(Plasma::Direction direction)
Causes an animated show; requires compositing to work, otherwise the dialog will simply show.
void animatedHide(Plasma::Direction direction)
Causes an animated hide; requires compositing to work, otherwise the dialog will simply hide.
QGraphicsWidget * graphicsWidget()
Extends applets to allow detachable parts.
void setAppearance(Appearance appearance)
Use this function to instruct the extender on how to render its items.
QString filePath(const char *fileType, const QString &filename) const
Get the path to a given file.
static Theme * defaultTheme()
Singleton pattern accessor.
Namespace for everything in libplasma.
@ ConstrainedSquare
The applet is no wider (in horizontal formfactors) or no higher (in vertical ones) than a square.
@ InvalidAspectRatioMode
Unset mode used for dev convenience when there is a need to store the aspectRatioMode somewhere.
@ LeftEdge
Along the left side of the screen.
@ TopEdge
Along the top of the screen.
@ RightEdge
Along the right side of the screen.
@ BottomEdge
Along the bottom of the screen.
Direction locationToInverseDirection(Location location)
Converts a location to the direction facing it.
ItemStatus
Status of an applet.
@ UnknownStatus
The status is unknown.
Direction locationToDirection(Location location)
Converts a location to a direction.
@ PopupConstraint
the position of the popup needs to be recalculated
@ LocationConstraint
The Location of an object.
@ StartupCompletedConstraint
application startup has completed
@ FormFactorConstraint
The FormFactor for an object.
@ SizeConstraint
the size of the applet was changed
PopupPlacement
The popup position enumeration relatively to his attached widget.
@ BottomPosedRightAlignedPopup
Popup positioned on the bottom, aligned to the right of the widget.
@ LeftPosedBottomAlignedPopup
Popup positioned on the left, aligned to the bottom of the widget.
@ FloatingPopup
Free floating, non attached popup.
@ TopPosedRightAlignedPopup
Popup positioned on the top, aligned to the right of the widget.
@ RightPosedTopAlignedPopup
Popup positioned on the right, aligned to the top of the wigdet.
@ BottomPosedLeftAlignedPopup
Popup positioned on the bottom, aligned to the left of the wigdet.
@ TopPosedLeftAlignedPopup
Popup positioned on the top, aligned to the left of the wigdet.
@ LeftPosedTopAlignedPopup
Popup positioned on the left, aligned to the right of the wigdet.
@ RightPosedBottomAlignedPopup
Popup positioned on the right, aligned to the bottom of the widget.
FormFactor
The FormFactor enumeration describes how a Plasma::Applet should arrange itself.
@ Horizontal
The applet is constrained vertically, but can expand horizontally.
@ Vertical
The applet is constrained horizontally, but can expand vertically.