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

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

Skip menu "kdelibs"
  • 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
Generated for kdelibs by doxygen 1.7.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal