1/*
2 * Copyright 2008 by Alessandro Diaferia <alediaferia@gmail.com>
3 * Copyright 2007 by Alexis Ménard <darktears31@gmail.com>
4 * Copyright 2007 Sebastian Kuegler <sebas@kde.org>
5 * Copyright 2006 Aaron Seigo <aseigo@kde.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301 USA
21 */
22
23#include "dialog.h"
24#include "private/dialog_p.h"
25
26#include <QPainter>
27#include <QSvgRenderer>
28#include <QResizeEvent>
29#include <QMouseEvent>
30#ifdef Q_WS_X11
31#include <QX11Info>
32#endif
33#include <QBitmap>
34#include <QTimer>
35#include <QtGui/QVBoxLayout>
36#include <QtGui/QGraphicsSceneEvent>
37#include <QtGui/QGraphicsView>
38#include <QtGui/QGraphicsWidget>
39#include <QApplication>
40#include <QDesktopWidget>
41#include <QVarLengthArray>
42#include <QGraphicsLayout>
43
44#include <kdebug.h>
45#include <kwindowsystem.h>
46#include <netwm.h>
47
48#include "plasma/applet.h"
49#include "plasma/animator.h"
50#include "plasma/containment.h"
51#include "plasma/corona.h"
52#include "plasma/extenders/extender.h"
53#include "plasma/private/extender_p.h"
54#include "plasma/private/dialogshadows_p.h"
55#include "plasma/framesvg.h"
56#include "plasma/theme.h"
57#include "plasma/widgets/scrollwidget.h"
58#include "plasma/windoweffects.h"
59
60#ifdef Q_WS_X11
61#include <X11/Xlib.h>
62#endif
63
64namespace Plasma
65{
66
67void DialogPrivate::scheduleBorderCheck(bool triggeredByResize)
68{
69 //kDebug();
70 if (triggeredByResize) {
71 resizeChecksWithBorderCheck = true;
72
73 // to keep the UI as fluid as possible, we call checkBorders
74 // immediately when there is a resize, and therefore stop any
75 // move-triggered scheduled calls to it. this keeps things
76 // looking reasonable during resize while avoiding as many
77 // calls to checkBorders as possible
78 if (moveTimer) {
79 moveTimer->stop();
80 }
81
82 checkBorders();
83 return;
84 }
85
86 if (!moveTimer) {
87 moveTimer = new QTimer(q);
88 moveTimer->setSingleShot(true);
89 QObject::connect(moveTimer, SIGNAL(timeout()), q, SLOT(checkBorders()));
90 }
91
92 moveTimer->start(0);
93}
94
95void DialogPrivate::themeChanged()
96{
97 checkBorders(false);
98
99 const bool translucency = Plasma::Theme::defaultTheme()->windowTranslucencyEnabled();
100 // WA_NoSystemBackground is going to fail combined with sliding popups, but is needed
101 // when we aren't compositing
102 q->setAttribute(Qt::WA_NoSystemBackground, !translucency);
103 WindowEffects::overrideShadow(q->winId(), !DialogShadows::self()->enabled());
104 updateMask();
105 q->update();
106}
107
108void DialogPrivate::updateMask()
109{
110 const bool translucency = Plasma::Theme::defaultTheme()->windowTranslucencyEnabled();
111 WindowEffects::enableBlurBehind(q->winId(), translucency,
112 translucency ? background->mask() : QRegion());
113 if (translucency) {
114 q->clearMask();
115 } else {
116 q->setMask(background->mask());
117 }
118}
119
120void DialogPrivate::checkBorders()
121{
122 checkBorders(true);
123}
124
125void DialogPrivate::delayedAdjustSize()
126{
127 q->syncToGraphicsWidget();
128}
129
130void DialogPrivate::checkBorders(bool updateMaskIfNeeded)
131{
132 if (resizeChecksWithBorderCheck) {
133 background->resizeFrame(q->size());
134 }
135
136 QGraphicsWidget *graphicsWidget = graphicsWidgetPtr.data();
137 const FrameSvg::EnabledBorders currentBorders = background->enabledBorders();
138 FrameSvg::EnabledBorders borders = FrameSvg::AllBorders;
139
140 Extender *extender = qobject_cast<Extender*>(graphicsWidget);
141 Plasma::Applet *applet = appletPtr.data();
142
143 //used to remove borders at the edge of the desktop
144 QRegion avail;
145 QRect screenGeom;
146 QDesktopWidget *desktop = QApplication::desktop();
147 Plasma::Corona *c = 0;
148 if (applet) {
149 c = qobject_cast<Plasma::Corona *>(applet->scene());
150 } else if (graphicsWidget) {
151 c = qobject_cast<Plasma::Corona *>(graphicsWidget->scene());
152 }
153 if (c) {
154 avail = c->availableScreenRegion(desktop->screenNumber(q));
155 screenGeom = c->screenGeometry(desktop->screenNumber(q));
156 } else {
157 avail = QRegion(desktop->availableGeometry(desktop->screenNumber(q)));
158 screenGeom = desktop->screenGeometry(desktop->screenNumber(q));
159 }
160
161 QRect dialogGeom = q->geometry();
162
163 qreal topHeight(0);
164 qreal leftWidth(0);
165 qreal rightWidth(0);
166 qreal bottomHeight(0);
167
168 //decide about disabling the border attached to the panel
169 //don't cut borders on tooltips
170 if (applet && !q->testAttribute(Qt::WA_X11NetWmWindowTypeToolTip)) {
171 background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight);
172
173 switch (applet->location()) {
174 case BottomEdge:
175 if (applet->containment() &&
176 dialogGeom.bottom() + 2 >= screenGeom.bottom() - applet->containment()->size().height() &&
177 dialogGeom.width() <= applet->containment()->size().width()) {
178 borders &= ~FrameSvg::BottomBorder;
179 leftWidth = 0;
180 rightWidth = 0;
181 bottomHeight = 0;
182 }
183 break;
184
185 case TopEdge:
186 if (applet->containment() &&
187 dialogGeom.top() <= screenGeom.top() + applet->containment()->size().height() &&
188 dialogGeom.width() <= applet->containment()->size().width()) {
189 borders &= ~FrameSvg::TopBorder;
190 topHeight = 0;
191 leftWidth = 0;
192 rightWidth = 0;
193 }
194 break;
195
196 case LeftEdge:
197 if (applet->containment() &&
198 dialogGeom.left() <= screenGeom.left() + applet->containment()->size().width() &&
199 dialogGeom.height() <= applet->containment()->size().height()) {
200 borders &= ~FrameSvg::LeftBorder;
201 leftWidth = 0;
202 rightWidth = 0;
203 }
204 break;
205
206 case RightEdge:
207 if (applet->containment() &&
208 dialogGeom.right() + 2 >= screenGeom.right() - applet->containment()->size().width() &&
209 dialogGeom.height() <= applet->containment()->size().height()) {
210 borders &= ~FrameSvg::RightBorder;
211 leftWidth = 0;
212 rightWidth = 0;
213 }
214 break;
215
216 default:
217 break;
218 }
219 }
220
221 //decide if to disable the other borders
222 if (q->isVisible() && !q->testAttribute(Qt::WA_X11NetWmWindowTypeToolTip)) {
223 if (!avail.contains(QPoint(dialogGeom.left()-1, dialogGeom.center().y()))) {
224 borders &= ~FrameSvg::LeftBorder;
225 }
226 if (!avail.contains(QPoint(dialogGeom.center().x(), dialogGeom.top()-1))) {
227 borders &= ~FrameSvg::TopBorder;
228 }
229 //FIXME: that 2 pixels offset has probably something to do with kwin
230 if (!avail.contains(QPoint(dialogGeom.right()+1, dialogGeom.center().y()))) {
231 borders &= ~FrameSvg::RightBorder;
232 }
233 if (!avail.contains(QPoint(dialogGeom.center().x(), dialogGeom.bottom()+1))) {
234 borders &= ~FrameSvg::BottomBorder;
235 }
236 }
237
238 background->setEnabledBorders(borders);
239 DialogShadows::self()->addWindow(q, borders);
240
241 if (extender) {
242 FrameSvg::EnabledBorders disabledBorders = FrameSvg::NoBorder;
243 if (!(borders & FrameSvg::LeftBorder)) {
244 disabledBorders |= FrameSvg::LeftBorder;
245 }
246 if (!(borders & FrameSvg::RightBorder)) {
247 disabledBorders |= FrameSvg::RightBorder;
248 }
249 extender->d->setDisabledBordersHint(disabledBorders);
250
251 //if there is a scrollbar, reserve a margin to not draw it over the shadow
252 qreal left, top, right, bottom;
253 background->getMargins(left, top, right, bottom);
254 if (extender->d->scrollWidget->viewportGeometry().height() < extender->d->scrollWidget->contentsSize().height()) {
255 if (QApplication::layoutDirection() == Qt::RightToLeft) {
256 leftWidth = left;
257 } else {
258 rightWidth = right;
259 }
260 }
261 } else {
262 background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight);
263 }
264
265 //kDebug() << leftWidth << topHeight << rightWidth << bottomHeight;
266 q->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
267
268 if (resizeChecksWithBorderCheck) {
269 updateResizeCorners();
270 updateMask();
271 q->update();
272 } else if (currentBorders != borders) {
273 if (updateMaskIfNeeded) {
274 updateMask();
275 }
276
277 q->update();
278 }
279
280 resizeChecksWithBorderCheck = false;
281}
282
283void Dialog::syncToGraphicsWidget()
284{
285 d->adjustViewTimer->stop();
286 QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data();
287 if (d->view && graphicsWidget && d->resizeStartCorner != -1) {
288 const int prevStartCorner = d->resizeStartCorner;
289 d->resizeStartCorner = -1;
290 QSize prevSize = size();
291 /*
292 kDebug() << "Widget size:" << graphicsWidget->size()
293 << "| Widget size hint:" << graphicsWidget->effectiveSizeHint(Qt::PreferredSize)
294 << "| Widget minsize hint:" << graphicsWidget->minimumSize()
295 << "| Widget maxsize hint:" << graphicsWidget->maximumSize()
296 << "| Widget bounding rect:" << graphicsWidget->sceneBoundingRect();
297 */
298 //set the sizehints correctly:
299 int left, top, right, bottom;
300 getContentsMargins(&left, &top, &right, &bottom);
301
302 QDesktopWidget *desktop = QApplication::desktop();
303 QSize maxSize = desktop->availableGeometry(desktop->screenNumber(this)).size();
304
305 setMinimumSize(0, 0);
306 setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
307
308 QSize newSize(qMin(int(graphicsWidget->size().width()) + left + right, maxSize.width()),
309 qMin(int(graphicsWidget->size().height()) + top + bottom, maxSize.height()));
310
311 const QSizeF minimum = graphicsWidget->effectiveSizeHint(Qt::MinimumSize);
312 QSize newMinimumSize(qMin(int(minimum.width()) + left + right, maxSize.width()),
313 qMin(int(minimum.height()) + top + bottom, maxSize.height()));
314
315
316 QSize newMaximumSize(qMin(int(graphicsWidget->maximumSize().width()) + left + right, maxSize.width()),
317 qMin(int(graphicsWidget->maximumSize().height()) + top + bottom, maxSize.height()));
318
319
320 Plasma::Applet *applet = d->appletPtr.data();
321 if (applet) {
322 QRect currentGeometry(geometry());
323 currentGeometry.setSize(newSize);
324 if (applet->location() == Plasma::TopEdge ||
325 applet->location() == Plasma::LeftEdge) {
326 currentGeometry.setSize(newSize);
327 } else if (applet->location() == Plasma::RightEdge) {
328 currentGeometry.moveTopRight(geometry().topRight());
329 //BottomEdge and floating
330 } else {
331 currentGeometry.moveBottomLeft(geometry().bottomLeft());
332 }
333 setGeometry(currentGeometry);
334 } else {
335 resize(newSize);
336 }
337
338 setMinimumSize(newMinimumSize);
339 setMaximumSize(newMaximumSize);
340
341
342 updateGeometry();
343
344 //reposition and resize the view.
345 //force a valid rect, otherwise it will take up the whole scene
346 QRectF sceneRect(graphicsWidget->sceneBoundingRect());
347
348 sceneRect.setWidth(qMax(qreal(1), sceneRect.width()));
349 sceneRect.setHeight(qMax(qreal(1), sceneRect.height()));
350 d->view->setSceneRect(sceneRect);
351
352 //d->view->resize(graphicsWidget->size().toSize());
353 d->view->centerOn(graphicsWidget);
354
355 if (size() != prevSize) {
356 //the size of the dialog has changed, emit the signal:
357 emit dialogResized();
358 }
359
360 d->resizeStartCorner = prevStartCorner;
361 }
362}
363
364int DialogPrivate::calculateWidthForHeightAndRatio(int height, qreal ratio)
365{
366 switch (aspectRatioMode) {
367 case KeepAspectRatio:
368 return qRound(height * ratio);
369 break;
370 case Square:
371 return height;
372 break;
373 case ConstrainedSquare:
374 return height;
375 break;
376 default:
377 return -1;
378 }
379}
380
381Dialog::Dialog(QWidget *parent, Qt::WindowFlags f)
382 : QWidget(parent, f | Qt::FramelessWindowHint),
383 d(new DialogPrivate(this))
384{
385 setMouseTracking(true);
386 setAttribute(Qt::WA_TranslucentBackground);
387 d->background = new FrameSvg(this);
388 d->background->setImagePath("dialogs/background");
389 d->background->setEnabledBorders(FrameSvg::AllBorders);
390 d->background->resizeFrame(size());
391 connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(themeChanged()));
392
393 QPalette pal = palette();
394 pal.setColor(backgroundRole(), Qt::transparent);
395 setPalette(pal);
396 WindowEffects::overrideShadow(winId(), !DialogShadows::self()->enabled());
397
398 d->adjustViewTimer = new QTimer(this);
399 d->adjustViewTimer->setSingleShot(true);
400 connect(d->adjustViewTimer, SIGNAL(timeout()), this, SLOT(syncToGraphicsWidget()));
401
402 d->adjustSizeTimer = new QTimer(this);
403 d->adjustSizeTimer->setSingleShot(true);
404 connect(d->adjustSizeTimer, SIGNAL(timeout()), this, SLOT(delayedAdjustSize()));
405
406 d->themeChanged();
407}
408
409Dialog::~Dialog()
410{
411 DialogShadows::self()->removeWindow(this);
412 delete d;
413}
414
415void Dialog::paintEvent(QPaintEvent *e)
416{
417 QPainter p(this);
418 p.setCompositionMode(QPainter::CompositionMode_Source);
419 d->background->paintFrame(&p, e->rect(), e->rect());
420}
421
422void Dialog::mouseMoveEvent(QMouseEvent *event)
423{
424 if (event->modifiers() == Qt::AltModifier) {
425 unsetCursor();
426 } else if (d->resizeAreas[Dialog::NorthEast].contains(event->pos())) {
427 setCursor(Qt::SizeBDiagCursor);
428 } else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos())) {
429 setCursor(Qt::SizeFDiagCursor);
430 } else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos())) {
431 setCursor(Qt::SizeFDiagCursor);
432 } else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos())) {
433 setCursor(Qt::SizeBDiagCursor);
434 } else if (!(event->buttons() & Qt::LeftButton)) {
435 unsetCursor();
436 }
437
438 // here we take care of resize..
439 if (d->resizeStartCorner != Dialog::NoCorner) {
440 int newWidth;
441 int newHeight;
442 QPoint position;
443
444 qreal aspectRatio = (qreal)width() / (qreal)height();
445
446 switch(d->resizeStartCorner) {
447 case Dialog::NorthEast:
448 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height() - event->y()));
449 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
450 if (newWidth == -1) {
451 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), event->x()));
452 }
453 position = QPoint(x(), y() + height() - newHeight);
454 break;
455 case Dialog::NorthWest:
456 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height() - event->y()));
457 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
458 if (newWidth == -1) {
459 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width() - event->x()));
460 }
461 position = QPoint(x() + width() - newWidth, y() + height() - newHeight);
462 break;
463 case Dialog::SouthWest:
464 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), event->y()));
465 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
466 if (newWidth == -1) {
467 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width() - event->x()));
468 }
469 position = QPoint(x() + width() - newWidth, y());
470 break;
471 case Dialog::SouthEast:
472 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), event->y()));
473 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
474 if (newWidth == -1) {
475 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), event->x()));
476 }
477 position = QPoint(x(), y());
478 break;
479 default:
480 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height()));
481 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio);
482 if (newWidth == -1) {
483 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width()));
484 }
485 position = QPoint(x(), y());
486 break;
487 }
488
489 QRect newGeom(position, QSize(newWidth, newHeight));
490
491 // now sanity check the resize results again min constraints, if any
492 if (d->leftResizeMin > -1 && newGeom.left() > d->leftResizeMin) {
493 newGeom.setLeft(d->leftResizeMin);
494 }
495
496 if (d->topResizeMin > -1 && newGeom.top() > d->topResizeMin) {
497 newGeom.setTop(d->topResizeMin);
498 }
499
500 if (d->rightResizeMin > -1 && newGeom.right() < d->rightResizeMin) {
501 newGeom.setRight(d->rightResizeMin);
502 }
503
504 if (d->bottomResizeMin > -1 && newGeom.bottom() < d->bottomResizeMin) {
505 newGeom.setBottom(d->bottomResizeMin);
506 }
507
508 if ((newGeom.width() >= minimumSize().width()) && (newGeom.height() >= minimumSize().height())) {
509 setGeometry(newGeom);
510 }
511 }
512
513 QWidget::mouseMoveEvent(event);
514}
515
516void Dialog::mousePressEvent(QMouseEvent *event)
517{
518 if (d->resizeAreas[Dialog::NorthEast].contains(event->pos())) {
519 d->resizeStartCorner = Dialog::NorthEast;
520 } else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos())) {
521 d->resizeStartCorner = Dialog::NorthWest;
522 } else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos())) {
523 d->resizeStartCorner = Dialog::SouthEast;
524 } else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos())) {
525 d->resizeStartCorner = Dialog::SouthWest;
526 } else {
527 d->resizeStartCorner = Dialog::NoCorner;
528 }
529
530 QWidget::mousePressEvent(event);
531}
532
533void Dialog::mouseReleaseEvent(QMouseEvent *event)
534{
535 if (d->resizeStartCorner != Dialog::NoCorner) {
536 emit dialogResized();
537 d->resizeStartCorner = Dialog::NoCorner;
538 unsetCursor();
539 }
540
541 QWidget::mouseReleaseEvent(event);
542}
543
544void Dialog::keyPressEvent(QKeyEvent *event)
545{
546 if (event->key() == Qt::Key_Escape) {
547 hide();
548 }
549}
550
551bool Dialog::event(QEvent *event)
552{
553 return QWidget::event(event);
554}
555
556void Dialog::resizeEvent(QResizeEvent *event)
557{
558 Q_UNUSED(event)
559 //kDebug();
560 d->scheduleBorderCheck(true);
561
562 if (d->resizeStartCorner != -1 && d->view && d->graphicsWidgetPtr) {
563 QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data();
564 graphicsWidget->resize(d->view->size());
565
566 QRectF sceneRect(graphicsWidget->sceneBoundingRect());
567 sceneRect.setWidth(qMax(qreal(1), sceneRect.width()));
568 sceneRect.setHeight(qMax(qreal(1), sceneRect.height()));
569 d->view->setSceneRect(sceneRect);
570 d->view->centerOn(graphicsWidget);
571 }
572}
573
574void DialogPrivate::updateResizeCorners()
575{
576 const int resizeAreaMargin = 20;
577 const QRect r = q->rect();
578 const FrameSvg::EnabledBorders borders = background->enabledBorders();
579
580 // IMPLEMENTATION NOTE: we set resize corners for the corners set, but also
581 // for the complimentary corners if we've cut out an edge of our SVG background
582 // which implies we are up against an immovable edge (e.g. a screen edge)
583
584 resizeAreas.clear();
585 if (resizeCorners & Dialog::NorthEast ||
586 (resizeCorners & Dialog::NorthWest && !(borders & FrameSvg::LeftBorder)) ||
587 (resizeCorners & Dialog::SouthEast && !(borders & FrameSvg::BottomBorder))) {
588 resizeAreas[Dialog::NorthEast] = QRect(r.right() - resizeAreaMargin, 0,
589 resizeAreaMargin, resizeAreaMargin);
590 }
591
592 if (resizeCorners & Dialog::NorthWest ||
593 (resizeCorners & Dialog::NorthEast && !(borders & FrameSvg::RightBorder)) ||
594 (resizeCorners & Dialog::SouthWest && !(borders & FrameSvg::BottomBorder))) {
595 resizeAreas[Dialog::NorthWest] = QRect(0, 0, resizeAreaMargin, resizeAreaMargin);
596 }
597
598 if (resizeCorners & Dialog::SouthEast ||
599 (resizeCorners & Dialog::SouthWest && !(borders & FrameSvg::LeftBorder)) ||
600 (resizeCorners & Dialog::NorthEast && !(borders & FrameSvg::TopBorder))) {
601 resizeAreas[Dialog::SouthEast] = QRect(r.right() - resizeAreaMargin,
602 r.bottom() - resizeAreaMargin,
603 resizeAreaMargin, resizeAreaMargin);
604 }
605
606 if (resizeCorners & Dialog::SouthWest ||
607 (resizeCorners & Dialog::SouthEast && !(borders & FrameSvg::RightBorder)) ||
608 (resizeCorners & Dialog::NorthWest && !(borders & FrameSvg::TopBorder))) {
609 resizeAreas[Dialog::SouthWest] = QRect(0, r.bottom() - resizeAreaMargin,
610 resizeAreaMargin, resizeAreaMargin);
611 }
612}
613
614void Dialog::setGraphicsWidget(QGraphicsWidget *widget)
615{
616 if (d->graphicsWidgetPtr) {
617 d->graphicsWidgetPtr.data()->removeEventFilter(this);
618 }
619
620 d->graphicsWidgetPtr = widget;
621
622 if (widget) {
623 Plasma::Corona *c = qobject_cast<Plasma::Corona *>(widget->scene());
624 if (c) {
625 c->addOffscreenWidget(widget);
626 }
627
628 if (!layout()) {
629 QVBoxLayout *lay = new QVBoxLayout(this);
630 lay->setMargin(0);
631 lay->setSpacing(0);
632 }
633
634 d->checkBorders();
635
636 if (!d->view) {
637 d->view = new QGraphicsView(this);
638 d->view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
639 d->view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
640 d->view->setFrameShape(QFrame::NoFrame);
641 d->view->viewport()->setAutoFillBackground(false);
642 layout()->addWidget(d->view);
643 }
644
645 d->view->setScene(widget->scene());
646
647 //try to have the proper size -before- showing the dialog
648 d->view->centerOn(widget);
649 if (widget->layout()) {
650 widget->layout()->activate();
651 }
652 static_cast<QGraphicsLayoutItem *>(widget)->updateGeometry();
653 widget->resize(widget->size().expandedTo(widget->effectiveSizeHint(Qt::MinimumSize)));
654
655 syncToGraphicsWidget();
656
657 //d->adjustSizeTimer->start(150);
658
659 widget->installEventFilter(this);
660 d->view->installEventFilter(this);
661 } else {
662 delete d->view;
663 d->view = 0;
664 }
665}
666
667//KDE5 FIXME: should be const
668QGraphicsWidget *Dialog::graphicsWidget()
669{
670 return d->graphicsWidgetPtr.data();
671}
672
673bool Dialog::eventFilter(QObject *watched, QEvent *event)
674{
675 if (d->resizeStartCorner == Dialog::NoCorner && watched == d->graphicsWidgetPtr.data() &&
676 (event->type() == QEvent::GraphicsSceneResize || event->type() == QEvent::GraphicsSceneMove)) {
677 d->adjustViewTimer->start(150);
678 }
679
680 // when moving the cursor with a 45° angle from the outside
681 // to the inside passing over a resize angle the cursor changes its
682 // shape to a resize cursor. As a side effect this is the only case
683 // when the cursor immediately enters the view without giving
684 // the dialog the chance to restore the original cursor shape.
685 if (event->type() == QEvent::Enter && watched == d->view) {
686 unsetCursor();
687 }
688
689 return QWidget::eventFilter(watched, event);
690}
691
692void Dialog::hideEvent(QHideEvent * event)
693{
694 Q_UNUSED(event);
695 emit dialogVisible(false);
696}
697
698void Dialog::showEvent(QShowEvent * event)
699{
700 Q_UNUSED(event);
701
702 //check if the widget size is still synced with the view
703 d->checkBorders();
704 d->updateResizeCorners();
705
706 QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data();
707 if (graphicsWidget &&
708 ((d->view && graphicsWidget->size().toSize() != d->view->size()) ||
709 d->oldGraphicsWidgetMinimumSize != graphicsWidget->minimumSize() ||
710 d->oldGraphicsWidgetMaximumSize != graphicsWidget->maximumSize())) {
711 //here have to be done immediately, ideally should have to be done -before- shwing, but is not possible to catch show() so early
712 syncToGraphicsWidget();
713 d->oldGraphicsWidgetMinimumSize = graphicsWidget->minimumSize().toSize();
714 d->oldGraphicsWidgetMaximumSize = graphicsWidget->maximumSize().toSize();
715 }
716
717 if (d->view) {
718 d->view->setFocus();
719 }
720
721 if (graphicsWidget) {
722 graphicsWidget->setFocus();
723 }
724
725 emit dialogVisible(true);
726 WindowEffects::overrideShadow(winId(), !DialogShadows::self()->enabled());
727 DialogShadows::self()->addWindow(this, d->background->enabledBorders());
728}
729
730void Dialog::focusInEvent(QFocusEvent *event)
731{
732 Q_UNUSED(event)
733
734 if (d->view) {
735 d->view->setFocus();
736 }
737
738 QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data();
739 if (graphicsWidget) {
740 graphicsWidget->setFocus();
741 }
742}
743
744void Dialog::moveEvent(QMoveEvent *event)
745{
746 Q_UNUSED(event)
747 //kDebug();
748 d->scheduleBorderCheck();
749}
750
751void Dialog::setResizeHandleCorners(ResizeCorners corners)
752{
753 if ((d->resizeCorners != corners) && (aspectRatioMode() != FixedSize)) {
754 d->resizeCorners = corners;
755 d->updateResizeCorners();
756 }
757}
758
759Dialog::ResizeCorners Dialog::resizeCorners() const
760{
761 return d->resizeCorners;
762}
763
764bool Dialog::isUserResizing() const
765{
766 return d->resizeStartCorner > NoCorner;
767}
768
769void Dialog::setMinimumResizeLimits(int left, int top, int right, int bottom)
770{
771 d->leftResizeMin = left;
772 d->topResizeMin = top;
773 d->rightResizeMin = right;
774 d->bottomResizeMin = bottom;
775}
776
777void Dialog::getMinimumResizeLimits(int *left, int *top, int *right, int *bottom)
778{
779 if (left) {
780 *left = d->leftResizeMin;
781 }
782
783 if (top) {
784 *top = d->topResizeMin;
785 }
786
787 if (right) {
788 *right = d->rightResizeMin;
789 }
790
791 if (bottom) {
792 *bottom = d->bottomResizeMin;
793 }
794}
795
796void Dialog::animatedHide(Plasma::Direction direction)
797{
798 if (!isVisible()) {
799 return;
800 }
801
802 if (!Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
803 hide();
804 return;
805 }
806
807 Location location = Desktop;
808 switch (direction) {
809 case Down:
810 location = BottomEdge;
811 break;
812 case Right:
813 location = RightEdge;
814 break;
815 case Left:
816 location = LeftEdge;
817 break;
818 case Up:
819 location = TopEdge;
820 break;
821 default:
822 break;
823 }
824
825 Plasma::WindowEffects::slideWindow(this, location);
826 hide();
827}
828
829void Dialog::animatedShow(Plasma::Direction direction)
830{
831 if (!Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
832 show();
833 return;
834 }
835
836 //copied to not add new api
837 Location location = Desktop;
838 switch (direction) {
839 case Up:
840 location = BottomEdge;
841 break;
842 case Left:
843 location = RightEdge;
844 break;
845 case Right:
846 location = LeftEdge;
847 break;
848 case Down:
849 location = TopEdge;
850 break;
851 default:
852 break;
853 }
854
855 if (Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
856 Plasma::WindowEffects::slideWindow(this, location);
857 }
858
859 show();
860}
861
862bool Dialog::inControlArea(const QPoint &point)
863{
864 foreach (const QRect &r, d->resizeAreas) {
865 if (r.contains(point)) {
866 return true;
867 }
868 }
869 return false;
870}
871
872Plasma::AspectRatioMode Dialog::aspectRatioMode() const
873{
874 return d->aspectRatioMode;
875}
876
877void Dialog::setAspectRatioMode(Plasma::AspectRatioMode mode)
878{
879 if (mode == FixedSize) {
880 setResizeHandleCorners(NoCorner);
881 }
882
883 d->aspectRatioMode = mode;
884}
885
886}
887#include "dialog.moc"
888