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

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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.3
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