File indexing completed on 2024-05-12 16:39:57

0001 /* This file is part of the KDE libraries
0002  *
0003  * Copyright (c) 2011 Aurélien Gâteau <agateau@kde.org>
0004  * Copyright (C) 2011-2013 Jarosław Staniek <staniek@kde.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public
0017  * License along with this library; if not, write to the Free Software
0018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0019  * 02110-1301  USA
0020  */
0021 #include "kmessagewidget.h"
0022 #include "kmessagewidget_p.h"
0023 
0024 #include "KexiCloseButton.h"
0025 #include "KexiIcon.h"
0026 #include <kexiutils/utils.h>
0027 
0028 #include <KColorScheme>
0029 #include <KStandardAction>
0030 #include <KStandardGuiItem>
0031 
0032 #include <QDebug>
0033 #include <QEvent>
0034 #include <QGridLayout>
0035 #include <QHBoxLayout>
0036 #include <QPainter>
0037 #include <QShowEvent>
0038 #include <QTimeLine>
0039 #include <QToolButton>
0040 #include <QPointer>
0041 #include <QPainterPath>
0042 #include <QTimer>
0043 #include <QAction>
0044 
0045 static const int LAYOUT_SPACING = 6;
0046 
0047 ClickableLabel::ClickableLabel(QWidget *parent)
0048  : QLabel(parent)
0049 {
0050 }
0051 
0052 ClickableLabel::~ClickableLabel()
0053 {
0054 }
0055 
0056 void ClickableLabel::mousePressEvent(QMouseEvent *ev)
0057 {
0058     if (ev->button() == Qt::LeftButton) {
0059         emit clicked();
0060     }
0061     QLabel::mousePressEvent(ev);
0062 }
0063 
0064 //---------------------------------------------------------------------
0065 // KMessageWidgetFrame
0066 //---------------------------------------------------------------------
0067 
0068 KMessageWidgetFrame::KMessageWidgetFrame(QWidget* parent)
0069  : QFrame(parent), radius(7),
0070    m_calloutPointerDirection(KMessageWidget::NoPointer),
0071    m_sizeForRecentTransformation(-1, -1),
0072    m_calloutPointerGlobalPosition(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX)
0073 {
0074     const qreal rad = radius;
0075     m_polyline << QPointF(0, 0)
0076                << QPointF(0, rad * 2.0) //<< QPointF(rad, rad * 2.0 - 0.5)
0077                << QPointF(rad * 2.0, 0);
0078     m_polygon << QPointF(m_polyline[0].x(), m_polyline[0].y() - 1)
0079               << QPointF(m_polyline[1].x(), m_polyline[1].y() - 1)
0080               << QPointF(m_polyline[2].x(), m_polyline[2].y() - 1);
0081 }
0082 
0083 void KMessageWidgetFrame::paintEvent(QPaintEvent* event)
0084 {
0085     QFrame::paintEvent(event);
0086     paintCalloutPointer();
0087 }
0088 
0089 KMessageWidget::CalloutPointerDirection KMessageWidgetFrame::calloutPointerDirection() const
0090 {
0091     return m_calloutPointerDirection;
0092 }
0093 
0094 void KMessageWidgetFrame::setCalloutPointerDirection(
0095     KMessageWidget::CalloutPointerDirection direction)
0096 {
0097     m_calloutPointerDirection = direction;
0098     m_sizeForRecentTransformation = QSize(-1, -1);
0099 }
0100 
0101 void KMessageWidgetFrame::updateCalloutPointerTransformation() const
0102 {
0103     if (m_sizeForRecentTransformation == parentWidget()->size())
0104         return;
0105 
0106     m_calloutPointerTransformation.reset();
0107 
0108     const QSizeF s(parentWidget()->size());
0109     m_sizeForRecentTransformation = parentWidget()->size();
0110     // qDebug() << size() << parentWidget()->size();
0111     const qreal rad = radius;
0112     // Original: [v    ]
0113     //           [     ]
0114     switch (m_calloutPointerDirection) {
0115     case KMessageWidget::Up:
0116         //  ^
0117         // [    ]
0118         m_calloutPointerTransformation
0119             .rotate(180.0)
0120             .translate(- rad * 5.0 + 0.5, - rad * 2 - 0.5)
0121             .scale(-1.0, 1.0);
0122         break;
0123     case KMessageWidget::Down:
0124         // [    ]
0125         //  v
0126         // No rotation needed, this is original position of polyline below
0127         m_calloutPointerTransformation
0128             .translate(rad * 3.0 + 0.5, s.height() - rad * 2);
0129         break;
0130     case KMessageWidget::Left:
0131         // <[     ]
0132         //  [     ]
0133         m_calloutPointerTransformation
0134             .rotate(90.0)
0135             .translate(rad * 1.5, - rad * 2 - 3.5);
0136         break;
0137     case KMessageWidget::Right:
0138         // [     ]>
0139         // [     ]
0140         m_calloutPointerTransformation
0141             .rotate(-90.0)
0142             .translate(- rad * 1.5, s.width() - rad * 2 - 3.5)
0143             .scale(-1.0, 1.0);
0144         break;
0145     default:
0146         break;
0147     }
0148 }
0149 
0150 void KMessageWidgetFrame::setCalloutPointerPosition(const QPoint& globalPos)
0151 {
0152     m_calloutPointerGlobalPosition = globalPos;
0153     updateCalloutPointerPosition();
0154 }
0155 
0156 QPoint KMessageWidgetFrame::calloutPointerPosition() const
0157 {
0158     return m_calloutPointerGlobalPosition;
0159 }
0160 
0161 void KMessageWidgetFrame::updateCalloutPointerPosition() const
0162 {
0163     if (m_calloutPointerGlobalPosition == QPoint(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX))
0164         return;
0165     QWidget *messageWidgetParent = parentWidget()->parentWidget();
0166     if (messageWidgetParent) {
0167 /*        qDebug() << "m_calloutPointerGlobalPosition:" << m_calloutPointerGlobalPosition
0168          << "pos():" << pos()
0169          << "pointerPosition():" << pointerPosition()
0170          << "(m_calloutPointerGlobalPosition - pos() - pointerPosition()):"
0171          << (m_calloutPointerGlobalPosition - pos() - pointerPosition())
0172          << "messageWidgetParent->mapFromGlobal():"
0173          << messageWidgetParent->mapFromGlobal(
0174               m_calloutPointerGlobalPosition - pos() - pointerPosition());*/
0175         parentWidget()->move(
0176             messageWidgetParent->mapFromGlobal(
0177                 m_calloutPointerGlobalPosition - pos() - pointerPosition())
0178         );
0179     }
0180 }
0181 
0182 void KMessageWidgetFrame::paintCalloutPointer()
0183 {
0184     updateCalloutPointerTransformation();
0185 
0186     if (m_calloutPointerTransformation.isIdentity())
0187         return;
0188     QPainter painter(this);
0189     painter.setTransform(m_calloutPointerTransformation);
0190 
0191     painter.setRenderHint(QPainter::Antialiasing);
0192     painter.setPen(QPen(bgBrush.color(), 1.0));
0193     painter.setBrush(bgBrush);
0194     painter.drawPolygon(m_polygon);
0195     painter.setPen(QPen(borderBrush, 1.0));
0196     painter.drawPolyline(m_polyline);
0197 }
0198 
0199 QPoint KMessageWidgetFrame::pointerPosition() const
0200 {
0201     updateCalloutPointerTransformation();
0202     //qDebug() << "MAPPED:" << t.map(polyline[1]) << mapToGlobal(t.map(polyline[1]).toPoint());
0203     return m_calloutPointerTransformation.map(m_polyline[1]).toPoint();
0204 }
0205 
0206 //---------------------------------------------------------------------
0207 // KMessageWidgetPrivate
0208 //---------------------------------------------------------------------
0209 class KMessageWidgetPrivate
0210 {
0211 public:
0212     KMessageWidgetPrivate();
0213     void init(KMessageWidget*);
0214 
0215     KMessageWidget* q;
0216     KMessageWidgetFrame* content;
0217     ClickableLabel* iconLabel;
0218     ClickableLabel* textLabel;
0219     KexiCloseButton* closeButton;
0220     QTimeLine* timeLine;
0221 
0222     KMessageWidget::MessageType messageType;
0223     bool wordWrap;
0224     QList<QToolButton*> buttons;
0225     QPixmap contentSnapShot;
0226     QAction* defaultAction;
0227     QPointer<QToolButton> defaultButton;
0228     QSet<QAction*> leftAlignedButtons;
0229     KColorScheme::ColorSet colorSet;
0230     KColorScheme::BackgroundRole bgRole;
0231     KColorScheme::ForegroundRole fgRole;
0232     bool autoDelete;
0233     QWidget* contentsWidget;
0234     bool clickClosesMessage;
0235     bool resizeToContentsOnTimeLineFinished;
0236 
0237     void createLayout();
0238     void updateSnapShot();
0239     void updateLayout();
0240     void updateStyleSheet();
0241 };
0242 
0243 KMessageWidgetPrivate::KMessageWidgetPrivate()
0244  : contentsWidget(0)
0245 {
0246 }
0247 
0248 void KMessageWidgetPrivate::init(KMessageWidget *q_ptr)
0249 {
0250     q = q_ptr;
0251 
0252     q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
0253 
0254     timeLine = new QTimeLine(500, q);
0255     QObject::connect(timeLine, SIGNAL(valueChanged(qreal)), q, SLOT(slotTimeLineChanged(qreal)));
0256     QObject::connect(timeLine, SIGNAL(finished()), q, SLOT(slotTimeLineFinished()));
0257 
0258     content = new KMessageWidgetFrame(q);
0259     content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
0260 
0261     wordWrap = false;
0262     resizeToContentsOnTimeLineFinished = false;
0263 
0264     if (contentsWidget) {
0265         iconLabel = 0;
0266         textLabel = 0;
0267     }
0268     else {
0269         iconLabel = new ClickableLabel(content);
0270         iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
0271         QObject::connect(iconLabel, SIGNAL(clicked()), q, SLOT(tryClickCloseMessage()));
0272 
0273         textLabel = new ClickableLabel(content);
0274         textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
0275         textLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0276         textLabel->setContentsMargins(0, 0, 0, 0);
0277         QObject::connect(textLabel, SIGNAL(clicked()), q, SLOT(tryClickCloseMessage()));
0278 #if 0
0279     content->setAutoFillBackground(true);
0280     content->setBackgroundRole(QPalette::Dark);
0281     textLabel->setAutoFillBackground(true);
0282     textLabel->setBackgroundRole(QPalette::Mid);
0283 #endif
0284     }
0285     closeButton = new KexiCloseButton(content);
0286     QObject::connect(closeButton, SIGNAL(clicked()), q, SLOT(animatedHide()));
0287 
0288     defaultAction = 0;
0289     autoDelete = false;
0290     clickClosesMessage = false;
0291     q->setMessageType(KMessageWidget::Information);
0292 }
0293 
0294 void KMessageWidgetPrivate::createLayout()
0295 {
0296     delete content->layout();
0297 
0298     content->resize(q->size());
0299 
0300     qDeleteAll(buttons);
0301     buttons.clear();
0302 
0303     QList<QToolButton*> buttonsTabOrder;
0304     Q_FOREACH(QAction* action, q->actions()) {
0305         QToolButton* button = new QToolButton(content);
0306         button->setDefaultAction(action);
0307         button->setFocusPolicy(Qt::StrongFocus);
0308         button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
0309         buttons.append(button);
0310         if (defaultAction == action) {
0311             buttonsTabOrder.prepend(button); // default button is focused first
0312             q->setFocusProxy(button);
0313             defaultButton = button;
0314         }
0315         else
0316             buttonsTabOrder.append(button);
0317     }
0318     QToolButton *previousButton = 0;
0319     Q_FOREACH(QToolButton* button, buttonsTabOrder) {
0320         if (previousButton)
0321             QWidget::setTabOrder(previousButton, button);
0322         previousButton = button;
0323     }
0324 
0325     // Only set autoRaise on if there are no buttons, otherwise the close
0326     // button looks weird
0327     //closeButton->setAutoRaise(buttons.isEmpty());
0328 
0329     QHBoxLayout* buttonLayout = 0;
0330     int leftContentSpacerItemWidth = LAYOUT_SPACING;
0331     int rightContentSpacerItemWidth = LAYOUT_SPACING;
0332     int bottomContentSpacerItemHeight = LAYOUT_SPACING;
0333     switch (content->calloutPointerDirection()) {
0334     case KMessageWidget::Up:
0335         break;
0336     case KMessageWidget::Down:
0337         bottomContentSpacerItemHeight = content->radius * 2 + LAYOUT_SPACING;
0338         break;
0339     case KMessageWidget::Left:
0340         leftContentSpacerItemWidth = content->radius * 2 + LAYOUT_SPACING;
0341         break;
0342     case KMessageWidget::Right:
0343         rightContentSpacerItemWidth = content->radius * 2 + LAYOUT_SPACING;
0344         break;
0345     default:;
0346     }
0347     if (wordWrap) {
0348         QGridLayout* layout = new QGridLayout(content);
0349         layout->setSpacing(LAYOUT_SPACING);
0350         if (contentsWidget) {
0351             layout->addItem(new QSpacerItem(leftContentSpacerItemWidth, LAYOUT_SPACING), 0, 0);
0352             layout->addWidget(contentsWidget, 1, 0, 1, 2);
0353             layout->addItem(new QSpacerItem(rightContentSpacerItemWidth, LAYOUT_SPACING), 3, 0);
0354 
0355 /*            if (contentsWidget->maximumWidth() < QWIDGETSIZE_MAX
0356                 && contentsWidget->maximumHeight() < QWIDGETSIZE_MAX
0357                 && contentsWidget->maximumSize() == contentsWidget->minimumSize())
0358             {
0359                 qDebug() << "contentsWidget->maximumSize():" << contentsWidget->maximumSize();
0360                 qDebug() << "content->size():" << content->size();
0361                 contentsWidget->setFixedSize(
0362                     contentsWidget->maximumSize() - QSize(120, 0));
0363                 //q->setFixedSize(
0364                 //    contentsWidget->maximumSize() + QSize(100, 0));
0365 
0366                 qFatal() << contentsWidget->maximumSize();
0367             }*/
0368         }
0369         else {
0370             layout->addItem(new QSpacerItem(leftContentSpacerItemWidth, LAYOUT_SPACING), 0, 0);
0371             layout->addWidget(iconLabel, 1, 1, Qt::AlignCenter | Qt::AlignTop);
0372             //iconLabel->setContentsMargins(0, LAYOUT_SPACING, 0, 0);
0373             iconLabel->setAlignment(Qt::AlignCenter | Qt::AlignTop);
0374             layout->addWidget(textLabel, 1, 2);
0375             textLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
0376             layout->addItem(new QSpacerItem(rightContentSpacerItemWidth, LAYOUT_SPACING), 0, 3);
0377         }
0378 
0379         buttonLayout = new QHBoxLayout;
0380         buttonLayout->setSpacing(LAYOUT_SPACING);
0381         bool stretchAdded = false;
0382         Q_FOREACH(QToolButton* button, buttons) {
0383             if (!stretchAdded && !leftAlignedButtons.contains(button->defaultAction())) {
0384                 buttonLayout->addStretch();
0385                 stretchAdded = true;
0386             }
0387             // For some reason, calling show() is necessary here, but not in
0388             // wordwrap mode
0389             button->show();
0390             buttonLayout->addWidget(button);
0391         }
0392         if (contentsWidget) {
0393             buttonLayout->addStretch();
0394             buttonLayout->addWidget(closeButton);
0395             buttonLayout->setContentsMargins(0, 10, 0, 0);
0396             layout->addLayout(buttonLayout, 0, 0);
0397         }
0398         else {
0399             buttonLayout->addWidget(closeButton);
0400             //?? buttonLayout->setContentsMargins(0, 10, 0, 0);
0401             layout->addItem(buttonLayout, 2, 1, 1, 2);
0402             layout->addItem(new QSpacerItem(rightContentSpacerItemWidth, bottomContentSpacerItemHeight), 3, 3);
0403         }
0404     } else {
0405         QHBoxLayout* layout = new QHBoxLayout(content);
0406         layout->setSpacing(LAYOUT_SPACING);
0407         if (contentsWidget) {
0408             layout->addWidget(contentsWidget);
0409         }
0410         else {
0411             layout->addWidget(iconLabel);
0412             layout->addWidget(textLabel);
0413         }
0414         Q_FOREACH(QToolButton* button, buttons) {
0415             layout->addWidget(button);
0416         }
0417 
0418         layout->addWidget(closeButton);
0419     };
0420 
0421     // add margins based on outer margins
0422     int left, top, right, bottom;
0423     q->getContentsMargins(&left, &top, &right, &bottom);
0424     //qDebug() << "q->getContentsMargins:" << left << top << right << bottom;
0425     switch (content->calloutPointerDirection()) {
0426     case KMessageWidget::Up:
0427         left += 1;
0428         top += 4;
0429         bottom += 4;
0430         right += 2;
0431         if (!buttons.isEmpty()) {
0432             top += 4;
0433             right += 3;
0434         }
0435         break;
0436     case KMessageWidget::Down:
0437         left += 1;
0438         top += 4;
0439         bottom += 4;
0440         right += 2;
0441         if (!buttons.isEmpty()) {
0442             right += 3;
0443         }
0444         break;
0445     case KMessageWidget::Left: {
0446         left += 0;
0447         top += 3;
0448         bottom += 3;
0449         right += 1;
0450         if (buttonLayout) {
0451             int leftSp = content->radius * 2 + LAYOUT_SPACING;
0452             buttonLayout->insertSpacing(0, leftSp);
0453             buttonLayout->addSpacing(LAYOUT_SPACING);
0454         }
0455         break;
0456     }
0457     case KMessageWidget::Right:
0458         left += 0;
0459         top += 3;
0460         bottom += 3;
0461         right += 1;
0462         break;
0463     default:;
0464     }
0465     content->layout()->setContentsMargins(
0466         left, top, right, bottom);
0467 
0468     if (q->isVisible()) {
0469         if (content->sizeHint().height() >= 0) {
0470             //q->setFixedHeight(content->sizeHint().height());
0471             q->setFixedHeight(QWIDGETSIZE_MAX);
0472         }
0473     }
0474     content->updateGeometry();
0475     q->updateGeometry();
0476 }
0477 
0478 void KMessageWidgetPrivate::updateLayout()
0479 {
0480     if (content->layout()) {
0481         createLayout();
0482     }
0483 }
0484 
0485 void KMessageWidgetPrivate::updateSnapShot()
0486 {
0487     contentSnapShot = QPixmap(content->size());
0488     contentSnapShot.fill(Qt::transparent);
0489     content->render(&contentSnapShot, QPoint(), QRegion(), QWidget::DrawChildren);
0490 }
0491 
0492 void KMessageWidgetPrivate::updateStyleSheet()
0493 {
0494     KColorScheme scheme(QPalette::Active, colorSet);
0495     content->bgBrush = scheme.background(bgRole);
0496     content->borderBrush = scheme.foreground(fgRole);
0497     QBrush fg = scheme.foreground();
0498 
0499     int left, top, right, bottom;
0500     content->getContentsMargins(&left, &top, &right, &bottom);
0501     //qDebug() << "content->getContentsMargins:" << left << top << right << bottom;
0502     if (!buttons.isEmpty()) {
0503         //q->setContentsMargins(0, 0, 0, 0);
0504         content->setContentsMargins(LAYOUT_SPACING, 0, 0, 0);
0505     }
0506     q->getContentsMargins(&left, &top, &right, &bottom);
0507     //qDebug() << "q->getContentsMargins:" << left << top << right << bottom;
0508 #if 1
0509     int add = content->radius * 2;
0510     switch (content->calloutPointerDirection()) {
0511     case KMessageWidget::Up:
0512         top += add;
0513         break;
0514     case KMessageWidget::Down:
0515         bottom += add;
0516         break;
0517     case KMessageWidget::Left:
0518         left += add;
0519         break;
0520     case KMessageWidget::Right:
0521         right += add;
0522         break;
0523     default:;
0524     }
0525     content->setStyleSheet(
0526         QString(".KMessageWidgetFrame {"
0527             "background-color: %1;"
0528             "border-radius: %2px;"
0529             "margin: %3px %4px %5px %6px;"
0530             "border: 1px solid %7;"
0531             "}"
0532             ".QLabel { color: %8; }"
0533             )
0534         .arg(content->bgBrush.color().name())
0535         .arg(content->radius)
0536         .arg(top)
0537         .arg(right)
0538         .arg(bottom)
0539         .arg(left)
0540         .arg(content->borderBrush.color().name())
0541         .arg(fg.color().name())
0542     );
0543     closeButton->setStyle(QApplication::style()); // clear stylesheets style from this button
0544 #endif
0545 }
0546 
0547 //---------------------------------------------------------------------
0548 // KMessageWidget
0549 //---------------------------------------------------------------------
0550 KMessageWidget::KMessageWidget(QWidget* parent)
0551     : QFrame(parent)
0552     , d(new KMessageWidgetPrivate)
0553 {
0554     d->init(this);
0555 }
0556 
0557 KMessageWidget::KMessageWidget(const QString& text, QWidget* parent)
0558     : QFrame(parent)
0559     , d(new KMessageWidgetPrivate)
0560 {
0561     d->init(this);
0562     setText(text);
0563 }
0564 
0565 KMessageWidget::KMessageWidget(QWidget* contentsWidget, QWidget* parent)
0566     : QFrame(parent)
0567     , d(new KMessageWidgetPrivate)
0568 {
0569     d->contentsWidget = contentsWidget;
0570     d->init(this);
0571 }
0572 
0573 KMessageWidget::~KMessageWidget()
0574 {
0575     delete d;
0576 }
0577 
0578 QString KMessageWidget::text() const
0579 {
0580     return d->textLabel ? d->textLabel->text() : QString();
0581 }
0582 
0583 void KMessageWidget::setText(const QString& text)
0584 {
0585     if (d->textLabel) {
0586         d->textLabel->setText(text);
0587         updateGeometry();
0588     }
0589 }
0590 
0591 KMessageWidget::MessageType KMessageWidget::messageType() const
0592 {
0593     return d->messageType;
0594 }
0595 
0596 void KMessageWidget::setMessageType(KMessageWidget::MessageType type)
0597 {
0598     d->messageType = type;
0599     QIcon icon;
0600     d->colorSet = KColorScheme::View;
0601     switch (type) {
0602     case Positive:
0603         icon = koIcon("dialog-ok");
0604         d->bgRole = KColorScheme::PositiveBackground;
0605         d->fgRole = KColorScheme::PositiveText;
0606         break;
0607     case Information:
0608         icon = koIcon("dialog-information");
0609         d->bgRole = KColorScheme::NeutralBackground;
0610         d->fgRole = KColorScheme::NeutralText;
0611         break;
0612     case Warning:
0613         icon = koIcon("dialog-warning");
0614         d->bgRole = KColorScheme::NeutralBackground;
0615         d->fgRole = KColorScheme::NeutralText;
0616         break;
0617     case Error:
0618         icon = koIcon("dialog-error");
0619         d->bgRole = KColorScheme::NegativeBackground;
0620         d->fgRole = KColorScheme::NegativeText;
0621         break;
0622     }
0623     if (d->iconLabel) {
0624         const int size = KIconLoader::global()->currentSize(KIconLoader::MainToolbar);
0625         d->iconLabel->setPixmap(icon.pixmap(size));
0626     }
0627 
0628     d->updateStyleSheet();
0629     d->updateLayout();
0630 }
0631 
0632 KMessageWidget::CalloutPointerDirection KMessageWidget::calloutPointerDirection() const
0633 {
0634     return d->content->calloutPointerDirection();
0635 }
0636 
0637 void KMessageWidget::setCalloutPointerDirection(KMessageWidget::CalloutPointerDirection direction)
0638 {
0639     d->content->setCalloutPointerDirection(direction);
0640     d->updateStyleSheet();
0641     d->updateLayout();
0642     d->content->updateCalloutPointerPosition();
0643 }
0644 
0645 QSize KMessageWidget::sizeHint() const
0646 {
0647     ensurePolished();
0648     //qDebug() << "d->content->sizeHint():" << d->content->sizeHint();
0649     //qDebug() << "QFrame::sizeHint():" << QFrame::sizeHint();
0650     return QFrame::sizeHint();
0651 /*    QSize s1(QFrame::sizeHint());
0652     QSize s2(d->content->sizeHint());
0653     return QSize(qMax(s1.width(), s2.width()), qMax(s1.height(), s2.height()));*/
0654 }
0655 
0656 QSize KMessageWidget::minimumSizeHint() const
0657 {
0658     ensurePolished();
0659     //qDebug() << "d->content->minimumSizeHint():" << d->content->minimumSizeHint();
0660     //qDebug() << "QFrame::minimumSizeHint():" << QFrame::minimumSizeHint();
0661     return QFrame::minimumSizeHint();
0662 /*    QSize s1(QFrame::minimumSizeHint());
0663     QSize s2(d->content->minimumSizeHint());
0664     return QSize(qMax(s1.width(), s2.width()), qMax(s1.height(), s2.height()));*/
0665 }
0666 
0667 bool KMessageWidget::event(QEvent* event)
0668 {
0669     if (event->type() == QEvent::Polish && !d->content->layout()) {
0670         d->createLayout();
0671     }
0672     else if (event->type() == QEvent::Hide) {
0673         //qDebug() << "QEvent::Hide" << event->spontaneous();
0674         if (!event->spontaneous()) {
0675             if (d->autoDelete) {
0676                 deleteLater();
0677             }
0678         }
0679     }
0680     else if (event->type() == QEvent::MouseButtonPress) {
0681         if (static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton) {
0682             tryClickCloseMessage();
0683         }
0684     }
0685     return QFrame::event(event);
0686 }
0687 
0688 void KMessageWidget::resizeEvent(QResizeEvent* event)
0689 {
0690     QFrame::resizeEvent(event);
0691     if (d->timeLine->state() == QTimeLine::NotRunning) {
0692         d->content->resize(size());
0693         d->updateStyleSheet(); // needed because margins could be changed
0694     }
0695 }
0696 
0697 void KMessageWidget::paintEvent(QPaintEvent* event)
0698 {
0699     QFrame::paintEvent(event);
0700     if (d->timeLine->state() == QTimeLine::Running) {
0701         QPainter painter(this);
0702         painter.setOpacity(d->timeLine->currentValue() * d->timeLine->currentValue());
0703         painter.drawPixmap(0, 0, d->contentSnapShot);
0704     }
0705 }
0706 
0707 void KMessageWidget::showEvent(QShowEvent* event)
0708 {
0709     QFrame::showEvent(event);
0710     if (!event->spontaneous()) {
0711 #if 0
0712         int wantedHeight = d->content->sizeHint().height();
0713         d->content->setGeometry(0, 0, width(), wantedHeight);
0714         if (d->buttons.isEmpty()) {
0715             setFixedHeight(wantedHeight);
0716         }
0717 #endif
0718     }
0719 }
0720 
0721 bool KMessageWidget::wordWrap() const
0722 {
0723     return d->wordWrap;
0724 }
0725 
0726 void KMessageWidget::setWordWrap(bool wordWrap)
0727 {
0728     d->wordWrap = wordWrap;
0729     if (d->textLabel) {
0730         d->textLabel->setWordWrap(wordWrap);
0731         d->updateLayout();
0732     }
0733 }
0734 
0735 bool KMessageWidget::isCloseButtonVisible() const
0736 {
0737     return d->closeButton->isVisible();
0738 }
0739 
0740 void KMessageWidget::setCloseButtonVisible(bool show)
0741 {
0742     d->closeButton->setVisible(show);
0743 }
0744 
0745 bool KMessageWidget::clickClosesMessage() const
0746 {
0747     return d->clickClosesMessage;
0748 }
0749 
0750 void KMessageWidget::setClickClosesMessage(bool set)
0751 {
0752     d->clickClosesMessage = set;
0753 }
0754 
0755 void KMessageWidget::addAction(QAction* action)
0756 {
0757     QFrame::addAction(action);
0758     d->updateLayout();
0759 }
0760 
0761 void KMessageWidget::setDefaultAction(QAction* action)
0762 {
0763     d->defaultAction = action;
0764     d->createLayout();
0765 }
0766 
0767 void KMessageWidget::setButtonLeftAlignedForAction(QAction *action)
0768 {
0769     d->leftAlignedButtons.insert(action);
0770 }
0771 
0772 void KMessageWidget::removeAction(QAction* action)
0773 {
0774     QFrame::removeAction(action);
0775     d->updateLayout();
0776 }
0777 
0778 void KMessageWidget::setAutoDelete(bool set)
0779 {
0780     d->autoDelete = set;
0781 }
0782 
0783 void KMessageWidget::animatedShow()
0784 {
0785     if (!(KexiUtils::graphicEffectsLevel() & KexiUtils::SimpleAnimationEffects)) {
0786         show();
0787         return;
0788     }
0789 
0790     if (isVisible()) {
0791         return;
0792     }
0793 
0794     d->content->updateCalloutPointerPosition();
0795     QFrame::show();
0796     if (d->contentsWidget) {
0797         int wantedHeight = height();
0798         d->content->setGeometry(0, 0, width(), wantedHeight);
0799         setFixedHeight(wantedHeight);
0800     }
0801     else {
0802         setFixedHeight(0);
0803         int wantedHeight = d->content->sizeHint().height();
0804         d->content->setGeometry(0, -wantedHeight, width(), wantedHeight);
0805     }
0806 
0807     d->updateSnapShot();
0808 
0809     d->timeLine->setDirection(QTimeLine::Forward);
0810     if (d->timeLine->state() == QTimeLine::NotRunning) {
0811         d->timeLine->start();
0812     }
0813 }
0814 
0815 void KMessageWidget::animatedHide()
0816 {
0817     if (!(KexiUtils::graphicEffectsLevel() & KexiUtils::SimpleAnimationEffects)) {
0818         hide();
0819         return;
0820     }
0821 
0822     if (!isVisible()) {
0823         return;
0824     }
0825 
0826     d->content->move(0, -d->content->height());
0827     d->updateSnapShot();
0828 
0829     d->timeLine->setDirection(QTimeLine::Backward);
0830     if (d->timeLine->state() == QTimeLine::NotRunning) {
0831         d->timeLine->start();
0832     }
0833 }
0834 
0835 void KMessageWidget::setCalloutPointerPosition(const QPoint& globalPos)
0836 {
0837     d->content->setCalloutPointerPosition(globalPos);
0838 }
0839 
0840 QPoint KMessageWidget::calloutPointerPosition() const
0841 {
0842     return d->content->calloutPointerPosition();
0843 }
0844 
0845 QBrush KMessageWidget::backgroundBrush() const
0846 {
0847     return d->content->bgBrush;
0848 }
0849 
0850 QBrush KMessageWidget::borderBrush() const
0851 {
0852     return d->content->borderBrush;
0853 }
0854 
0855 void KMessageWidget::resizeToContents()
0856 {
0857 //    qDebug() << LAYOUT_SPACING + d->iconLabel->width() + LAYOUT_SPACING + d->textLabel->width() + LAYOUT_SPACING;
0858 //    qDebug() << "sizeHint():" << sizeHint();
0859 //    qDebug() << "d->content->sizeHint():" << d->content->sizeHint();
0860     d->resizeToContentsOnTimeLineFinished = true; // try to resize later too if animation in progress
0861     (void)sizeHint(); // to update d->content->sizeHint()
0862     setFixedSize(d->content->sizeHint());
0863 }
0864 
0865 void KMessageWidget::slotTimeLineChanged(qreal value)
0866 {
0867     if (!d->contentsWidget) {
0868         setFixedHeight(qMin(value * 2, qreal(1.0)) * d->content->height());
0869     }
0870     update();
0871 }
0872 
0873 void KMessageWidget::slotTimeLineFinished()
0874 {
0875     if (d->timeLine->direction() == QTimeLine::Forward) {
0876         // Show
0877         d->content->move(0, 0);
0878         d->content->updateCalloutPointerPosition();
0879         if (d->resizeToContentsOnTimeLineFinished) {
0880             d->resizeToContentsOnTimeLineFinished = false;
0881             d->content->resize(size());
0882             d->updateStyleSheet(); // needed because margins could be changed
0883         }
0884         //q->setFixedHeight(QWIDGETSIZE_MAX);
0885         if (d->defaultButton) {
0886             d->defaultButton->setFocus();
0887         }
0888         emit animatedShowFinished();
0889     } else {
0890         // Hide
0891         hide();
0892         emit animatedHideFinished();
0893     }
0894 }
0895 
0896 void KMessageWidget::tryClickCloseMessage()
0897 {
0898     if (d->clickClosesMessage) {
0899         QTimer::singleShot(100, this, SLOT(animatedHide()));
0900     }
0901 }