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
KDE 4.6 API Reference