• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

kmessagewidget.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002  *
00003  * Copyright (c) 2011 Aurélien Gâteau <agateau@kde.org>
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 Street, Fifth Floor, Boston, MA
00018  * 02110-1301  USA
00019  */
00020 #include "kmessagewidget.h"
00021 
00022 #include <kaction.h>
00023 #include <kcolorscheme.h>
00024 #include <kdebug.h>
00025 #include <kglobalsettings.h>
00026 #include <kicon.h>
00027 #include <kiconloader.h>
00028 #include <kstandardaction.h>
00029 
00030 #include <QEvent>
00031 #include <QGridLayout>
00032 #include <QHBoxLayout>
00033 #include <QLabel>
00034 #include <QPainter>
00035 #include <QShowEvent>
00036 #include <QTimeLine>
00037 #include <QToolButton>
00038 
00039 //---------------------------------------------------------------------
00040 // KMessageWidgetPrivate
00041 //---------------------------------------------------------------------
00042 class KMessageWidgetPrivate
00043 {
00044 public:
00045     void init(KMessageWidget*);
00046 
00047     KMessageWidget* q;
00048     QFrame* content;
00049     QLabel* iconLabel;
00050     QLabel* textLabel;
00051     QToolButton* closeButton;
00052     QTimeLine* timeLine;
00053 
00054     KMessageWidget::MessageType messageType;
00055     bool wordWrap;
00056     QList<QToolButton*> buttons;
00057     QPixmap contentSnapShot;
00058 
00059     void createLayout();
00060     void updateSnapShot();
00061     void updateLayout();
00062     void slotTimeLineChanged(qreal);
00063     void slotTimeLineFinished();
00064 
00065     int bestContentHeight() const;
00066 };
00067 
00068 void KMessageWidgetPrivate::init(KMessageWidget *q_ptr)
00069 {
00070     q = q_ptr;
00071 
00072     q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
00073 
00074     timeLine = new QTimeLine(500, q);
00075     QObject::connect(timeLine, SIGNAL(valueChanged(qreal)), q, SLOT(slotTimeLineChanged(qreal)));
00076     QObject::connect(timeLine, SIGNAL(finished()), q, SLOT(slotTimeLineFinished()));
00077 
00078     content = new QFrame(q);
00079     content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00080 
00081     wordWrap = false;
00082 
00083     iconLabel = new QLabel(content);
00084     iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00085 
00086     textLabel = new QLabel(content);
00087     textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00088     textLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
00089 
00090     KAction* closeAction = KStandardAction::close(q, SLOT(animatedHide()), q);
00091 
00092     closeButton = new QToolButton(content);
00093     closeButton->setAutoRaise(true);
00094     closeButton->setDefaultAction(closeAction);
00095 
00096     q->setMessageType(KMessageWidget::Information);
00097 }
00098 
00099 void KMessageWidgetPrivate::createLayout()
00100 {
00101     delete content->layout();
00102 
00103     content->resize(q->size());
00104 
00105     qDeleteAll(buttons);
00106     buttons.clear();
00107 
00108     Q_FOREACH(QAction* action, q->actions()) {
00109         QToolButton* button = new QToolButton(content);
00110         button->setDefaultAction(action);
00111         button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
00112         buttons.append(button);
00113     }
00114 
00115     // AutoRaise reduces visual clutter, but we don't want to turn it on if
00116     // there are other buttons, otherwise the close button will look different
00117     // from the others.
00118     closeButton->setAutoRaise(buttons.isEmpty());
00119 
00120     if (wordWrap) {
00121         QGridLayout* layout = new QGridLayout(content);
00122         // Set alignment to make sure icon does not move down if text wraps
00123         layout->addWidget(iconLabel, 0, 0, 1, 1, Qt::AlignHCenter | Qt::AlignTop);
00124         layout->addWidget(textLabel, 0, 1);
00125 
00126         QHBoxLayout* buttonLayout = new QHBoxLayout;
00127         buttonLayout->addStretch();
00128         Q_FOREACH(QToolButton* button, buttons) {
00129             // For some reason, calling show() is necessary if wordwrap is true,
00130             // otherwise the buttons do not show up. It is not needed if
00131             // wordwrap is false.
00132             button->show();
00133             buttonLayout->addWidget(button);
00134         }
00135         buttonLayout->addWidget(closeButton);
00136         layout->addItem(buttonLayout, 1, 0, 1, 2);
00137     } else {
00138         QHBoxLayout* layout = new QHBoxLayout(content);
00139         layout->addWidget(iconLabel);
00140         layout->addWidget(textLabel);
00141 
00142         Q_FOREACH(QToolButton* button, buttons) {
00143             layout->addWidget(button);
00144         }
00145 
00146         layout->addWidget(closeButton);
00147     };
00148 
00149     if (q->isVisible()) {
00150         q->setFixedHeight(content->sizeHint().height());
00151     }
00152     q->updateGeometry();
00153 }
00154 
00155 void KMessageWidgetPrivate::updateLayout()
00156 {
00157     if (content->layout()) {
00158         createLayout();
00159     }
00160 }
00161 
00162 void KMessageWidgetPrivate::updateSnapShot()
00163 {
00164     // Attention: updateSnapShot calls QWidget::render(), which causes the whole
00165     // window layouts to be activated. Calling this method from resizeEvent()
00166     // can lead to infinite recursion, see:
00167     // https://bugs.kde.org/show_bug.cgi?id=311336
00168     contentSnapShot = QPixmap(content->size());
00169     contentSnapShot.fill(Qt::transparent);
00170     content->render(&contentSnapShot, QPoint(), QRegion(), QWidget::DrawChildren);
00171 }
00172 
00173 void KMessageWidgetPrivate::slotTimeLineChanged(qreal value)
00174 {
00175     q->setFixedHeight(qMin(value * 2, qreal(1.0)) * content->height());
00176     q->update();
00177 }
00178 
00179 void KMessageWidgetPrivate::slotTimeLineFinished()
00180 {
00181     if (timeLine->direction() == QTimeLine::Forward) {
00182         // Show
00183         // We set the whole geometry here, because it may be wrong if a
00184         // KMessageWidget is shown right when the toplevel window is created.
00185         content->setGeometry(0, 0, q->width(), bestContentHeight());
00186     } else {
00187         // Hide
00188         q->hide();
00189     }
00190 }
00191 
00192 int KMessageWidgetPrivate::bestContentHeight() const
00193 {
00194     int height = content->heightForWidth(q->width());
00195     if (height == -1) {
00196         height = content->sizeHint().height();
00197     }
00198     return height;
00199 }
00200 
00201 
00202 //---------------------------------------------------------------------
00203 // KMessageWidget
00204 //---------------------------------------------------------------------
00205 KMessageWidget::KMessageWidget(QWidget* parent)
00206     : QFrame(parent)
00207     , d(new KMessageWidgetPrivate)
00208 {
00209     d->init(this);
00210 }
00211 
00212 KMessageWidget::KMessageWidget(const QString& text, QWidget* parent)
00213     : QFrame(parent)
00214     , d(new KMessageWidgetPrivate)
00215 {
00216     d->init(this);
00217     setText(text);
00218 }
00219 
00220 KMessageWidget::~KMessageWidget()
00221 {
00222     delete d;
00223 }
00224 
00225 QString KMessageWidget::text() const
00226 {
00227     return d->textLabel->text();
00228 }
00229 
00230 void KMessageWidget::setText(const QString& text)
00231 {
00232     d->textLabel->setText(text);
00233     updateGeometry();
00234 }
00235 
00236 KMessageWidget::MessageType KMessageWidget::messageType() const
00237 {
00238     return d->messageType;
00239 }
00240 
00241 static void getColorsFromColorScheme(KColorScheme::BackgroundRole bgRole, QColor* bg, QColor* fg)
00242 {
00243     KColorScheme scheme(QPalette::Active, KColorScheme::Window);
00244     *bg = scheme.background(bgRole).color();
00245     *fg = scheme.foreground().color();
00246 }
00247 
00248 void KMessageWidget::setMessageType(KMessageWidget::MessageType type)
00249 {
00250     d->messageType = type;
00251     KIcon icon;
00252     QColor bg0, bg1, bg2, border, fg;
00253     switch (type) {
00254     case Positive:
00255         icon = KIcon("dialog-ok");
00256         getColorsFromColorScheme(KColorScheme::PositiveBackground, &bg1, &fg);
00257         break;
00258     case Information:
00259         icon = KIcon("dialog-information");
00260         // There is no "information" background role in KColorScheme, use the
00261         // colors of highlighted items instead
00262         bg1 = palette().highlight().color();
00263         fg = palette().highlightedText().color();
00264         break;
00265     case Warning:
00266         icon = KIcon("dialog-warning");
00267         getColorsFromColorScheme(KColorScheme::NeutralBackground, &bg1, &fg);
00268         break;
00269     case Error:
00270         icon = KIcon("dialog-error");
00271         getColorsFromColorScheme(KColorScheme::NegativeBackground, &bg1, &fg);
00272         break;
00273     }
00274 
00275     // Colors
00276     bg0 = bg1.lighter(110);
00277     bg2 = bg1.darker(110);
00278     border = KColorScheme::shade(bg1, KColorScheme::DarkShade);
00279 
00280     d->content->setStyleSheet(
00281         QString(".QFrame {"
00282             "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
00283             "    stop: 0 %1,"
00284             "    stop: 0.1 %2,"
00285             "    stop: 1.0 %3);"
00286             "border-radius: 5px;"
00287             "border: 1px solid %4;"
00288             "}"
00289             ".QLabel { color: %5; }"
00290             )
00291         .arg(bg0.name())
00292         .arg(bg1.name())
00293         .arg(bg2.name())
00294         .arg(border.name())
00295         .arg(fg.name())
00296         );
00297 
00298     // Icon
00299     const int size = KIconLoader::global()->currentSize(KIconLoader::MainToolbar);
00300     d->iconLabel->setPixmap(icon.pixmap(size));
00301 }
00302 
00303 QSize KMessageWidget::sizeHint() const
00304 {
00305     ensurePolished();
00306     return d->content->sizeHint();
00307 }
00308 
00309 QSize KMessageWidget::minimumSizeHint() const
00310 {
00311     ensurePolished();
00312     return d->content->minimumSizeHint();
00313 }
00314 
00315 bool KMessageWidget::event(QEvent* event)
00316 {
00317     if (event->type() == QEvent::Polish && !d->content->layout()) {
00318         d->createLayout();
00319     }
00320     return QFrame::event(event);
00321 }
00322 
00323 void KMessageWidget::resizeEvent(QResizeEvent* event)
00324 {
00325     QFrame::resizeEvent(event);
00326 
00327     if (d->timeLine->state() == QTimeLine::NotRunning) {
00328         d->content->resize(width(), d->bestContentHeight());
00329     }
00330 }
00331 
00332 int KMessageWidget::heightForWidth(int width) const
00333 {
00334     ensurePolished();
00335     return d->content->heightForWidth(width);
00336 }
00337 
00338 void KMessageWidget::paintEvent(QPaintEvent* event)
00339 {
00340     QFrame::paintEvent(event);
00341     if (d->timeLine->state() == QTimeLine::Running) {
00342         QPainter painter(this);
00343         painter.setOpacity(d->timeLine->currentValue() * d->timeLine->currentValue());
00344         painter.drawPixmap(0, 0, d->contentSnapShot);
00345     }
00346 }
00347 
00348 void KMessageWidget::showEvent(QShowEvent* event)
00349 {
00350     // Keep this method here to avoid breaking binary compatibility:
00351     // QFrame::showEvent() used to be reimplemented.
00352     QFrame::showEvent(event);
00353 }
00354 
00355 bool KMessageWidget::wordWrap() const
00356 {
00357     return d->wordWrap;
00358 }
00359 
00360 void KMessageWidget::setWordWrap(bool wordWrap)
00361 {
00362     d->wordWrap = wordWrap;
00363     d->textLabel->setWordWrap(wordWrap);
00364     QSizePolicy policy = sizePolicy();
00365     policy.setHeightForWidth(wordWrap);
00366     setSizePolicy(policy);
00367     d->updateLayout();
00368     // Without this, when user does wordWrap -> !wordWrap -> wordWrap, a minimum
00369     // height is set, causing the widget to be too high.
00370     // Mostly visible in test programs.
00371     if (wordWrap) {
00372         setMinimumHeight(0);
00373     }
00374 }
00375 
00376 bool KMessageWidget::isCloseButtonVisible() const
00377 {
00378     return d->closeButton->isVisible();
00379 }
00380 
00381 void KMessageWidget::setCloseButtonVisible(bool show)
00382 {
00383     d->closeButton->setVisible(show);
00384     updateGeometry();
00385 }
00386 
00387 void KMessageWidget::addAction(QAction* action)
00388 {
00389     QFrame::addAction(action);
00390     d->updateLayout();
00391 }
00392 
00393 void KMessageWidget::removeAction(QAction* action)
00394 {
00395     QFrame::removeAction(action);
00396     d->updateLayout();
00397 }
00398 
00399 void KMessageWidget::animatedShow()
00400 {
00401     if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
00402         show();
00403         return;
00404     }
00405 
00406     if (isVisible()) {
00407         return;
00408     }
00409 
00410     QFrame::show();
00411     setFixedHeight(0);
00412     int wantedHeight = d->bestContentHeight();
00413     d->content->setGeometry(0, -wantedHeight, width(), wantedHeight);
00414 
00415     d->updateSnapShot();
00416 
00417     d->timeLine->setDirection(QTimeLine::Forward);
00418     if (d->timeLine->state() == QTimeLine::NotRunning) {
00419         d->timeLine->start();
00420     }
00421 }
00422 
00423 void KMessageWidget::animatedHide()
00424 {
00425     if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
00426         hide();
00427         return;
00428     }
00429 
00430     if (!isVisible()) {
00431         return;
00432     }
00433 
00434     d->content->move(0, -d->content->height());
00435     d->updateSnapShot();
00436 
00437     d->timeLine->setDirection(QTimeLine::Backward);
00438     if (d->timeLine->state() == QTimeLine::NotRunning) {
00439         d->timeLine->start();
00440     }
00441 }
00442 
00443 #include "kmessagewidget.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:41 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal