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

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.5
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