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