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

Plasma

popupapplet.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2008 by Montel Laurent <montel@kde.org>
00003  * Copyright 2008 by Marco Martin <notmart@gmail.com>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2.1 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor,
00018  * Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include "popupapplet.h"
00022 #include "private/popupapplet_p.h"
00023 #include "private/dialog_p.h"
00024 
00025 #include <QApplication>
00026 #include <QGraphicsProxyWidget>
00027 #include <QGraphicsLinearLayout>
00028 #include <QTimer>
00029 #include <QVBoxLayout>
00030 
00031 #ifdef Q_WS_X11
00032 #include <QX11Info>
00033 #endif
00034 
00035 #include <kicon.h>
00036 #include <kiconloader.h>
00037 #include <kwindowsystem.h>
00038 #include <kglobalsettings.h>
00039 #include <netwm.h>
00040 
00041 #include "plasma/private/applet_p.h"
00042 #include "plasma/private/extenderitemmimedata_p.h"
00043 #include "plasma/corona.h"
00044 #include "plasma/containment.h"
00045 #include "plasma/private/containment_p.h"
00046 #include "plasma/dialog.h"
00047 #include "plasma/extenders/extender.h"
00048 #include "plasma/extenders/extenderitem.h"
00049 #include "plasma/package.h"
00050 #include "plasma/theme.h"
00051 #include "plasma/scripting/appletscript.h"
00052 #include "plasma/tooltipmanager.h"
00053 #include "plasma/widgets/iconwidget.h"
00054 
00055 namespace Plasma
00056 {
00057 
00058 PopupApplet::PopupApplet(QObject *parent, const QVariantList &args)
00059     : Plasma::Applet(parent, args),
00060       d(new PopupAppletPrivate(this))
00061 {
00062 }
00063 
00064 PopupApplet::PopupApplet(const QString &packagePath, uint appletId, const QVariantList &args)
00065     : Plasma::Applet(packagePath, appletId, args),
00066       d(new PopupAppletPrivate(this))
00067 {
00068 }
00069 
00070 PopupApplet::~PopupApplet()
00071 {
00072     delete widget();
00073     delete d;
00074 }
00075 
00076 void PopupApplet::setPopupIcon(const QIcon &icon)
00077 {
00078     if (icon.isNull()) {
00079         if (d->icon) {
00080             delete d->icon;
00081             d->icon = 0;
00082             setLayout(0);
00083             setAspectRatioMode(d->savedAspectRatio);
00084             d->popupConstraintsEvent(FormFactorConstraint);
00085         }
00086 
00087         return;
00088     }
00089 
00090     d->createIconWidget();
00091     d->icon->setIcon(icon);
00092 }
00093 
00094 void PopupApplet::setPopupIcon(const QString &iconName)
00095 {
00096     // Attempt 1: is it in the plasmoid package?
00097     if (package()) {
00098         const QString file = package()->filePath("images", iconName);
00099         if (!file.isEmpty()) {
00100             setPopupIcon(KIcon(file));
00101             return;
00102         }
00103     }
00104 
00105     // Attempt 2: is it a svg in the icons directory?
00106     QString name = QString("icons/") + iconName.split("-").first();
00107     if (!Plasma::Theme::defaultTheme()->imagePath(name).isEmpty()) {
00108         d->createIconWidget();
00109         d->icon->setSvg(name, iconName);
00110         if (d->icon->svg().isEmpty()) {
00111             setPopupIcon(KIcon(iconName));
00112         }
00113 
00114         return;
00115     }
00116 
00117     // Final Attempt: use KIcon
00118     setPopupIcon(KIcon(iconName));
00119 }
00120 
00121 QIcon PopupApplet::popupIcon() const
00122 {
00123     return d->icon ? d->icon->icon() : QIcon();
00124 }
00125 
00126 QWidget *PopupApplet::widget()
00127 {
00128     return d->widget;
00129 }
00130 
00131 void PopupApplet::setWidget(QWidget *widget)
00132 {
00133     if (d->widget) {
00134         Plasma::Dialog *dialog = d->dialogPtr.data();
00135         if (dialog) {
00136             dialog->setGraphicsWidget(0);
00137             QVBoxLayout *lay = 0;
00138 
00139             QLayout *existingLayout = dialog->layout();
00140             if (existingLayout) {
00141                 lay = dynamic_cast<QVBoxLayout *>(existingLayout);
00142                 if (!lay) {
00143                     delete existingLayout;
00144                 }
00145             }
00146 
00147             if (!lay) {
00148                 lay = new QVBoxLayout;
00149                 dialog->setLayout(lay);
00150             }
00151 
00152             lay->removeWidget(d->widget);
00153             lay->addWidget(widget);
00154         } else if (d->proxy) {
00155             d->proxy.data()->setWidget(widget);
00156         }
00157     }
00158 
00159     d->widget = widget;
00160 }
00161 
00162 QGraphicsWidget *PopupApplet::graphicsWidget()
00163 {
00164     if (d->graphicsWidget) {
00165         return d->graphicsWidget.data();
00166     } else {
00167         return static_cast<Applet*>(this)->d->extender.data();
00168     }
00169 }
00170 
00171 void PopupApplet::setGraphicsWidget(QGraphicsWidget *graphicsWidget)
00172 {
00173     if (d->graphicsWidget) {
00174         if (d->dialogPtr) {
00175             d->dialogPtr.data()->setGraphicsWidget(graphicsWidget);
00176         } else if (layout())  {
00177             QGraphicsLinearLayout *lay = static_cast<QGraphicsLinearLayout *>(layout());
00178             lay->removeAt(0);
00179             if (graphicsWidget) {
00180                 lay->addItem(graphicsWidget);
00181             }
00182         }
00183     }
00184 
00185     d->graphicsWidget = graphicsWidget;
00186 }
00187 
00188 void PopupAppletPrivate::checkExtenderAppearance(Plasma::FormFactor f)
00189 {
00190     Extender *extender = qobject_cast<Extender*>(q->graphicsWidget());
00191     if (extender) {
00192         if (f != Plasma::Horizontal && f != Plasma::Vertical) {
00193             extender->setAppearance(Extender::NoBorders);
00194         } else if (q->location() == TopEdge) {
00195             extender->setAppearance(Extender::TopDownStacked);
00196         } else {
00197             extender->setAppearance(Extender::BottomUpStacked);
00198         }
00199 
00200         if (dialogPtr) {
00201             dialogPtr.data()->setGraphicsWidget(extender);
00202         }
00203     }
00204 }
00205 
00206 void PopupAppletPrivate::popupConstraintsEvent(Plasma::Constraints constraints)
00207 {
00208     Plasma::FormFactor f = q->formFactor();
00209 
00210     if (constraints & Plasma::LocationConstraint) {
00211         checkExtenderAppearance(f);
00212     }
00213 
00214     if (constraints & Plasma::FormFactorConstraint ||
00215         constraints & Plasma::StartupCompletedConstraint ||
00216         (constraints & Plasma::SizeConstraint &&
00217          (f == Plasma::Vertical || f == Plasma::Horizontal))) {
00218         QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout *>(q->layout());
00219 
00220         if (icon && lay && lay->count() > 0) {
00221             lay->removeAt(0);
00222         }
00223 
00224         QSizeF minimum;
00225         QSizeF parentSize;
00226 
00227         QGraphicsWidget *gWidget = q->graphicsWidget();
00228         //kDebug() << "graphics widget is" << (QObject*)gWidget;
00229         QWidget *qWidget = q->widget();
00230 
00231         if (gWidget) {
00232             minimum = gWidget->minimumSize();
00233             // our layout may have been replaced on us in the call to graphicsWidget!
00234             lay = dynamic_cast<QGraphicsLinearLayout *>(q->layout());
00235 
00236             if (!(constraints & LocationConstraint)) {
00237                 checkExtenderAppearance(f);
00238             }
00239         } else if (qWidget) {
00240             minimum = qWidget->minimumSizeHint();
00241         }
00242 
00243         //99% of the times q->parentWidget() is the containment, but using it  we can also manage the applet-in-applet case (i.e. systray)
00244         //there are also cases where the parentlayoutitem is bigger than the containment (e.g. newspaper)
00245         if (q->parentLayoutItem()) {
00246             parentSize = q->parentLayoutItem()->geometry().size();
00247         } else if (q->parentWidget()) {
00248             parentSize = q->parentWidget()->size();
00249         }
00250 
00251         //check if someone did the nasty trick of applets in applets, in this case we always want to be collapsed
00252         QGraphicsWidget *candidateParentApplet = q;
00253         Plasma::Applet *parentApplet = 0;
00254         //this loop should be executed normally a single time, at most 2-3 times for quite complex containments
00255         while (candidateParentApplet) {
00256             candidateParentApplet = candidateParentApplet->parentWidget();
00257             parentApplet = qobject_cast<Plasma::Applet *>(candidateParentApplet);
00258             if (parentApplet) {
00259                 break;
00260             }
00261         }
00262 
00263         //Applet on desktop
00264         if ((!parentApplet || parentApplet->isContainment() ) && icon && (!icon->svg().isEmpty() || !icon->icon().isNull()) && ((f != Plasma::Vertical && f != Plasma::Horizontal) ||
00265             ((f == Plasma::Vertical && parentSize.width() >= minimum.width()) ||
00266              (f == Plasma::Horizontal && parentSize.height() >= minimum.height())))) {
00267             //kDebug() << "we are expanding the popupapplet";
00268 
00269 
00270             // we only switch to expanded if we aren't horiz/vert constrained and
00271             // this applet has an icon.
00272             // otherwise, we leave it up to the applet itself to figure it out
00273             if (icon) {
00274                 icon->hide();
00275             }
00276 
00277             if (savedAspectRatio != Plasma::InvalidAspectRatioMode) {
00278                 q->setAspectRatioMode(savedAspectRatio);
00279             }
00280 
00281             Dialog *dialog = dialogPtr.data();
00282             if (dialog) {
00283                 if (dialog->layout() && qWidget) {
00284                     //we don't want to delete Widget inside the dialog layout
00285                     dialog->layout()->removeWidget(qWidget);
00286                 }
00287 
00288                 if (qWidget) {
00289                     qWidget->setParent(0);
00290                 }
00291 
00292                 delete dialog;
00293             }
00294 
00295             if (!lay) {
00296                 lay = new QGraphicsLinearLayout();
00297                 lay->setContentsMargins(0, 0, 0, 0);
00298                 lay->setSpacing(0);
00299                 lay->setOrientation(Qt::Horizontal);
00300                 q->setLayout(lay);
00301             }
00302 
00303             QSize prefSize;
00304 
00305             if (gWidget) {
00306                 if (proxy) {
00307                     proxy.data()->setWidget(0);
00308                     delete proxy.data();
00309                 }
00310 
00311                 Corona *corona = qobject_cast<Corona *>(gWidget->scene());
00312 
00313                 if (corona) {
00314                     corona->removeOffscreenWidget(gWidget);
00315                 }
00316 
00317                 lay->addItem(gWidget);
00318                 prefSize = gWidget->preferredSize().toSize();
00319             } else if (qWidget) {
00320                 if (!proxy) {
00321                     proxy = new QGraphicsProxyWidget(q);
00322                     proxy.data()->setWidget(qWidget);
00323                     proxy.data()->show();
00324                 }
00325 
00326                 lay->addItem(proxy.data());
00327                 prefSize = qWidget->sizeHint();
00328             }
00329 
00330             //we could be on a big panel, but in that case we will be able to resize
00331             //more than the natural minimum size, because we'll transform into an icon
00332             if (f == Plasma::Horizontal) {
00333                 minimum.setHeight(0);
00334             } else if (f == Plasma::Vertical) {
00335                 minimum.setWidth(0);
00336             }
00337 
00338             qreal left, top, right, bottom;
00339             q->getContentsMargins(&left, &top, &right, &bottom);
00340             QSizeF oldSize(q->size());
00341 
00342             //size not saved/invalid size saved
00343             if (oldSize.width() < q->minimumSize().width() || oldSize.height() < q->minimumSize().height()) {
00344                 q->resize(prefSize);
00345                 emit q->appletTransformedItself();
00346             }
00347         } else {
00348             //Applet on popup
00349             if (icon && lay) {
00350                 lay->addItem(icon);
00351             }
00352 
00353             //kDebug() << "about to switch to a popup";
00354             if (!qWidget && !gWidget) {
00355                 delete dialogPtr.data();
00356                 return;
00357             }
00358 
00359             //there was already a dialog? don't make the switch again
00360             if (dialogPtr) {
00361                 return;
00362             }
00363 
00364             if (proxy) {
00365                 proxy.data()->setWidget(0); // prevent it from deleting our widget!
00366                 delete proxy.data();
00367             }
00368 
00369             //save the aspect ratio mode in case we drag'n drop in the Desktop later
00370             savedAspectRatio = q->aspectRatioMode();
00371 
00372             if (icon) {
00373                 icon->show();
00374                 q->setAspectRatioMode(Plasma::ConstrainedSquare);
00375             }
00376 
00377             Dialog *dialog = new Dialog();
00378             dialog->d->appletPtr = q;
00379             dialogPtr = dialog;
00380 
00381             if (icon) {
00382                 dialog->setAspectRatioMode(savedAspectRatio);
00383             }
00384 
00385             //no longer use Qt::Popup since that seems to cause a lot of problem when you drag
00386             //stuff out of your Dialog (extenders). Monitor WindowDeactivate events so we can
00387             //emulate the same kind of behavior as Qt::Popup (close when you click somewhere
00388             //else.
00389 
00390             if (gWidget) {
00391                 Corona *corona = qobject_cast<Corona *>(gWidget->scene());
00392                 if (!corona) {
00393                     corona = qobject_cast<Corona *>(q->scene());
00394                 }
00395 
00396                 if (corona) {
00397                     corona->addOffscreenWidget(gWidget);
00398                 }
00399 
00400                 gWidget->show();
00401                 dialog->setGraphicsWidget(gWidget);
00402                 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (gWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
00403             } else if (qWidget) {
00404                 QVBoxLayout *l_layout = new QVBoxLayout(dialog);
00405                 l_layout->setSpacing(0);
00406                 l_layout->setMargin(0);
00407                 l_layout->addWidget(qWidget);
00408                 dialog->adjustSize();
00409                 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | (qWidget->windowFlags() & Qt::X11BypassWindowManagerHint));
00410             } else {
00411                 dialog->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
00412             }
00413 
00414             restoreDialogSize();
00415             KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
00416             dialog->installEventFilter(q);
00417 
00418             QObject::connect(dialog, SIGNAL(dialogResized()), q, SLOT(dialogSizeChanged()));
00419             QObject::connect(dialog, SIGNAL(dialogVisible(bool)), q, SLOT(dialogStatusChanged(bool)));
00420         }
00421     }
00422 
00423     if (constraints & Plasma::PopupConstraint) {
00424         updateDialogPosition();
00425     }
00426 
00427     if (icon) {
00428         // emit the size hint changing stuff for our applet as we are handling
00429         // the size changings
00430         emit q->sizeHintChanged(Qt::PreferredSize);
00431     }
00432 }
00433 
00434 void PopupAppletPrivate::appletActivated()
00435 {
00436     internalTogglePopup(true);
00437 }
00438 
00439 QSizeF PopupApplet::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
00440 {
00441     if (!d->dialogPtr || which != Qt::PreferredSize) {
00442         return Applet::sizeHint(which, constraint);
00443     }
00444 
00445     switch (formFactor()) {
00446         case Vertical:
00447         case Horizontal: {
00448             const int size = IconSize(KIconLoader::Panel);
00449             return QSizeF(size, size);
00450         }
00451         default:
00452             break;
00453     }
00454 
00455     const int size = IconSize(KIconLoader::Desktop);
00456     return QSizeF(size, size);
00457 }
00458 
00459 void PopupApplet::mousePressEvent(QGraphicsSceneMouseEvent *event)
00460 {
00461     if (!d->icon && !d->popupLostFocus && event->buttons() == Qt::LeftButton) {
00462         d->clicked = scenePos().toPoint();
00463         event->setAccepted(true);
00464         return;
00465     } else {
00466         d->popupLostFocus = false;
00467         Applet::mousePressEvent(event);
00468     }
00469 }
00470 
00471 void PopupApplet::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00472 {
00473     if (!d->icon &&
00474         (d->clicked - scenePos().toPoint()).manhattanLength() < KGlobalSettings::dndEventDelay()) {
00475         d->internalTogglePopup();
00476     } else {
00477         Applet::mouseReleaseEvent(event);
00478     }
00479 }
00480 
00481 bool PopupApplet::eventFilter(QObject *watched, QEvent *event)
00482 {
00483     if (!d->passive && watched == d->dialogPtr.data() && (event->type() == QEvent::WindowDeactivate)) {
00484         d->popupLostFocus = true;
00485         QTimer::singleShot(100, this, SLOT(clearPopupLostFocus()));
00486     }
00487 
00488     if (watched == d->dialogPtr.data() && event->type() == QEvent::ContextMenu) {
00489         //pass it up to the applet
00490         //well, actually we have to pass it to the *containment*
00491         //because all the code for showing an applet's contextmenu is actually in Containment.
00492         Containment *c = containment();
00493         if (c) {
00494             Applet *applet = this;
00495             Dialog *dialog = d->dialogPtr.data();
00496             if (dialog && dialog->graphicsWidget()) {
00497                 int left, top, right, bottom;
00498                 dialog->getContentsMargins(&left, &top, &right, &bottom);
00499                 const QPoint eventPos = static_cast<QContextMenuEvent*>(event)->pos() - QPoint(left, top);
00500                 QPointF pos = dialog->graphicsWidget()->mapToScene(eventPos);
00501 
00502                 if (Applet *actual = c->d->appletAt(pos)) {
00503                     applet = actual;
00504                 }
00505             }
00506 
00507             KMenu desktopMenu;
00508             c->d->addAppletActions(desktopMenu, applet, event);
00509 
00510             if (!desktopMenu.isEmpty()) {
00511                 desktopMenu.exec(static_cast<QContextMenuEvent*>(event)->globalPos());
00512                 return true;
00513             }
00514 
00515             return false;
00516         }
00517     }
00518 
00519     return Applet::eventFilter(watched, event);
00520 }
00521 
00522 //FIXME: some duplication between the drag events... maybe add some simple helper function?
00523 void PopupApplet::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
00524 {
00525     if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
00526         const ExtenderItemMimeData *mimeData =
00527             qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
00528         if (mimeData && qobject_cast<Extender*>(graphicsWidget())) {
00529             event->accept();
00530             showPopup();
00531         }
00532     }
00533 }
00534 
00535 void PopupApplet::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
00536 {
00537     if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
00538         const ExtenderItemMimeData *mimeData =
00539             qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
00540         if (mimeData && qobject_cast<Extender*>(graphicsWidget())) {
00541             //We want to hide the popup if we're not moving onto the popup AND it is not the popup
00542             //we started.
00543             if (d->dialogPtr && !d->dialogPtr.data()->geometry().contains(event->screenPos()) &&
00544                 mimeData->extenderItem()->extender() != qobject_cast<Extender*>(graphicsWidget())) {
00545                 //We actually try to hide the popup, with a call to showPopup, with a smal timeout,
00546                 //so if the user moves into the popup fast enough, it remains open (the extender
00547                 //will call showPopup which will cancel the timeout.
00548                 showPopup(250);
00549             }
00550         }
00551     }
00552 }
00553 
00554 void PopupApplet::dropEvent(QGraphicsSceneDragDropEvent *event)
00555 {
00556     if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
00557         const ExtenderItemMimeData *mimeData =
00558             qobject_cast<const ExtenderItemMimeData*>(event->mimeData());
00559         if (mimeData && qobject_cast<Extender*>(graphicsWidget())) {
00560             mimeData->extenderItem()->setExtender(extender());
00561             QApplication::restoreOverrideCursor();
00562         }
00563     }
00564 }
00565 
00566 void PopupApplet::showPopup(uint popupDuration)
00567 {
00568     // use autohideTimer to store when the next show should be
00569     if (popupDuration > 0 || d->autohideTimer) {
00570         if (!d->autohideTimer) {
00571             d->autohideTimer = new QTimer(this);
00572             d->autohideTimer->setSingleShot(true);
00573             connect(d->autohideTimer, SIGNAL(timeout()), this, SLOT(hideTimedPopup()));
00574         }
00575 
00576         d->autohideTimer->stop();
00577         d->autohideTimer->setInterval(popupDuration);
00578     }
00579 
00580     //kDebug() << "starting delayed show, duration for popup is" << popupDuration;
00581     d->delayedShowTimer.start(0, this);
00582 }
00583 
00584 void PopupApplet::timerEvent(QTimerEvent *event)
00585 {
00586     if (event->timerId() == d->delayedShowTimer.timerId()) {
00587         d->delayedShowTimer.stop();
00588         Dialog *dialog = d->dialogPtr.data();
00589         if (dialog) {
00590             // move the popup before its fist show, even if the show isn't triggered by
00591             // a click, this should fix the first random position seen in some widgets
00592             if (!dialog->isVisible()) {
00593                 d->internalTogglePopup();
00594             }
00595 
00596             const int popupDuration = d->autohideTimer ? d->autohideTimer->interval() : 0;
00597             //kDebug() << "popupDuration is:" << (d->autohideTimer ? d->autohideTimer->interval() : 0);
00598             if (popupDuration > 0) {
00599                 d->autohideTimer->start();
00600             } else if (d->autohideTimer) {
00601                 d->autohideTimer->stop();
00602             }
00603         }
00604     } else if (event->timerId() == d->showDialogTimer.timerId()) {
00605         d->showDialogTimer.stop();
00606         d->showDialog();
00607     } else {
00608         Applet::timerEvent(event);
00609     }
00610 }
00611 
00612 void PopupApplet::hidePopup()
00613 {
00614     d->showDialogTimer.stop();
00615     d->delayedShowTimer.stop();
00616 
00617     Dialog *dialog = d->dialogPtr.data();
00618     if (dialog && dialog->isVisible()) {
00619         if (location() != Floating) {
00620             dialog->animatedHide(locationToInverseDirection(location()));
00621         } else {
00622             dialog->hide();
00623         }
00624     }
00625 }
00626 
00627 void PopupApplet::togglePopup()
00628 {
00629     d->internalTogglePopup();
00630 }
00631 
00632 Plasma::PopupPlacement PopupApplet::popupPlacement() const
00633 {
00634     return d->popupPlacement;
00635 }
00636 
00637 void PopupApplet::setPopupAlignment(Qt::AlignmentFlag alignment)
00638 {
00639     d->popupAlignment = alignment;
00640 }
00641 
00642 Qt::AlignmentFlag PopupApplet::popupAlignment() const
00643 {
00644     return d->popupAlignment;
00645 }
00646 
00647 void PopupApplet::popupEvent(bool popped)
00648 {
00649     if (Applet::d->script) {
00650         emit Applet::d->script->popupEvent(popped);
00651     }
00652 }
00653 
00654 void PopupApplet::setPassivePopup(bool passive)
00655 {
00656     d->passive = passive;
00657 }
00658 
00659 bool PopupApplet::isPassivePopup() const
00660 {
00661     return d->passive;
00662 }
00663 
00664 bool PopupApplet::isPopupShowing() const
00665 {
00666     return d->dialogPtr && d->dialogPtr.data()->isVisible();
00667 }
00668 
00669 bool PopupApplet::isIconified() const
00670 {
00671     return d->dialogPtr;
00672 }
00673 
00674 PopupAppletPrivate::PopupAppletPrivate(PopupApplet *applet)
00675         : q(applet),
00676           icon(0),
00677           widget(0),
00678           popupPlacement(Plasma::FloatingPopup),
00679           popupAlignment(Qt::AlignLeft),
00680           savedAspectRatio(Plasma::InvalidAspectRatioMode),
00681           autohideTimer(0),
00682           preShowStatus(UnknownStatus),
00683           popupLostFocus(false),
00684           passive(false)
00685 {
00686     int iconSize = IconSize(KIconLoader::Desktop);
00687     q->resize(iconSize, iconSize);
00688     q->setAcceptDrops(true);
00689     QObject::disconnect(q, SIGNAL(activate()), static_cast<Applet*>(q), SLOT(setFocus()));
00690     QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
00691     QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconSizeChanged(int)));
00692 }
00693 
00694 PopupAppletPrivate::~PopupAppletPrivate()
00695 {
00696     if (proxy) {
00697         proxy.data()->setWidget(0);
00698     }
00699 
00700     delete dialogPtr.data();
00701     delete icon;
00702 }
00703 
00704 void PopupAppletPrivate::iconSizeChanged(int group)
00705 {
00706     if (icon && (group == KIconLoader::Desktop || group == KIconLoader::Panel)) {
00707         q->updateGeometry();
00708     }
00709 }
00710 
00711 void PopupAppletPrivate::internalTogglePopup(bool fromActivatedSignal)
00712 {
00713     if (autohideTimer) {
00714         autohideTimer->stop();
00715     }
00716 
00717     delayedShowTimer.stop();
00718 
00719     Plasma::Dialog *dialog = dialogPtr.data();
00720     if (!dialog) {
00721         q->setFocus(Qt::ShortcutFocusReason);
00722         if (!fromActivatedSignal) {
00723             QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
00724             emit q->activate();
00725             QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
00726         }
00727         return;
00728     }
00729 
00730     if (!q->view()) {
00731         return;
00732     }
00733 
00734     if (dialog->isVisible()) {
00735         if (q->location() != Floating) {
00736             dialog->animatedHide(locationToInverseDirection(q->location()));
00737         } else {
00738             dialog->hide();
00739         }
00740 
00741         dialog->clearFocus();
00742     } else {
00743         if (q->graphicsWidget() &&
00744             q->graphicsWidget() == static_cast<Applet*>(q)->d->extender.data() &&
00745             static_cast<Applet*>(q)->d->extender.data()->isEmpty()) {
00746             // we have nothing to show, so let's not.
00747             if (!fromActivatedSignal) {
00748                 QObject::disconnect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
00749                 emit q->activate();
00750                 QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated()));
00751             }
00752             return;
00753         }
00754 
00755         ToolTipManager::self()->hide(q);
00756         showDialogTimer.start(0, q);
00757     }
00758 }
00759 
00760 void PopupAppletPrivate::showDialog()
00761 {
00762     Plasma::Dialog *dialog = dialogPtr.data();
00763     if (!dialog) {
00764         return;
00765     }
00766 
00767     updateDialogPosition();
00768 
00769     KWindowSystem::setOnAllDesktops(dialog->winId(), true);
00770     KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager);
00771 
00772     if (icon) {
00773         dialog->setAspectRatioMode(savedAspectRatio);
00774     }
00775 
00776     if (q->location() != Floating) {
00777         dialog->animatedShow(locationToDirection(q->location()));
00778     } else {
00779         dialog->show();
00780     }
00781 
00782     if (!(dialog->windowFlags() & Qt::X11BypassWindowManagerHint)) {
00783         KWindowSystem::activateWindow(dialog->winId());
00784     }
00785 }
00786 
00787 void PopupAppletPrivate::hideTimedPopup()
00788 {
00789     autohideTimer->stop();
00790     q->hidePopup();
00791 }
00792 
00793 void PopupAppletPrivate::clearPopupLostFocus()
00794 {
00795     if (!icon || !icon->isDown()) {
00796         q->hidePopup();
00797     }
00798 
00799     popupLostFocus = false;
00800 }
00801 
00802 KConfigGroup PopupAppletPrivate::popupConfigGroup()
00803 {
00804     KConfigGroup *mainGroup = static_cast<Applet*>(q)->d->mainConfigGroup();
00805     return KConfigGroup(mainGroup, "PopupApplet");
00806 }
00807 
00808 void PopupAppletPrivate::dialogSizeChanged()
00809 {
00810     //Reposition the dialog
00811     Plasma::Dialog *dialog = dialogPtr.data();
00812     if (dialog) {
00813         KConfigGroup sizeGroup = popupConfigGroup();
00814         sizeGroup.writeEntry("DialogHeight", dialog->height());
00815         sizeGroup.writeEntry("DialogWidth", dialog->width());
00816 
00817         updateDialogPosition(!dialog->isUserResizing());
00818 
00819         emit q->configNeedsSaving();
00820         emit q->appletTransformedByUser();
00821     }
00822 }
00823 
00824 void PopupAppletPrivate::dialogStatusChanged(bool shown)
00825 {
00826     if (shown) {
00827         preShowStatus = q->status();
00828         q->setStatus(NeedsAttentionStatus);
00829         QObject::connect(q, SIGNAL(newStatus(Plasma::ItemStatus)),
00830                          q, SLOT(statusChangeWhileShown(Plasma::ItemStatus)),
00831                          Qt::UniqueConnection);
00832     } else {
00833         QObject::disconnect(q, SIGNAL(newStatus(Plasma::ItemStatus)),
00834                             q, SLOT(statusChangeWhileShown(Plasma::ItemStatus)));
00835         q->setStatus(preShowStatus);
00836     }
00837 
00838     q->popupEvent(shown);
00839 }
00840 
00841 void PopupAppletPrivate::statusChangeWhileShown(Plasma::ItemStatus status)
00842 {
00843     preShowStatus = status;
00844 }
00845 
00846 void PopupAppletPrivate::createIconWidget()
00847 {
00848     if (icon) {
00849         return;
00850     }
00851 
00852     icon = new Plasma::IconWidget(q);
00853     QObject::connect(icon, SIGNAL(clicked()), q, SLOT(internalTogglePopup()));
00854 
00855     QGraphicsLinearLayout *layout = new QGraphicsLinearLayout();
00856     layout->setContentsMargins(0, 0, 0, 0);
00857     layout->setSpacing(0);
00858     layout->setOrientation(Qt::Horizontal);
00859     layout->addItem(icon);
00860     layout->setAlignment(icon, Qt::AlignCenter);
00861     q->setLayout(layout);
00862 }
00863 
00864 void PopupAppletPrivate::restoreDialogSize()
00865 {
00866     Plasma::Dialog *dialog = dialogPtr.data();
00867     if (!dialog) {
00868         return;
00869     }
00870 
00871     Corona *corona = qobject_cast<Corona *>(q->scene());
00872     if (!corona) {
00873         return;
00874     }
00875 
00876     KConfigGroup sizeGroup = popupConfigGroup();
00877 
00878     int preferredWidth = 0;
00879     int preferredHeight = 0;
00880     QGraphicsWidget *gWidget = dialog->graphicsWidget();
00881     if (gWidget) {
00882         preferredWidth = gWidget->preferredSize().width();
00883         preferredHeight = gWidget->preferredSize().height();
00884     }
00885 
00886     const int width = qMin(sizeGroup.readEntry("DialogWidth", preferredWidth),
00887                            corona->screenGeometry(-1).width() - 50);
00888     const int height = qMin(sizeGroup.readEntry("DialogHeight", preferredHeight),
00889                             corona->screenGeometry(-1).height() - 50);
00890 
00891     QSize saved(width, height);
00892 
00893     if (saved.isNull()) {
00894         saved = dialog->sizeHint();
00895     } else {
00896         saved = saved.expandedTo(dialog->minimumSizeHint());
00897     }
00898 
00899     if (saved.width() != dialog->width() || saved.height() != dialog->height()) {
00900         dialog->resize(saved);
00901        /*if (gWidget) {
00902          gWidget->resize(saved);
00903        }*/
00904     }
00905 }
00906 
00907 void PopupAppletPrivate::updateDialogPosition(bool move)
00908 {
00909     Plasma::Dialog *dialog = dialogPtr.data();
00910     if (!dialog) {
00911         return;
00912     }
00913 
00914     Corona *corona = qobject_cast<Corona *>(q->scene());
00915     if (!corona) {
00916         return;
00917     }
00918 
00919     QGraphicsView *view = q->view();
00920     if (!view) {
00921         return;
00922     }
00923 
00924     const QPoint appletPos = view->mapToGlobal(view->mapFromScene(q->scenePos()));
00925 
00926     QPoint dialogPos = dialog->pos();
00927     if (move) {
00928         if (!q->containment() || view == q->containment()->view()) {
00929             dialogPos = corona->popupPosition(q, dialog->size(), popupAlignment);
00930         } else {
00931             dialogPos = corona->popupPosition(q->parentItem(), dialog->size(), popupAlignment);
00932         }
00933     }
00934 
00935     bool reverse = false;
00936     if (q->formFactor() == Plasma::Vertical) {
00937         reverse = (appletPos.y() + (q->size().height() / 2)) < (dialogPos.y() + (dialog->size().height() / 2));
00938         dialog->setMinimumResizeLimits(-1, appletPos.y(), -1, appletPos.y() + q->size().height());
00939     } else {
00940         reverse = (appletPos.x() + (q->size().width() / 2)) < (dialogPos.x() + (dialog->size().width() / 2));
00941         dialog->setMinimumResizeLimits(appletPos.x(), -1, appletPos.x() + q->size().width(), -1);
00942     }
00943 
00944     Dialog::ResizeCorners resizeCorners = Dialog::NoCorner;
00945     switch (q->location()) {
00946     case BottomEdge:
00947         resizeCorners = Dialog::NorthEast | Dialog::NorthWest;
00948         popupPlacement = reverse ? TopPosedLeftAlignedPopup : TopPosedRightAlignedPopup;
00949         break;
00950     case TopEdge:
00951         resizeCorners = Dialog::SouthEast | Dialog::SouthWest;
00952         popupPlacement = reverse ? Plasma::BottomPosedLeftAlignedPopup : Plasma::BottomPosedRightAlignedPopup;
00953         break;
00954     case LeftEdge:
00955         resizeCorners = Dialog::SouthEast | Dialog::NorthEast;
00956         popupPlacement = reverse ? RightPosedTopAlignedPopup : RightPosedBottomAlignedPopup;
00957         break;
00958 
00959     case RightEdge:
00960         resizeCorners = Dialog::SouthWest | Dialog::NorthWest;
00961         popupPlacement = reverse ? LeftPosedTopAlignedPopup : LeftPosedBottomAlignedPopup;
00962         break;
00963 
00964     default:
00965         popupPlacement = FloatingPopup;
00966         resizeCorners = Dialog::All;
00967         break;
00968     }
00969 
00970     dialog->setResizeHandleCorners(resizeCorners);
00971     if (move) {
00972         dialog->move(dialogPos);
00973     }
00974 }
00975 
00976 } // Plasma namespace
00977 
00978 #include "popupapplet.moc"
00979 
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed May 2 2012 17:36:14 by doxygen 1.8.0 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.3 API Reference

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