00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "extenderitem.h"
00021
00022 #include <QApplication>
00023 #include <QAction>
00024 #include <QBitmap>
00025 #include <QGraphicsSceneResizeEvent>
00026 #include <QGraphicsSceneMouseEvent>
00027 #include <QGraphicsLinearLayout>
00028 #include <QLayout>
00029 #include <QPainter>
00030 #include <QTimer>
00031
00032 #include <kdebug.h>
00033 #include <kicon.h>
00034 #include <kwindowsystem.h>
00035 #include <kglobalsettings.h>
00036
00037 #include "applet.h"
00038 #include "containment.h"
00039 #include "corona.h"
00040 #include "dialog.h"
00041 #include "extender.h"
00042 #include "framesvg.h"
00043 #include "popupapplet.h"
00044 #include "theme.h"
00045 #include "view.h"
00046
00047 #include "private/applet_p.h"
00048 #include "private/extender_p.h"
00049 #include "private/extenderitem_p.h"
00050
00051 #include "widgets/iconwidget.h"
00052
00053 namespace Plasma
00054 {
00055
00056 class ExtenderItemView : public QGraphicsView
00057 {
00058 public:
00059 ExtenderItemView(QGraphicsScene *scene, QWidget *parent = 0)
00060 : QGraphicsView(scene, parent)
00061 {
00062
00063 composite = KWindowSystem::compositingActive();
00064 }
00065
00066 ~ExtenderItemView()
00067 {}
00068
00069 void drawBackground(QPainter *painter, const QRectF &rect)
00070 {
00071 if (composite) {
00072 painter->setCompositionMode(QPainter::CompositionMode_Source);
00073 painter->fillRect(rect.toAlignedRect(), Qt::transparent);
00074 } else {
00075 QGraphicsView::drawBackground(painter, rect);
00076 }
00077 }
00078
00079 private:
00080 bool composite;
00081 };
00082
00083 ExtenderItem::ExtenderItem(Extender *hostExtender, uint extenderItemId)
00084 : QGraphicsWidget(hostExtender),
00085 d(new ExtenderItemPrivate(this, hostExtender))
00086 {
00087 Q_ASSERT(hostExtender);
00088
00089
00090 if (extenderItemId) {
00091 d->extenderItemId = extenderItemId;
00092 ExtenderItemPrivate::s_maxExtenderItemId =
00093 qMax(ExtenderItemPrivate::s_maxExtenderItemId, extenderItemId);
00094 } else {
00095 d->extenderItemId = ++ExtenderItemPrivate::s_maxExtenderItemId;
00096 }
00097
00098
00099 KConfigGroup cg = hostExtender->d->applet->config("ExtenderItems");
00100 KConfigGroup dg = KConfigGroup(&cg, QString::number(d->extenderItemId));
00101
00102 uint sourceAppletId = dg.readEntry("sourceAppletId", 0);
00103
00104
00105 if (!sourceAppletId) {
00106
00107 dg.writeEntry("sourceAppletPluginName", hostExtender->d->applet->pluginName());
00108 dg.writeEntry("sourceAppletId", hostExtender->d->applet->id());
00109 dg.writeEntry("extenderIconName", hostExtender->d->applet->icon());
00110 d->sourceApplet = hostExtender->d->applet;
00111 d->collapseIcon = new IconWidget(KIcon(hostExtender->d->applet->icon()), "", this);
00112 } else {
00113
00114 d->name = dg.readEntry("extenderItemName", "");
00115 d->title = dg.readEntry("extenderTitle", "");
00116 setCollapsed(dg.readEntry("isCollapsed", false));
00117
00118 QString iconName = dg.readEntry("extenderIconName", "utilities-desktop-extra");
00119 if (iconName.isEmpty()) {
00120 iconName = "utilities-desktop-extra";
00121 }
00122 d->collapseIcon = new IconWidget(KIcon(iconName), "", this);
00123
00124
00125 Corona *corona = hostExtender->d->applet->containment()->corona();
00126 foreach (Containment *containment, corona->containments()) {
00127 foreach (Applet *applet, containment->applets()) {
00128 if (applet->id() == sourceAppletId &&
00129 applet->pluginName() == dg.readEntry("sourceAppletPluginName", "")) {
00130 d->sourceApplet = applet;
00131 }
00132 }
00133 }
00134 }
00135
00136
00137
00138 connect(d->sourceApplet, SIGNAL(destroyed()), this, SLOT(sourceAppletRemoved()));
00139 connect(d->collapseIcon, SIGNAL(clicked()), this, SLOT(toggleCollapse()));
00140
00141
00142 d->toolbox = new QGraphicsWidget(this);
00143 d->toolboxLayout = new QGraphicsLinearLayout(d->toolbox);
00144 d->toolbox->setLayout(d->toolboxLayout);
00145
00146
00147 setExtender(hostExtender);
00148
00149
00150 d->updateToolBox();
00151
00152
00153 d->themeChanged();
00154
00155 setAcceptsHoverEvents(true);
00156
00157 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeChanged()));
00158 }
00159
00160 ExtenderItem::~ExtenderItem()
00161 {
00162
00163 if (d->mouseOver) {
00164 QApplication::restoreOverrideCursor();
00165 }
00166 delete d;
00167 }
00168
00169 KConfigGroup ExtenderItem::config() const
00170 {
00171 KConfigGroup cg = d->extender->d->applet->config("ExtenderItems");
00172 return KConfigGroup(&cg, QString::number(d->extenderItemId));
00173 }
00174
00175 void ExtenderItem::setTitle(const QString &title)
00176 {
00177 d->title = title;
00178 config().writeEntry("extenderTitle", title);
00179 update();
00180 }
00181
00182 QString ExtenderItem::title() const
00183 {
00184 return d->title;
00185 }
00186
00187 void ExtenderItem::setName(const QString &name)
00188 {
00189 d->name = name;
00190 config().writeEntry("extenderItemName", name);
00191 }
00192
00193 QString ExtenderItem::name() const
00194 {
00195 return d->name;
00196 }
00197
00198 void ExtenderItem::setWidget(QGraphicsItem *widget)
00199 {
00200 widget->setParentItem(this);
00201
00202 QSizeF panelSize(QSizeF(size().width() - d->bgLeft - d->bgRight,
00203 d->iconSize() + d->dragTop + d->dragBottom));
00204 widget->setPos(QPointF(d->bgLeft + d->dragLeft, panelSize.height() +
00205 d->bgTop + d->dragTop));
00206 d->widget = widget;
00207 setCollapsed(isCollapsed());
00208 }
00209
00210 QGraphicsItem *ExtenderItem::widget() const
00211 {
00212 return d->widget;
00213 }
00214
00215 void ExtenderItem::setIcon(const QIcon &icon)
00216 {
00217 d->iconName.clear();
00218 d->collapseIcon->setIcon(icon);
00219 }
00220
00221 void ExtenderItem::setIcon(const QString &icon)
00222 {
00223 if (icon != d->iconName) {
00224 d->collapseIcon->setIcon(icon);
00225 d->iconName = icon;
00226 config().writeEntry("extenderIconName", icon);
00227 }
00228 }
00229
00230 QIcon ExtenderItem::icon() const
00231 {
00232 return d->collapseIcon->icon();
00233 }
00234
00235 void ExtenderItem::setExtender(Extender *extender, const QPointF &pos)
00236 {
00237 Q_ASSERT(extender);
00238
00239 if (extender == d->extender) {
00240
00241 setParentItem(extender);
00242 extender->d->addExtenderItem(this, pos);
00243 return;
00244 }
00245
00246
00247
00248 d->extender->d->removeExtenderItem(this);
00249 emit d->extender->itemDetached(this);
00250
00251
00252 if (d->hostApplet() && (extender != d->extender)) {
00253 KConfigGroup c = extender->d->applet->config("ExtenderItems");
00254 config().reparent(&c);
00255 }
00256
00257 d->extender = extender;
00258
00259
00260 setParentItem(extender);
00261 extender->d->addExtenderItem(this, pos);
00262
00263
00264 if (d->expirationTimer && isDetached()) {
00265 d->expirationTimer->stop();
00266 delete d->expirationTimer;
00267 d->expirationTimer = 0;
00268 }
00269
00270
00271 d->themeChanged();
00272
00273
00274 d->updateToolBox();
00275 }
00276
00277 Extender *ExtenderItem::extender() const
00278 {
00279 return d->extender;
00280 }
00281
00282 bool ExtenderItem::isCollapsed() const
00283 {
00284 return d->collapsed;
00285 }
00286
00287 void ExtenderItem::setAutoExpireDelay(uint time)
00288 {
00289 if (!time) {
00290 if (d->expirationTimer) {
00291 d->expirationTimer->stop();
00292 delete d->expirationTimer;
00293 d->expirationTimer = 0;
00294 }
00295 return;
00296 }
00297
00298 if (!isDetached()) {
00299 if (!d->expirationTimer) {
00300 d->expirationTimer = new QTimer(this);
00301 connect(d->expirationTimer, SIGNAL(timeout()), this, SLOT(destroy()));
00302 }
00303
00304 d->expirationTimer->stop();
00305 d->expirationTimer->setSingleShot(true);
00306 d->expirationTimer->setInterval(time);
00307 d->expirationTimer->start();
00308 }
00309 }
00310
00311 uint ExtenderItem::autoExpireDelay() const
00312 {
00313 if (d->expirationTimer) {
00314 return d->expirationTimer->interval();
00315 } else {
00316 return 0;
00317 }
00318 }
00319
00320 bool ExtenderItem::isDetached() const
00321 {
00322 if (d->hostApplet()) {
00323 return (d->sourceApplet != d->hostApplet());
00324 } else {
00325 return false;
00326 }
00327 }
00328
00329 void ExtenderItem::addAction(const QString &name, QAction *action)
00330 {
00331 Q_ASSERT(action);
00332 if (d->actionsInOrder.contains(action)) {
00333 return;
00334 }
00335
00336 d->actions.insert(name, action);
00337 d->actionsInOrder.append(action);
00338 connect(action, SIGNAL(changed()), this, SLOT(updateToolBox()));
00339 connect(action, SIGNAL(destroyed(QObject*)), this, SLOT(actionDestroyed(QObject*)));
00340 d->updateToolBox();
00341 }
00342
00343 QAction *ExtenderItem::action(const QString &name) const
00344 {
00345 return d->actions.value(name, 0);
00346 }
00347
00348 void ExtenderItem::showCloseButton()
00349 {
00350 if (d->destroyActionVisibility) {
00351 return;
00352 }
00353
00354 d->destroyActionVisibility = true;
00355 d->updateToolBox();
00356 }
00357
00358 void ExtenderItem::hideCloseButton()
00359 {
00360 if (!d->destroyActionVisibility) {
00361 return;
00362 }
00363
00364 d->destroyActionVisibility = false;
00365 d->updateToolBox();
00366 }
00367
00368 void ExtenderItem::destroy()
00369 {
00370 if (d->mousePressed) {
00371
00372 return;
00373 }
00374
00375 d->hostApplet()->config("ExtenderItems").deleteGroup(QString::number(d->extenderItemId));
00376 d->extender->d->removeExtenderItem(this);
00377 deleteLater();
00378 }
00379
00380 void ExtenderItem::setCollapsed(bool collapsed)
00381 {
00382 config().writeEntry("isCollapsed", collapsed);
00383 d->collapsed = collapsed;
00384
00385 qreal marginWidth = d->bgLeft + d->bgRight + d->dragLeft + d->dragRight;
00386 qreal marginHeight = d->bgTop + d->bgBottom + 2 * d->dragTop + 2 * d->dragBottom;
00387
00388 if (!d->widget) {
00389 setPreferredSize(QSizeF(200, d->dragHandleRect().height()));
00390 setMinimumSize(QSizeF(0, d->dragHandleRect().height()));
00391
00392 setMaximumSize(QSizeF(1000, d->dragHandleRect().height()));
00393 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00394 updateGeometry();
00395 return;
00396 }
00397
00398 d->widget->setVisible(!collapsed);
00399
00400 QSizeF min;
00401 QSizeF pref;
00402 QSizeF max;
00403
00404 if (d->widget->isWidget()) {
00405 QGraphicsWidget *graphicsWidget = static_cast<QGraphicsWidget*>(d->widget);
00406 min = graphicsWidget->minimumSize();
00407 pref = graphicsWidget->preferredSize();
00408 max = graphicsWidget->maximumSize();
00409 } else {
00410 min = d->widget->boundingRect().size();
00411 pref = d->widget->boundingRect().size();
00412 max = d->widget->boundingRect().size();
00413 }
00414
00415 if (collapsed) {
00416 setPreferredSize(QSizeF(pref.width() + marginWidth,
00417 d->dragHandleRect().height() + marginHeight));
00418 setMinimumSize(QSizeF(min.width() + marginWidth,
00419 d->dragHandleRect().height() + marginHeight));
00420 setMaximumSize(QSizeF(max.width() + marginWidth,
00421 d->dragHandleRect().height() + marginHeight));
00422 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00423
00424 if (d->collapseIcon) {
00425 d->collapseIcon->setToolTip(i18n("Expand this widget"));
00426 }
00427 } else {
00428 setPreferredSize(QSizeF(pref.width() + marginWidth,
00429 pref.height() + d->dragHandleRect().height() + marginHeight));
00430 setMinimumSize(QSizeF(min.width() + marginWidth,
00431 min.height() + d->dragHandleRect().height() + marginHeight));
00432 setMaximumSize(QSizeF(max.width() + marginWidth,
00433 max.height() + d->dragHandleRect().height() + marginHeight));
00434
00435 if (d->widget->isWidget()) {
00436 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
00437 } else {
00438 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00439 }
00440
00441 if (d->collapseIcon) {
00442 d->collapseIcon->setToolTip(i18n("Collapse this widget"));
00443 }
00444 }
00445
00446 updateGeometry();
00447 d->extender->d->adjustSizeHints();
00448 }
00449
00450 void ExtenderItem::returnToSource()
00451 {
00452 if (!d->sourceApplet) {
00453 return;
00454 }
00455 setExtender(d->sourceApplet->d->extender);
00456 }
00457
00458 void ExtenderItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
00459 QWidget *widget)
00460 {
00461 Q_UNUSED(option);
00462 Q_UNUSED(widget);
00463
00464 painter->setRenderHint(QPainter::TextAntialiasing, true);
00465 painter->setRenderHint(QPainter::Antialiasing, true);
00466
00467 if (d->background->enabledBorders() != (FrameSvg::LeftBorder | FrameSvg::RightBorder) &&
00468 d->background->enabledBorders()) {
00469
00470
00471 d->background->paintFrame(painter, QPointF(0, 0));
00472 }
00473
00474 d->dragger->paintFrame(painter, QPointF(d->bgLeft, d->bgTop));
00475
00476
00477 if (d->title.isEmpty()) {
00478 return;
00479 }
00480
00481
00482 Plasma::Theme *theme = Plasma::Theme::defaultTheme();
00483 QFont font = theme->font(Plasma::Theme::DefaultFont);
00484 font.setWeight(QFont::Bold);
00485
00486
00487 QRectF rect = QRectF(d->titleRect().width() - 30, 0, 30, d->titleRect().height());
00488
00489 QPixmap pixmap(d->titleRect().size().toSize());
00490 pixmap.fill(Qt::transparent);
00491
00492 QPainter p(&pixmap);
00493 p.setPen(theme->color(Plasma::Theme::TextColor));
00494 p.setFont(font);
00495 p.drawText(QRectF(QPointF(0, 0), d->titleRect().size()),
00496 Qt::TextSingleLine | Qt::AlignVCenter | Qt::AlignLeft,
00497 d->title);
00498
00499
00500 QLinearGradient alphaGradient(0, 0, 1, 0);
00501 alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
00502
00503 alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
00504 alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
00505
00506 p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00507 p.fillRect(rect, alphaGradient);
00508
00509 p.end();
00510
00511 painter->drawPixmap(d->titleRect().topLeft(), pixmap);
00512 }
00513
00514 void ExtenderItem::moveEvent(QGraphicsSceneMoveEvent *event)
00515 {
00516 Q_UNUSED(event);
00517
00518 if (d->toplevel) {
00519 d->toplevel->setSceneRect(sceneBoundingRect());
00520 d->toplevel->setMask(d->background->mask());
00521 }
00522 }
00523
00524 void ExtenderItem::resizeEvent(QGraphicsSceneResizeEvent *event)
00525 {
00526 d->resizeContent(event->newSize());
00527
00528 if (d->toplevel) {
00529 d->toplevel->setSceneRect(sceneBoundingRect());
00530 d->toplevel->setMask(d->background->mask());
00531 }
00532 }
00533
00534 void ExtenderItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
00535 {
00536 if (!(d->dragHandleRect().contains(event->pos())) ||
00537 d->extender->d->applet->immutability() != Plasma::Mutable) {
00538 event->ignore();
00539 return;
00540 }
00541
00542 QApplication::setOverrideCursor(Qt::ClosedHandCursor);
00543
00544 d->mousePos = event->pos().toPoint();
00545 d->deltaScene = pos();
00546 d->mousePressed = true;
00547 }
00548
00549 void ExtenderItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
00550 {
00551 if (d->mousePressed && !d->dragStarted &&
00552 (d->mousePos - event->pos().toPoint()).manhattanLength() >= QApplication::startDragDistance()) {
00553
00554 d->dragStarted = true;
00555
00556
00557 d->hostApplet()->raise();
00558 setZValue(d->hostApplet()->zValue());
00559
00560 QPointF mousePos = d->scenePosFromScreenPos(event->screenPos());
00561 if (!mousePos.isNull()) {
00562 d->extender->itemHoverMoveEvent(this, d->extender->mapFromScene(mousePos));
00563 }
00564 d->extender->d->removeExtenderItem(this);
00565
00566 d->themeChanged();
00567 } else if (!d->dragStarted) {
00568 return;
00569 }
00570
00571
00572
00573 d->deltaScene += event->scenePos() - event->lastScenePos();
00574
00575
00576
00577 QRect screenRect = QRect();
00578 screenRect.setTopLeft(event->screenPos() - d->mousePos);
00579 screenRect.setSize(d->screenRect().size());
00580
00581 Corona *corona = d->hostApplet()->containment()->corona();
00582
00583 if (d->leaveCurrentView(screenRect)) {
00584
00585
00586
00587 if (!d->toplevel) {
00588
00589
00590 corona->addOffscreenWidget(this);
00591
00592 d->toplevel = new ExtenderItemView(scene(), 0);
00593
00594 d->toplevel->setWindowFlags(
00595 Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
00596 d->toplevel->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00597 d->toplevel->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00598 d->toplevel->setFrameShape(QFrame::NoFrame);
00599
00600 d->toplevel->setSceneRect(sceneBoundingRect());
00601 d->toplevel->setGeometry(screenRect);
00602 d->toplevel->setMask(d->background->mask());
00603
00604 d->toplevel->show();
00605 }
00606
00607 d->toplevel->setSceneRect(sceneBoundingRect());
00608 d->toplevel->setGeometry(screenRect);
00609 d->toplevel->setMask(d->background->mask());
00610 } else {
00611 corona->removeOffscreenWidget(this);
00612 setParentItem(d->hostApplet());
00613 setPos(d->deltaScene);
00614
00615
00616 delete d->toplevel;
00617 d->toplevel = 0;
00618 }
00619
00620
00621
00622
00623
00624 QPointF mousePos = d->scenePosFromScreenPos(event->screenPos());
00625
00626
00627 Extender *targetExtender = 0;
00628
00629 if (!mousePos.isNull()) {
00630 foreach (Containment *containment, corona->containments()) {
00631 foreach (Applet *applet, containment->applets()) {
00632 if (applet->d->extender &&
00633 (applet->sceneBoundingRect().contains(mousePos) ||
00634 applet->d->extender->sceneBoundingRect().contains(mousePos))) {
00635 targetExtender = applet->d->extender;
00636
00637
00638 PopupApplet *popupApplet = qobject_cast<PopupApplet*>(applet);
00639 if (popupApplet && (applet->formFactor() == Plasma::Horizontal ||
00640 applet->formFactor() == Plasma::Vertical)) {
00641 popupApplet->showPopup();
00642 }
00643 }
00644 }
00645
00646 if (containment->sceneBoundingRect().contains(mousePos) && !targetExtender) {
00647 containment->showDropZone(containment->mapFromScene(mousePos).toPoint());
00648 } else {
00649 containment->showDropZone(QPoint());
00650 }
00651 }
00652 }
00653
00654
00655 if (targetExtender != d->previousTargetExtender) {
00656 if (d->previousTargetExtender) {
00657 d->previousTargetExtender->itemHoverLeaveEvent(this);
00658 d->previousTargetExtender->disconnect(this, SIGNAL(destroyed(QObject*)));
00659 }
00660
00661 d->previousTargetExtender = targetExtender;
00662
00663
00664
00665 if (targetExtender) {
00666 connect(targetExtender, SIGNAL(destroyed(QObject*)),
00667 this, SLOT(previousTargetExtenderDestroyed(QObject*)));
00668 }
00669
00670 if (targetExtender) {
00671 targetExtender->itemHoverEnterEvent(this);
00672 }
00673 }
00674
00675
00676 if (targetExtender) {
00677 if (targetExtender->sceneBoundingRect().contains(mousePos)) {
00678 targetExtender->itemHoverMoveEvent(this, targetExtender->mapFromScene(mousePos));
00679 }
00680 }
00681 }
00682
00683 void ExtenderItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
00684 {
00685 if (d->titleRect().contains(event->pos())) {
00686 d->toggleCollapse();
00687 }
00688 }
00689
00690 void ExtenderItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
00691 {
00692 if (d->titleRect().contains(event->pos()) &&
00693 d->extender->d->applet->immutability() == Plasma::Mutable) {
00694 if (!d->mouseOver) {
00695 QApplication::setOverrideCursor(Qt::OpenHandCursor);
00696 d->mouseOver = true;
00697 }
00698 } else {
00699 if (d->mouseOver) {
00700 QApplication::restoreOverrideCursor();
00701 d->mouseOver = false;
00702 }
00703 }
00704 }
00705
00706 void ExtenderItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00707 {
00708 Q_UNUSED(event);
00709
00710 if (d->mouseOver) {
00711 QApplication::restoreOverrideCursor();
00712 d->mouseOver = false;
00713 }
00714 }
00715
00716 void ExtenderItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00717 {
00718 if (d->mousePressed) {
00719 QApplication::restoreOverrideCursor();
00720 }
00721
00722 d->mousePressed = false;
00723
00724 if (d->dragStarted) {
00725 d->dragStarted = false;
00726 d->previousTargetExtender = 0;
00727
00728
00729 if (d->toplevel) {
00730 delete d->toplevel;
00731 d->toplevel = 0;
00732 }
00733
00734
00735
00736
00737
00738 QPointF mousePos = d->scenePosFromScreenPos(event->screenPos());
00739
00740
00741 Extender *targetExtender = 0;
00742 Corona *corona = qobject_cast<Corona*>(d->extender->d->applet->scene());
00743
00744 corona->removeOffscreenWidget(this);
00745
00746 if (!mousePos.isNull()) {
00747 foreach (Containment *containment, corona->containments()) {
00748 containment->showDropZone(QPoint());
00749 foreach (Applet *applet, containment->applets()) {
00750 if (applet->d->extender &&
00751 (applet->sceneBoundingRect().contains(mousePos) ||
00752 applet->d->extender->sceneBoundingRect().contains(mousePos))) {
00753 targetExtender = applet->d->extender;
00754 }
00755 }
00756 }
00757 }
00758
00759
00760 if (targetExtender) {
00761 if (targetExtender->sceneBoundingRect().contains(mousePos)) {
00762 setExtender(targetExtender, targetExtender->mapFromScene(mousePos));
00763 } else {
00764 setExtender(targetExtender);
00765 }
00766 } else {
00767
00768 bool extenderCreated = false;
00769 mousePos = d->scenePosFromScreenPos(event->screenPos());
00770 if (!mousePos.isNull()) {
00771 foreach (Containment *containment, corona->containments()) {
00772 if (containment->sceneBoundingRect().contains(mousePos)) {
00773 kDebug() << "Instantiate a new ExtenderApplet";
00774
00775
00776
00777
00778 QPointF position;
00779 if (containment->type() == Plasma::Containment::DesktopContainment) {
00780 position = containment->mapFromScene(
00781 d->scenePosFromScreenPos(event->screenPos() - d->mousePos));
00782 } else {
00783 position = containment->mapFromScene(mousePos);
00784 }
00785
00786 Applet *applet = containment->addApplet("internal:extender",
00787 QVariantList(),
00788 QRectF(containment->mapFromScene(mousePos), size()));
00789
00790 if (applet) {
00791 setExtender(applet->d->extender);
00792 QSizeF margin = applet->size() - applet->contentsRect().size();
00793 applet->setMinimumSize(minimumSize() + margin);
00794 applet->setPreferredSize(preferredSize() + margin);
00795 applet->resize(preferredSize());
00796
00797 extenderCreated = true;
00798 } else {
00799 kDebug() << "Creating internal:extender applet failed, probably "
00800 << "because widgets are locked.";
00801 }
00802 }
00803 }
00804 }
00805
00806
00807
00808 if (!extenderCreated) {
00809 setExtender(extender());
00810 kDebug() << "Move the item back to where it came from.";
00811 }
00812 }
00813 }
00814 }
00815
00816 ExtenderItemPrivate::ExtenderItemPrivate(ExtenderItem *extenderItem, Extender *hostExtender)
00817 : q(extenderItem),
00818 widget(0),
00819 toolbox(0),
00820 toplevel(0),
00821 previousTargetExtender(0),
00822 extender(hostExtender),
00823 sourceApplet(0),
00824 dragger(new FrameSvg(extenderItem)),
00825 background(new FrameSvg(extenderItem)),
00826 collapseIcon(0),
00827 title(QString()),
00828 mousePressed(false),
00829 mouseOver(false),
00830 dragStarted(false),
00831 destroyActionVisibility(false),
00832 collapsed(false),
00833 expirationTimer(0)
00834 {
00835 dragLeft = dragTop = dragRight = dragBottom = 0;
00836 bgLeft = bgTop = bgRight = bgBottom = 0;
00837 }
00838
00839 ExtenderItemPrivate::~ExtenderItemPrivate()
00840 {
00841 delete widget;
00842 widget = 0;
00843 delete toplevel;
00844 }
00845
00846
00847 QRectF ExtenderItemPrivate::dragHandleRect()
00848 {
00849 QSizeF panelSize(QSizeF(q->size().width() - bgLeft - bgRight,
00850 iconSize() + dragTop + dragBottom));
00851 return QRectF(QPointF(bgLeft, bgTop), panelSize);
00852 }
00853
00854 QRectF ExtenderItemPrivate::titleRect()
00855 {
00856 return dragHandleRect().adjusted(dragLeft + collapseIcon->size().width() + 1, dragTop,
00857 -toolbox->size().width() - dragRight, -dragBottom);
00858 }
00859
00860 bool ExtenderItemPrivate::leaveCurrentView(const QRect &rect)
00861 {
00862 if ((q->sceneBoundingRect().left() < 0)) {
00863
00864
00865
00866 return true;
00867 }
00868
00869 foreach (QWidget *widget, QApplication::topLevelWidgets()) {
00870 if (widget->geometry().intersects(rect) && widget->isVisible() && widget != toplevel) {
00871
00872
00873 QGraphicsView *v = qobject_cast<QGraphicsView*>(widget);
00874 QGraphicsView *currentV = 0;
00875
00876 if (hostApplet()) {
00877 currentV = qobject_cast<QGraphicsView*>(hostApplet()->containment()->view());
00878 }
00879
00880 if (v && v != currentV) {
00881 return true;
00882 }
00883 }
00884 }
00885
00886 return false;
00887 }
00888
00889 QRect ExtenderItemPrivate::screenRect()
00890 {
00891 return hostApplet()->containment()->view()
00892 ->mapFromScene(q->sceneBoundingRect()).boundingRect();
00893 }
00894
00895 void ExtenderItemPrivate::toggleCollapse()
00896 {
00897 q->setCollapsed(!q->isCollapsed());
00898 }
00899
00900 void ExtenderItemPrivate::updateToolBox()
00901 {
00902 Q_ASSERT(toolbox);
00903 Q_ASSERT(dragger);
00904 Q_ASSERT(toolboxLayout);
00905
00906 uint iconHeight = iconSize();
00907
00908
00909 while (toolboxLayout->count()) {
00910 QGraphicsLayoutItem *icon = toolboxLayout->itemAt(0);
00911 QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget*>(icon);
00912 widget->deleteLater();
00913 toolboxLayout->removeAt(0);
00914 }
00915
00916
00917 foreach (QAction *action, actionsInOrder) {
00918 if (action->isVisible()) {
00919 IconWidget *icon = new IconWidget(q);
00920 icon->setAction(action);
00921 QSizeF iconSize = icon->sizeFromIconSize(iconHeight);
00922 icon->setMinimumSize(iconSize);
00923 icon->setMaximumSize(iconSize);
00924 toolboxLayout->addItem(icon);
00925 }
00926 }
00927
00928
00929 if (q->isDetached() && sourceApplet) {
00930 IconWidget *returnToSource = new IconWidget(q);
00931 returnToSource->setSvg("widgets/configuration-icons", "return-to-source");
00932 QSizeF iconSize = returnToSource->sizeFromIconSize(iconHeight);
00933 returnToSource->setMinimumSize(iconSize);
00934 returnToSource->setMaximumSize(iconSize);
00935
00936 toolboxLayout->addItem(returnToSource);
00937 QObject::connect(returnToSource, SIGNAL(clicked()), q, SLOT(returnToSource()));
00938 }
00939
00940
00941 if (destroyActionVisibility) {
00942 IconWidget *destroyAction = new IconWidget(q);
00943 destroyAction->setSvg("widgets/configuration-icons", "close");
00944 QSizeF iconSize = destroyAction->sizeFromIconSize(iconHeight);
00945 destroyAction->setMinimumSize(iconSize);
00946 destroyAction->setMaximumSize(iconSize);
00947
00948 toolboxLayout->addItem(destroyAction);
00949 QObject::connect(destroyAction, SIGNAL(clicked()), q, SLOT(destroy()));
00950 }
00951
00952 toolboxLayout->updateGeometry();
00953
00954
00955 QSizeF minimum = toolboxLayout->minimumSize();
00956 toolbox->resize(minimum);
00957 repositionToolbox();
00958 }
00959
00960 void ExtenderItemPrivate::repositionToolbox()
00961 {
00962 QSizeF minimum = toolboxLayout->minimumSize();
00963 toolbox->setPos(q->size().width() - minimum.width() - bgRight,
00964 (dragHandleRect().height()/2) -
00965 (minimum.height()/2) + bgTop);
00966 }
00967
00968
00969 QPointF ExtenderItemPrivate::scenePosFromScreenPos(const QPoint &pos) const
00970 {
00971
00972
00973 QList<WId> order = KWindowSystem::stackingOrder();
00974 if (toplevel) {
00975 order.removeOne(toplevel->winId());
00976 }
00977
00978 QGraphicsView *found = 0;
00979 foreach (QWidget *w, QApplication::topLevelWidgets()) {
00980 QGraphicsView *v = 0;
00981
00982
00983 Dialog *dialog = qobject_cast<Dialog*>(w);
00984 if (dialog) {
00985 if (dialog->isVisible() && dialog->geometry().contains(pos)) {
00986 v = qobject_cast<QGraphicsView*>(dialog->layout()->itemAt(0)->widget());
00987 if (v) {
00988 return v->mapToScene(v->mapFromGlobal(pos));
00989 }
00990 }
00991 } else {
00992 v = qobject_cast<QGraphicsView *>(w);
00993 }
00994
00995
00996 if (v && w->isVisible() && w->geometry().contains(pos)) {
00997 if (found && order.contains(found->winId())) {
00998 if (order.indexOf(found->winId()) < order.indexOf(v->winId())) {
00999 found = v;
01000 }
01001 } else {
01002 found = v;
01003 }
01004 }
01005 }
01006
01007 if (!found) {
01008 return QPointF();
01009 }
01010
01011 return found->mapToScene(found->mapFromGlobal(pos));
01012 }
01013
01014 Applet *ExtenderItemPrivate::hostApplet() const
01015 {
01016 if (extender) {
01017 return extender->d->applet;
01018 } else {
01019 return 0;
01020 }
01021 }
01022
01023 void ExtenderItemPrivate::themeChanged()
01024 {
01025 background->setImagePath("widgets/extender-background");
01026 if (mousePressed) {
01027 background->setEnabledBorders(FrameSvg::AllBorders);
01028 } else {
01029 background->setEnabledBorders(extender->enabledBordersForItem(q));
01030 }
01031 background->getMargins(bgLeft, bgTop, bgRight, bgBottom);
01032
01033 dragger->setImagePath("widgets/extender-dragger");
01034 dragger->getMargins(dragLeft, dragTop, dragRight, dragBottom);
01035
01036 QSizeF panelSize(QSizeF(q->size().width() - bgLeft - bgRight,
01037 iconSize() + dragTop + dragBottom));
01038
01039
01040 collapseIcon->resize(collapseIcon->sizeFromIconSize(iconSize()));
01041
01042
01043 collapseIcon->setPos(bgLeft + dragLeft,
01044 panelSize.height()/2 -
01045 collapseIcon->size().height()/2 + bgTop);
01046
01047
01048 if (widget) {
01049 widget->setPos(QPointF(bgLeft + dragLeft, panelSize.height() +
01050 bgTop + dragTop));
01051 }
01052
01053
01054 repositionToolbox();
01055
01056
01057 q->setCollapsed(q->isCollapsed());
01058
01059 if (!q->size().isEmpty())
01060 resizeContent(q->size());
01061 }
01062
01063 void ExtenderItemPrivate::sourceAppletRemoved()
01064 {
01065
01066
01067 sourceApplet = 0;
01068 updateToolBox();
01069 }
01070
01071 qreal ExtenderItemPrivate::iconSize()
01072 {
01073
01074 QSizeF size = dragger->elementSize("hint-preferred-icon-size");
01075 size = size.expandedTo(QSizeF(16,16));
01076
01077
01078 Plasma::Theme *theme = Plasma::Theme::defaultTheme();
01079 QFont font = theme->font(Plasma::Theme::DefaultFont);
01080 QFontMetrics fm(font);
01081
01082 return qMax(size.height(), (qreal) fm.height());
01083 }
01084
01085 void ExtenderItemPrivate::resizeContent(const QSizeF &newSize)
01086 {
01087 qreal width = newSize.width();
01088 qreal height = newSize.height();
01089
01090
01091 dragger->resizeFrame(QSizeF(width - bgLeft - bgRight,
01092 iconSize() + dragTop + dragBottom));
01093
01094
01095 background->resizeFrame(newSize);
01096
01097
01098 if (widget && widget->isWidget()) {
01099 QSizeF newWidgetSize(width - bgLeft - bgRight - dragLeft - dragRight,
01100 height - dragHandleRect().height() - bgTop - bgBottom -
01101 2 * dragTop - 2 * dragBottom);
01102
01103 QGraphicsWidget *graphicsWidget = static_cast<QGraphicsWidget*>(widget);
01104 graphicsWidget->resize(newWidgetSize);
01105 }
01106
01107
01108 repositionToolbox();
01109
01110 q->update();
01111 }
01112
01113 void ExtenderItemPrivate::previousTargetExtenderDestroyed(QObject *o)
01114 {
01115 Q_UNUSED(o)
01116 previousTargetExtender = 0;
01117 }
01118
01119 void ExtenderItemPrivate::actionDestroyed(QObject *o)
01120 {
01121 QAction *action = static_cast<QAction *>(o);
01122 QMutableHashIterator<QString, QAction *> hit(actions);
01123 while (hit.hasNext()) {
01124 if (hit.next().value() == action) {
01125 hit.remove();
01126 break;
01127 }
01128 }
01129
01130 QMutableListIterator<QAction *> lit(actionsInOrder);
01131 while (lit.hasNext()) {
01132 if (lit.next() == action) {
01133 lit.remove();
01134 break;
01135 }
01136 }
01137 }
01138
01139 uint ExtenderItemPrivate::s_maxExtenderItemId = 0;
01140
01141 }
01142
01143 #include "extenderitem.moc"