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 q->setStatus(Plasma::NeedsAttentionStatus); 00440 q->showPopup(); 00441 } 00442 00443 QSizeF PopupApplet::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const 00444 { 00445 if (!d->dialogPtr || which != Qt::PreferredSize) { 00446 return Applet::sizeHint(which, constraint); 00447 } 00448 00449 switch (formFactor()) { 00450 case Vertical: 00451 case Horizontal: { 00452 const int size = IconSize(KIconLoader::Panel); 00453 return QSizeF(size, size); 00454 break; 00455 } 00456 default: 00457 break; 00458 } 00459 00460 const int size = IconSize(KIconLoader::Desktop); 00461 return QSizeF(size, size); 00462 } 00463 00464 void PopupApplet::mousePressEvent(QGraphicsSceneMouseEvent *event) 00465 { 00466 if (!d->icon && !d->popupLostFocus && event->buttons() == Qt::LeftButton) { 00467 d->clicked = scenePos().toPoint(); 00468 event->setAccepted(true); 00469 return; 00470 } else { 00471 d->popupLostFocus = false; 00472 Applet::mousePressEvent(event); 00473 } 00474 } 00475 00476 void PopupApplet::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) 00477 { 00478 if (!d->icon && 00479 (d->clicked - scenePos().toPoint()).manhattanLength() < KGlobalSettings::dndEventDelay()) { 00480 d->internalTogglePopup(); 00481 } else { 00482 Applet::mouseReleaseEvent(event); 00483 } 00484 } 00485 00486 bool PopupApplet::eventFilter(QObject *watched, QEvent *event) 00487 { 00488 if (!d->passive && watched == d->dialogPtr.data() && (event->type() == QEvent::WindowDeactivate)) { 00489 d->popupLostFocus = true; 00490 QTimer::singleShot(100, this, SLOT(clearPopupLostFocus())); 00491 } 00492 00493 if (watched == d->dialogPtr.data() && event->type() == QEvent::ContextMenu) { 00494 //pass it up to the applet 00495 //well, actually we have to pass it to the *containment* 00496 //because all the code for showing an applet's contextmenu is actually in Containment. 00497 Containment *c = containment(); 00498 if (c) { 00499 Applet *applet = this; 00500 Dialog *dialog = d->dialogPtr.data(); 00501 if (dialog && dialog->graphicsWidget()) { 00502 int left, top, right, bottom; 00503 dialog->getContentsMargins(&left, &top, &right, &bottom); 00504 const QPoint eventPos = static_cast<QContextMenuEvent*>(event)->pos() - QPoint(left, top); 00505 QPointF pos = dialog->graphicsWidget()->mapToScene(eventPos); 00506 00507 if (Applet *actual = c->d->appletAt(pos)) { 00508 applet = actual; 00509 } 00510 } 00511 00512 KMenu desktopMenu; 00513 c->d->addAppletActions(desktopMenu, applet, event); 00514 00515 if (!desktopMenu.isEmpty()) { 00516 desktopMenu.exec(static_cast<QContextMenuEvent*>(event)->globalPos()); 00517 return true; 00518 } 00519 00520 return false; 00521 } 00522 } 00523 00524 return Applet::eventFilter(watched, event); 00525 } 00526 00527 //FIXME: some duplication between the drag events... maybe add some simple helper function? 00528 void PopupApplet::dragEnterEvent(QGraphicsSceneDragDropEvent *event) 00529 { 00530 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) { 00531 const ExtenderItemMimeData *mimeData = 00532 qobject_cast<const ExtenderItemMimeData*>(event->mimeData()); 00533 if (mimeData && qobject_cast<Extender*>(graphicsWidget())) { 00534 event->accept(); 00535 showPopup(); 00536 } 00537 } 00538 } 00539 00540 void PopupApplet::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) 00541 { 00542 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) { 00543 const ExtenderItemMimeData *mimeData = 00544 qobject_cast<const ExtenderItemMimeData*>(event->mimeData()); 00545 if (mimeData && qobject_cast<Extender*>(graphicsWidget())) { 00546 //We want to hide the popup if we're not moving onto the popup AND it is not the popup 00547 //we started. 00548 if (d->dialogPtr && !d->dialogPtr.data()->geometry().contains(event->screenPos()) && 00549 mimeData->extenderItem()->extender() != qobject_cast<Extender*>(graphicsWidget())) { 00550 //We actually try to hide the popup, with a call to showPopup, with a smal timeout, 00551 //so if the user moves into the popup fast enough, it remains open (the extender 00552 //will call showPopup which will cancel the timeout. 00553 showPopup(250); 00554 } 00555 } 00556 } 00557 } 00558 00559 void PopupApplet::dropEvent(QGraphicsSceneDragDropEvent *event) 00560 { 00561 if (event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) { 00562 const ExtenderItemMimeData *mimeData = 00563 qobject_cast<const ExtenderItemMimeData*>(event->mimeData()); 00564 if (mimeData && qobject_cast<Extender*>(graphicsWidget())) { 00565 mimeData->extenderItem()->setExtender(extender()); 00566 QApplication::restoreOverrideCursor(); 00567 } 00568 } 00569 } 00570 00571 void PopupApplet::showPopup(uint popupDuration) 00572 { 00573 // use autohideTimer to store when the next show should be 00574 if (popupDuration > 0 || d->autohideTimer) { 00575 if (!d->autohideTimer) { 00576 d->autohideTimer = new QTimer(this); 00577 d->autohideTimer->setSingleShot(true); 00578 connect(d->autohideTimer, SIGNAL(timeout()), this, SLOT(hideTimedPopup())); 00579 } 00580 00581 d->autohideTimer->stop(); 00582 d->autohideTimer->setInterval(popupDuration); 00583 } 00584 00585 //kDebug() << "starting delayed show, duration for popup is" << popupDuration; 00586 d->delayedShowTimer.start(0, this); 00587 } 00588 00589 void PopupApplet::timerEvent(QTimerEvent *event) 00590 { 00591 if (event->timerId() == d->delayedShowTimer.timerId()) { 00592 d->delayedShowTimer.stop(); 00593 Dialog *dialog = d->dialogPtr.data(); 00594 if (dialog) { 00595 // move the popup before its fist show, even if the show isn't triggered by 00596 // a click, this should fix the first random position seen in some widgets 00597 if (!dialog->isVisible()) { 00598 d->internalTogglePopup(); 00599 } 00600 00601 const int popupDuration = d->autohideTimer ? d->autohideTimer->interval() : 0; 00602 //kDebug() << "popupDuration is:" << (d->autohideTimer ? d->autohideTimer->interval() : 0); 00603 if (popupDuration > 0) { 00604 d->autohideTimer->start(); 00605 } else if (d->autohideTimer) { 00606 d->autohideTimer->stop(); 00607 } 00608 } 00609 } else { 00610 Applet::timerEvent(event); 00611 } 00612 } 00613 00614 void PopupApplet::hidePopup() 00615 { 00616 d->delayedShowTimer.stop(); 00617 00618 Dialog *dialog = d->dialogPtr.data(); 00619 if (dialog) { 00620 if (location() != Floating) { 00621 dialog->animatedHide(locationToInverseDirection(location())); 00622 } else { 00623 dialog->hide(); 00624 } 00625 } 00626 } 00627 00628 void PopupApplet::togglePopup() 00629 { 00630 d->internalTogglePopup(); 00631 } 00632 00633 Plasma::PopupPlacement PopupApplet::popupPlacement() const 00634 { 00635 return d->popupPlacement; 00636 } 00637 00638 void PopupApplet::setPopupAlignment(Qt::AlignmentFlag alignment) 00639 { 00640 d->popupAlignment = alignment; 00641 } 00642 00643 Qt::AlignmentFlag PopupApplet::popupAlignment() const 00644 { 00645 return d->popupAlignment; 00646 } 00647 00648 void PopupApplet::popupEvent(bool popped) 00649 { 00650 if (Applet::d->script) { 00651 emit Applet::d->script->popupEvent(popped); 00652 } 00653 } 00654 00655 void PopupApplet::setPassivePopup(bool passive) 00656 { 00657 d->passive = passive; 00658 } 00659 00660 bool PopupApplet::isPassivePopup() const 00661 { 00662 return d->passive; 00663 } 00664 00665 bool PopupApplet::isPopupShowing() const 00666 { 00667 return d->dialogPtr && d->dialogPtr.data()->isVisible(); 00668 } 00669 00670 bool PopupApplet::isIconified() const 00671 { 00672 return d->dialogPtr; 00673 } 00674 00675 PopupAppletPrivate::PopupAppletPrivate(PopupApplet *applet) 00676 : q(applet), 00677 icon(0), 00678 widget(0), 00679 graphicsWidget(0), 00680 popupPlacement(Plasma::FloatingPopup), 00681 popupAlignment(Qt::AlignLeft), 00682 savedAspectRatio(Plasma::InvalidAspectRatioMode), 00683 autohideTimer(0), 00684 popupLostFocus(false), 00685 passive(false) 00686 { 00687 int iconSize = IconSize(KIconLoader::Desktop); 00688 q->resize(iconSize, iconSize); 00689 q->setAcceptDrops(true); 00690 QObject::disconnect(q, SIGNAL(activate()), static_cast<Applet*>(q), SLOT(setFocus())); 00691 QObject::connect(q, SIGNAL(activate()), q, SLOT(appletActivated())); 00692 QObject::connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), q, SLOT(iconSizeChanged(int))); 00693 } 00694 00695 PopupAppletPrivate::~PopupAppletPrivate() 00696 { 00697 if (proxy) { 00698 proxy.data()->setWidget(0); 00699 } 00700 00701 delete dialogPtr.data(); 00702 delete icon; 00703 } 00704 00705 void PopupAppletPrivate::iconSizeChanged(int group) 00706 { 00707 if (icon && (group == KIconLoader::Desktop || group == KIconLoader::Panel)) { 00708 q->updateGeometry(); 00709 } 00710 } 00711 00712 void PopupAppletPrivate::internalTogglePopup() 00713 { 00714 if (autohideTimer) { 00715 autohideTimer->stop(); 00716 } 00717 00718 delayedShowTimer.stop(); 00719 00720 Plasma::Dialog *dialog = dialogPtr.data(); 00721 if (!dialog) { 00722 q->setFocus(Qt::ShortcutFocusReason); 00723 return; 00724 } 00725 00726 if (!q->view()) { 00727 return; 00728 } 00729 00730 if (dialog->isVisible()) { 00731 if (q->location() != Floating) { 00732 dialog->animatedHide(locationToInverseDirection(q->location())); 00733 } else { 00734 dialog->hide(); 00735 } 00736 00737 dialog->clearFocus(); 00738 } else { 00739 if (q->graphicsWidget() && 00740 q->graphicsWidget() == static_cast<Applet*>(q)->d->extender.data() && 00741 static_cast<Applet*>(q)->d->extender.data()->isEmpty()) { 00742 // we have nothing to show, so let's not. 00743 return; 00744 } 00745 00746 ToolTipManager::self()->hide(q); 00747 updateDialogPosition(); 00748 00749 KWindowSystem::setOnAllDesktops(dialog->winId(), true); 00750 KWindowSystem::setState(dialog->winId(), NET::SkipTaskbar | NET::SkipPager); 00751 00752 dialog->setAspectRatioMode(savedAspectRatio); 00753 00754 if (q->location() != Floating) { 00755 dialog->animatedShow(locationToDirection(q->location())); 00756 } else { 00757 dialog->show(); 00758 } 00759 00760 if (!(dialog->windowFlags() & Qt::X11BypassWindowManagerHint)) { 00761 KWindowSystem::activateWindow(dialog->winId()); 00762 } 00763 } 00764 } 00765 00766 void PopupAppletPrivate::hideTimedPopup() 00767 { 00768 autohideTimer->stop(); 00769 q->hidePopup(); 00770 } 00771 00772 void PopupAppletPrivate::clearPopupLostFocus() 00773 { 00774 if (!icon || !icon->isDown()) { 00775 q->hidePopup(); 00776 } 00777 00778 popupLostFocus = false; 00779 } 00780 00781 KConfigGroup PopupAppletPrivate::popupConfigGroup() 00782 { 00783 KConfigGroup *mainGroup = static_cast<Applet*>(q)->d->mainConfigGroup(); 00784 return KConfigGroup(mainGroup, "PopupApplet"); 00785 } 00786 00787 void PopupAppletPrivate::dialogSizeChanged() 00788 { 00789 //Reposition the dialog 00790 Plasma::Dialog *dialog = dialogPtr.data(); 00791 if (dialog) { 00792 KConfigGroup sizeGroup = popupConfigGroup(); 00793 sizeGroup.writeEntry("DialogHeight", dialog->height()); 00794 sizeGroup.writeEntry("DialogWidth", dialog->width()); 00795 00796 updateDialogPosition(); 00797 00798 emit q->configNeedsSaving(); 00799 emit q->appletTransformedByUser(); 00800 } 00801 } 00802 00803 void PopupAppletPrivate::dialogStatusChanged(bool status) 00804 { 00805 q->popupEvent(status); 00806 } 00807 00808 void PopupAppletPrivate::restoreDialogSize() 00809 { 00810 Plasma::Dialog *dialog = dialogPtr.data(); 00811 if (!dialog) { 00812 return; 00813 } 00814 00815 Corona *corona = qobject_cast<Corona *>(q->scene()); 00816 if (!corona) { 00817 return; 00818 } 00819 00820 KConfigGroup sizeGroup = popupConfigGroup(); 00821 00822 int preferredWidth = 0; 00823 int preferredHeight = 0; 00824 if (dialog->graphicsWidget()) { 00825 preferredWidth = dialog->graphicsWidget()->preferredSize().width(); 00826 preferredHeight = dialog->graphicsWidget()->preferredSize().height(); 00827 } 00828 00829 const int width = qMin(sizeGroup.readEntry("DialogWidth", preferredWidth), 00830 corona->screenGeometry(-1).width() - 50); 00831 const int height = qMin(sizeGroup.readEntry("DialogHeight", preferredHeight), 00832 corona->screenGeometry(-1).height() - 50); 00833 00834 QSize saved(width, height); 00835 00836 if (saved.isNull()) { 00837 saved = dialog->sizeHint(); 00838 } else { 00839 saved = saved.expandedTo(dialog->minimumSizeHint()); 00840 } 00841 00842 if (saved.width() != dialog->width() || saved.height() != dialog->height()) { 00843 dialog->resize(saved); 00844 } 00845 } 00846 00847 void PopupAppletPrivate::updateDialogPosition() 00848 { 00849 Plasma::Dialog *dialog = dialogPtr.data(); 00850 if (!dialog) { 00851 return; 00852 } 00853 00854 Corona *corona = qobject_cast<Corona *>(q->scene()); 00855 if (!corona) { 00856 return; 00857 } 00858 00859 QGraphicsView *view = q->view(); 00860 if (!view) { 00861 return; 00862 } 00863 00864 QSize s = dialog->size(); 00865 QPoint pos = view->mapFromScene(q->scenePos()); 00866 00867 if (!q->containment() || view == q->containment()->view()) { 00868 pos = corona->popupPosition(q, s, popupAlignment); 00869 } else { 00870 pos = corona->popupPosition(q->parentItem(), s, popupAlignment); 00871 } 00872 00873 bool reverse = false; 00874 if (q->formFactor() == Plasma::Vertical) { 00875 if (view->mapToGlobal(view->mapFromScene(q->scenePos())).y() + q->size().height()/2 < pos.y() + dialog->size().width()/2) { 00876 reverse = true; 00877 } 00878 } else { 00879 if (view->mapToGlobal(view->mapFromScene(q->scenePos())).x() + q->size().width()/2 < pos.x() + dialog->size().width()/2) { 00880 reverse = true; 00881 } 00882 } 00883 00884 switch (q->location()) { 00885 case BottomEdge: 00886 if (pos.x() >= q->pos().x()) { 00887 dialog->setResizeHandleCorners(Dialog::NorthEast); 00888 } else { 00889 dialog->setResizeHandleCorners(Dialog::NorthWest); 00890 } 00891 00892 if (reverse) { 00893 popupPlacement = Plasma::TopPosedLeftAlignedPopup; 00894 } else { 00895 popupPlacement = Plasma::TopPosedRightAlignedPopup; 00896 } 00897 break; 00898 case TopEdge: 00899 if (pos.x() >= q->pos().x()) { 00900 dialog->setResizeHandleCorners(Dialog::SouthEast); 00901 } else { 00902 dialog->setResizeHandleCorners(Dialog::SouthWest); 00903 } 00904 00905 if (reverse) { 00906 popupPlacement = Plasma::BottomPosedLeftAlignedPopup; 00907 } else { 00908 popupPlacement = Plasma::BottomPosedRightAlignedPopup; 00909 } 00910 break; 00911 case LeftEdge: 00912 if (pos.y() >= q->pos().y()) { 00913 dialog->setResizeHandleCorners(Dialog::SouthEast); 00914 } else { 00915 dialog->setResizeHandleCorners(Dialog::NorthEast); 00916 } 00917 00918 if (reverse) { 00919 popupPlacement = Plasma::RightPosedTopAlignedPopup; 00920 } else { 00921 popupPlacement = Plasma::RightPosedBottomAlignedPopup; 00922 } 00923 break; 00924 00925 case RightEdge: 00926 if (pos.y() >= q->pos().y()) { 00927 dialog->setResizeHandleCorners(Dialog::SouthWest); 00928 } else { 00929 dialog->setResizeHandleCorners(Dialog::NorthWest); 00930 } 00931 00932 if (reverse) { 00933 popupPlacement = Plasma::LeftPosedTopAlignedPopup; 00934 } else { 00935 popupPlacement = Plasma::LeftPosedBottomAlignedPopup; 00936 } 00937 break; 00938 default: 00939 dialog->setResizeHandleCorners(Dialog::NorthEast); 00940 } 00941 00942 dialog->move(pos); 00943 } 00944 00945 } // Plasma namespace 00946 00947 #include "popupapplet.moc" 00948
KDE 4.6 API Reference