From c6ad476cb707bf452aa7d538255f72e157c55be7 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 19 Jan 2015 20:16:21 +0000 Subject: [PATCH 01/12] Added kmessagewidget from subsurface project (https://github.com/torvalds/subsurface, commit: 82a946152b7f1da177344937acbc9d3cb5b0ccbf). Added MessageWidget class. --- src/CMakeLists.txt | 2 + src/gui/MessageWidget.cpp | 49 +++++ src/gui/MessageWidget.h | 21 ++ src/gui/kmessagewidget.cpp | 425 +++++++++++++++++++++++++++++++++++++ src/gui/kmessagewidget.h | 239 +++++++++++++++++++++ 5 files changed, 736 insertions(+) create mode 100644 src/gui/MessageWidget.cpp create mode 100644 src/gui/MessageWidget.h create mode 100644 src/gui/kmessagewidget.cpp create mode 100644 src/gui/kmessagewidget.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c3948842..3de167544 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,9 +86,11 @@ set(keepassx_SOURCES gui/FileDialog.cpp gui/IconModels.cpp gui/KeePass1OpenWidget.cpp + gui/kmessagewidget.cpp gui/LineEdit.cpp gui/MainWindow.cpp gui/MessageBox.cpp + gui/MessageWidget.cpp gui/PasswordEdit.cpp gui/PasswordGeneratorWidget.cpp gui/PasswordComboBox.cpp diff --git a/src/gui/MessageWidget.cpp b/src/gui/MessageWidget.cpp new file mode 100644 index 000000000..1e6d06044 --- /dev/null +++ b/src/gui/MessageWidget.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "MessageWidget.h" + +MessageWidget::MessageWidget(QWidget* parent) + :KMessageWidget(parent) +{ + +} + +void MessageWidget::showMessageError(const QString& text) +{ + showMessage(text, MessageType::Error); +} + +void MessageWidget::showMessageWarning(const QString& text) +{ + showMessage(text, MessageType::Warning); +} + +void MessageWidget::showMessagePositive(const QString& text) +{ + showMessage(text, MessageType::Positive); +} + +void MessageWidget::showMessage(const QString& text, MessageType type) +{ + setMessageType(type); + setText(text); + animatedShow(); +} + + + diff --git a/src/gui/MessageWidget.h b/src/gui/MessageWidget.h new file mode 100644 index 000000000..6e8366fae --- /dev/null +++ b/src/gui/MessageWidget.h @@ -0,0 +1,21 @@ + + +#ifndef MESSAGEWIDGET_H +#define MESSAGEWIDGET_H + +#include "gui/kmessagewidget.h" + +class MessageWidget : public KMessageWidget +{ +public: + explicit MessageWidget(QWidget* parent = 0); + void showMessageError(const QString& text); + void showMessageWarning(const QString& text); + void showMessageInformation(const QString& text); + void showMessagePositive(const QString& text); + +private: + void showMessage(const QString& text, MessageType type); +}; + +#endif // MESSAGEWIDGET_H diff --git a/src/gui/kmessagewidget.cpp b/src/gui/kmessagewidget.cpp new file mode 100644 index 000000000..e5aafd61a --- /dev/null +++ b/src/gui/kmessagewidget.cpp @@ -0,0 +1,425 @@ +/* This file is part of the KDE libraries + * + * Copyright (c) 2011 Aurélien Gâteau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include "kmessagewidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void KMessageWidgetPrivate::init(KMessageWidget *q_ptr) +{ + q = q_ptr; + + q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + + timeLine = new QTimeLine(500, q); + QObject::connect(timeLine, SIGNAL(valueChanged(qreal)), q, SLOT(slotTimeLineChanged(qreal))); + QObject::connect(timeLine, SIGNAL(finished()), q, SLOT(slotTimeLineFinished())); + + content = new QFrame(q); + content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + wordWrap = false; + + iconLabel = new QLabel(content); + iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + iconLabel->hide(); + + textLabel = new QLabel(content); + textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + textLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + QObject::connect(textLabel, SIGNAL(linkActivated(const QString &)), q, SIGNAL(linkActivated(const QString &))); + QObject::connect(textLabel, SIGNAL(linkHovered(const QString &)), q, SIGNAL(linkHovered(const QString &))); + + QAction *closeAction = new QAction(QObject::tr("Close"), q); + q->connect(closeAction, SIGNAL(triggered(bool)), q, SLOT(animatedHide())); + + closeButton = new QToolButton(content); + closeButton->setAutoRaise(true); + closeButton->setDefaultAction(closeAction); + closeButton->setVisible(true); + q->setMessageType(KMessageWidget::Information); +} + +void KMessageWidgetPrivate::createLayout() +{ + delete content->layout(); + + content->resize(q->size()); + + qDeleteAll(buttons); + buttons.clear(); + + Q_FOREACH (QAction *action, q->actions()) { + QToolButton *button = new QToolButton(content); + button->setDefaultAction(action); + button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + buttons.append(button); + } + + // AutoRaise reduces visual clutter, but we don't want to turn it on if + // there are other buttons, otherwise the close button will look different + // from the others. + closeButton->setAutoRaise(buttons.isEmpty()); + + if (wordWrap) { + QGridLayout *layout = new QGridLayout(content); + // Set alignment to make sure icon does not move down if text wraps + layout->addWidget(iconLabel, 0, 0, 1, 1, Qt::AlignHCenter | Qt::AlignTop); + layout->addWidget(textLabel, 0, 1); + + QDialogButtonBox *buttonLayout = new QDialogButtonBox(); + //buttonLayout->addStretch(); + Q_FOREACH (QToolButton *button, buttons) { + // For some reason, calling show() is necessary if wordwrap is true, + // otherwise the buttons do not show up. It is not needed if + // wordwrap is false. + button->show(); + buttonLayout->addButton(button, QDialogButtonBox::QDialogButtonBox::AcceptRole); + } + buttonLayout->addButton(closeButton, QDialogButtonBox::RejectRole); + layout->addWidget(buttonLayout, 1, 0, 1, 2, Qt::AlignHCenter | Qt::AlignTop); + } else { + bool closeButtonVisible = closeButton->isVisible(); + QHBoxLayout *layout = new QHBoxLayout(content); + layout->addWidget(iconLabel); + layout->addWidget(textLabel); + + QDialogButtonBox *buttonLayout = new QDialogButtonBox(); + Q_FOREACH (QToolButton *button, buttons) { + buttonLayout->addButton(button, QDialogButtonBox::QDialogButtonBox::AcceptRole); + } + + buttonLayout->addButton(closeButton, QDialogButtonBox::RejectRole); + // Something gets changed when added to the buttonLayout + closeButton->setVisible(closeButtonVisible); + layout->addWidget(buttonLayout); + }; + + if (q->isVisible()) { + q->setFixedHeight(content->sizeHint().height()); + } + + q->updateGeometry(); +} + +void KMessageWidgetPrivate::updateLayout() +{ + if (content->layout()) { + createLayout(); + } +} + +void KMessageWidgetPrivate::updateSnapShot() +{ + // Attention: updateSnapShot calls QWidget::render(), which causes the whole + // window layouts to be activated. Calling this method from resizeEvent() + // can lead to infinite recursion, see: + // https://bugs.kde.org/show_bug.cgi?id=311336 + contentSnapShot = QPixmap(content->size()); + contentSnapShot.fill(Qt::transparent); + content->render(&contentSnapShot, QPoint(), QRegion(), QWidget::DrawChildren); +} + +void KMessageWidgetPrivate::slotTimeLineChanged(qreal value) +{ + q->setFixedHeight(qMin(value * 2, qreal(1.0)) * content->height()); + q->update(); +} + +void KMessageWidgetPrivate::slotTimeLineFinished() +{ + if (timeLine->direction() == QTimeLine::Forward) { + // Show + // We set the whole geometry here, because it may be wrong if a + // KMessageWidget is shown right when the toplevel window is created. + content->setGeometry(0, 0, q->width(), bestContentHeight()); + } else { + // Hide + q->hide(); + } +} + +int KMessageWidgetPrivate::bestContentHeight() const +{ + int height = content->heightForWidth(q->width()); + + if (height == -1) { + height = content->sizeHint().height(); + } + + return height; +} + + +//--------------------------------------------------------------------- +// KMessageWidget +//--------------------------------------------------------------------- +KMessageWidget::KMessageWidget(QWidget *parent) : QFrame(parent), d(new KMessageWidgetPrivate) +{ + d->init(this); +} + +KMessageWidget::KMessageWidget(const QString &text, QWidget *parent) : QFrame(parent), d(new KMessageWidgetPrivate) +{ + d->init(this); + setText(text); +} + +KMessageWidget::~KMessageWidget() +{ + delete d; +} + +QString KMessageWidget::text() const +{ + return d->textLabel->text(); +} + +void KMessageWidget::setText(const QString &text) +{ + d->textLabel->setText(text); + updateGeometry(); +} + +int KMessageWidget::bestContentHeight() const +{ + return d->bestContentHeight(); +} + + +KMessageWidget::MessageType KMessageWidget::messageType() const +{ + return d->messageType; +} + +void KMessageWidget::setMessageType(KMessageWidget::MessageType type) +{ + d->messageType = type; + QColor bg0, bg1, bg2, border, fg; + + switch (type) { + case Positive: + bg1 = QColor("#72D594"); // nice green + fg = QColor(Qt::white); + break; + + case Information: + bg1 = QColor("#41A8E3"); // nice blue + fg = QColor(Qt::black); + break; + + case Warning: + bg1 = QColor("#FFCD0F"); // nice yellow + fg = QColor(Qt::black); + break; + + case Error: + bg1 = QColor("#FF7D7D"); // nice red. + fg = QColor(Qt::black); + break; + } + + // Colors + bg0 = bg1.lighter(110); + bg2 = bg1.darker(110); + border = bg2.darker(110); + d->content->setStyleSheet( + QString(".QFrame {" + "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," + " stop: 0 %1," + " stop: 0.1 %2," + " stop: 1.0 %3);" + "border-radius: 5px;" + "border: 1px solid %4;" + "margin: %5px;" + "}" + ".QLabel { color: %6; }").arg(bg0.name()) + .arg(bg1.name()) + .arg(bg2.name()) + .arg(border.name()) + /* + DefaultFrameWidth returns the size of the external margin + border width. + We know our border is 1px, so we subtract this from the frame + normal QStyle FrameWidth to get our margin + */ + .arg(style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this) - 1) + .arg(fg.name())); +} + +QSize KMessageWidget::sizeHint() const +{ + ensurePolished(); + return d->content->sizeHint(); +} + +QSize KMessageWidget::minimumSizeHint() const +{ + ensurePolished(); + return d->content->minimumSizeHint(); +} + +bool KMessageWidget::event(QEvent *event) +{ + if (event->type() == QEvent::Polish && !d->content->layout()) { + d->createLayout(); + } + + return QFrame::event(event); +} + +void KMessageWidget::resizeEvent(QResizeEvent *event) +{ + QFrame::resizeEvent(event); + + if (d->timeLine->state() == QTimeLine::NotRunning) { + d->content->resize(width(), d->bestContentHeight()); + } +} + +int KMessageWidget::heightForWidth(int width) const +{ + ensurePolished(); + return d->content->heightForWidth(width); +} + +void KMessageWidget::paintEvent(QPaintEvent *event) +{ + QFrame::paintEvent(event); + + if (d->timeLine->state() == QTimeLine::Running) { + QPainter painter(this); + painter.setOpacity(d->timeLine->currentValue() * d->timeLine->currentValue()); + painter.drawPixmap(0, 0, d->contentSnapShot); + } +} + +void KMessageWidget::showEvent(QShowEvent *event) +{ + // Keep this method here to avoid breaking binary compatibility: + // QFrame::showEvent() used to be reimplemented. + QFrame::showEvent(event); +} + +bool KMessageWidget::wordWrap() const +{ + return d->wordWrap; +} + +void KMessageWidget::setWordWrap(bool wordWrap) +{ + d->wordWrap = wordWrap; + d->textLabel->setWordWrap(wordWrap); + QSizePolicy policy = sizePolicy(); + policy.setHeightForWidth(wordWrap); + setSizePolicy(policy); + d->updateLayout(); + + // Without this, when user does wordWrap -> !wordWrap -> wordWrap, a minimum + // height is set, causing the widget to be too high. + // Mostly visible in test programs. + if (wordWrap) { + setMinimumHeight(0); + } +} + +bool KMessageWidget::isCloseButtonVisible() const +{ + return d->closeButton->isVisible(); +} + +void KMessageWidget::setCloseButtonVisible(bool show) +{ + d->closeButton->setVisible(show); + updateGeometry(); +} + +void KMessageWidget::addAction(QAction *action) +{ + QFrame::addAction(action); + d->updateLayout(); +} + +void KMessageWidget::removeAction(QAction *action) +{ + QFrame::removeAction(action); + d->updateLayout(); +} + +void KMessageWidget::animatedShow() +{ + if (isVisible()) { + return; + } + + QFrame::show(); + setFixedHeight(0); + int wantedHeight = d->bestContentHeight(); + d->content->setGeometry(0, -wantedHeight, width(), wantedHeight); + + d->updateSnapShot(); + + d->timeLine->setDirection(QTimeLine::Forward); + + if (d->timeLine->state() == QTimeLine::NotRunning) { + d->timeLine->start(); + } +} + +void KMessageWidget::animatedHide() +{ + if (!isVisible()) { + hide(); + return; + } + + d->content->move(0, -d->content->height()); + d->updateSnapShot(); + + d->timeLine->setDirection(QTimeLine::Backward); + + if (d->timeLine->state() == QTimeLine::NotRunning) { + d->timeLine->start(); + } +} + +QIcon KMessageWidget::icon() const +{ + return d->icon; +} + +void KMessageWidget::setIcon(const QIcon &icon) +{ + d->icon = icon; + + if (d->icon.isNull()) { + d->iconLabel->hide(); + } else { + d->iconLabel->setPixmap(d->icon.pixmap(QSize(16, 16))); + d->iconLabel->show(); + } +} diff --git a/src/gui/kmessagewidget.h b/src/gui/kmessagewidget.h new file mode 100644 index 000000000..dbc694afa --- /dev/null +++ b/src/gui/kmessagewidget.h @@ -0,0 +1,239 @@ +/* This file is part of the KDE libraries + * + * Copyright (c) 2011 Aurélien Gâteau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef KMESSAGEWIDGET_H +#define KMESSAGEWIDGET_H + +#include + +class KMessageWidgetPrivate; + +/** + * @short A widget to provide feedback or propose opportunistic interactions. + * + * KMessageWidget can be used to provide inline positive or negative + * feedback, or to implement opportunistic interactions. + * + * As a feedback widget, KMessageWidget provides a less intrusive alternative + * to "OK Only" message boxes. If you do not need the modalness of KMessageBox, + * consider using KMessageWidget instead. + * + * Negative feedback + * + * The KMessageWidget can be used as a secondary indicator of failure: the + * first indicator is usually the fact the action the user expected to happen + * did not happen. + * + * Example: User fills a form, clicks "Submit". + * + * @li Expected feedback: form closes + * @li First indicator of failure: form stays there + * @li Second indicator of failure: a KMessageWidget appears on top of the + * form, explaining the error condition + * + * When used to provide negative feedback, KMessageWidget should be placed + * close to its context. In the case of a form, it should appear on top of the + * form entries. + * + * KMessageWidget should get inserted in the existing layout. Space should not + * be reserved for it, otherwise it becomes "dead space", ignored by the user. + * KMessageWidget should also not appear as an overlay to prevent blocking + * access to elements the user needs to interact with to fix the failure. + * + * Positive feedback + * + * KMessageWidget can be used for positive feedback but it shouldn't be + * overused. It is often enough to provide feedback by simply showing the + * results of an action. + * + * Examples of acceptable uses: + * + * @li Confirm success of "critical" transactions + * @li Indicate completion of background tasks + * + * Example of inadapted uses: + * + * @li Indicate successful saving of a file + * @li Indicate a file has been successfully removed + * + * Opportunistic interaction + * + * Opportunistic interaction is the situation where the application suggests to + * the user an action he could be interested in perform, either based on an + * action the user just triggered or an event which the application noticed. + * + * Example of acceptable uses: + * + * @li A browser can propose remembering a recently entered password + * @li A music collection can propose ripping a CD which just got inserted + * @li A chat application may notify the user a "special friend" just connected + * + * @author Aurélien Gâteau + * @since 4.7 + */ +class KMessageWidget : public QFrame { + Q_OBJECT + Q_ENUMS(MessageType) + + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap) + Q_PROPERTY(bool closeButtonVisible READ isCloseButtonVisible WRITE setCloseButtonVisible) + Q_PROPERTY(MessageType messageType READ messageType WRITE setMessageType) + Q_PROPERTY(QIcon icon READ icon WRITE setIcon) +public: + enum MessageType { + Positive, + Information, + Warning, + Error + }; + + /** + * Constructs a KMessageWidget with the specified parent. + */ + explicit KMessageWidget(QWidget *parent = 0); + + explicit KMessageWidget(const QString &text, QWidget *parent = 0); + + ~KMessageWidget(); + + QString text() const; + + bool wordWrap() const; + + bool isCloseButtonVisible() const; + + MessageType messageType() const; + + void addAction(QAction *action); + + void removeAction(QAction *action); + + QSize sizeHint() const; + + QSize minimumSizeHint() const; + + int heightForWidth(int width) const; + + /** + * The icon shown on the left of the text. By default, no icon is shown. + * @since 4.11 + */ + QIcon icon() const; + +public +Q_SLOTS: + void setText(const QString &text); + + void setWordWrap(bool wordWrap); + + void setCloseButtonVisible(bool visible); + + void setMessageType(KMessageWidget::MessageType type); + + /** + * Show the widget using an animation, unless + * KGlobalSettings::graphicsEffectLevel() does not allow simple effects. + */ + void animatedShow(); + + /** + * Hide the widget using an animation, unless + * KGlobalSettings::graphicsEffectLevel() does not allow simple effects. + */ + void animatedHide(); + + /** + * Define an icon to be shown on the left of the text + * @since 4.11 + */ + void setIcon(const QIcon &icon); + + int bestContentHeight() const; +Q_SIGNALS: + /** + * This signal is emitted when the user clicks a link in the text label. + * The URL referred to by the href anchor is passed in contents. + * @param contents text of the href anchor + * @see QLabel::linkActivated() + * @since 4.10 + */ + void linkActivated(const QString &contents); + + /** + * This signal is emitted when the user hovers over a link in the text label. + * The URL referred to by the href anchor is passed in contents. + * @param contents text of the href anchor + * @see QLabel::linkHovered() + * @since 4.11 + */ + void linkHovered(const QString &contents); + +protected: + void paintEvent(QPaintEvent *event); + + bool event(QEvent *event); + + void resizeEvent(QResizeEvent *event); + + void showEvent(QShowEvent *event); + +private: + KMessageWidgetPrivate *const d; + friend class KMessageWidgetPrivate; + + Q_PRIVATE_SLOT(d, void slotTimeLineChanged(qreal)) + Q_PRIVATE_SLOT(d, void slotTimeLineFinished()) +}; + +//--------------------------------------------------------------------- +// KMessageWidgetPrivate +//--------------------------------------------------------------------- +class QLabel; +class QToolButton; +class QTimeLine; +#include + +class KMessageWidgetPrivate { +public: + void init(KMessageWidget *); + + KMessageWidget *q; + QFrame *content; + QLabel *iconLabel; + QLabel *textLabel; + QToolButton *closeButton; + QTimeLine *timeLine; + QIcon icon; + + KMessageWidget::MessageType messageType; + bool wordWrap; + QList buttons; + QPixmap contentSnapShot; + + void createLayout(); + void updateSnapShot(); + void updateLayout(); + void slotTimeLineChanged(qreal); + void slotTimeLineFinished(); + + int bestContentHeight() const; +}; + +#endif // KMESSAGEWIDGET_H From a710181388f7525b703c88aaa69fcd4c6d1c0d37 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 19 Jan 2015 23:14:59 +0000 Subject: [PATCH 02/12] Replaced MessageBox dialogs with inline MessageWidget in DatabaseOpenWidget. --- src/gui/DatabaseOpenWidget.cpp | 15 ++++++++++----- src/gui/DatabaseOpenWidget.ui | 11 ++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 781b836fd..fcc029ab6 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -35,6 +35,8 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent) { m_ui->setupUi(this); + m_ui->messageWidget->setHidden(true); + QFont font = m_ui->labelHeadline->font(); font.setBold(true); font.setPointSize(font.pointSize() + 2); @@ -106,8 +108,8 @@ void DatabaseOpenWidget::openDatabase() QFile file(m_filename); if (!file.open(QIODevice::ReadOnly)) { - MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n") - .append(file.errorString())); + m_ui->messageWidget->showMessageError( + tr("Unable to open the database.").append("\n").append(file.errorString())); return; } if (m_db) { @@ -118,11 +120,14 @@ void DatabaseOpenWidget::openDatabase() QApplication::restoreOverrideCursor(); if (m_db) { + if (m_ui->messageWidget->isVisible()) { + m_ui->messageWidget->animatedHide(); + } Q_EMIT editFinished(true); } else { - MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n") - .append(reader.errorString())); + m_ui->messageWidget->showMessageError(tr("Unable to open the database.") + .append("\n").append(reader.errorString())); m_ui->editPassword->clear(); } } @@ -142,7 +147,7 @@ CompositeKey DatabaseOpenWidget::databaseKey() QString keyFilename = m_ui->comboKeyFile->currentText(); QString errorMsg; if (!key.load(keyFilename, &errorMsg)) { - MessageBox::warning(this, tr("Error"), tr("Can't open key file").append(":\n").append(errorMsg)); + m_ui->messageWidget->showMessageError(tr("Can't open key file").append(":\n").append(errorMsg)); return CompositeKey(); } masterKey.addKey(key); diff --git a/src/gui/DatabaseOpenWidget.ui b/src/gui/DatabaseOpenWidget.ui index 4aae5faf2..f658d568a 100644 --- a/src/gui/DatabaseOpenWidget.ui +++ b/src/gui/DatabaseOpenWidget.ui @@ -10,10 +10,13 @@ 250 - + 8 + + + @@ -144,6 +147,12 @@ QLineEdit
gui/PasswordEdit.h
+ + MessageWidget + QWidget +
gui/MessageWidget.h
+ 1 +
checkPassword From 3c4af1a1945e079e205f50164f97198930bee52f Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 19 Jan 2015 23:27:57 +0000 Subject: [PATCH 03/12] Replace MessageBox dialogs that don't require user interaction with inline MessageWidget in ChangeMasterKeyWidget. --- src/gui/ChangeMasterKeyWidget.cpp | 6 ++++-- src/gui/ChangeMasterKeyWidget.ui | 11 ++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/gui/ChangeMasterKeyWidget.cpp b/src/gui/ChangeMasterKeyWidget.cpp index 3e346bc10..185ffc26f 100644 --- a/src/gui/ChangeMasterKeyWidget.cpp +++ b/src/gui/ChangeMasterKeyWidget.cpp @@ -30,6 +30,8 @@ ChangeMasterKeyWidget::ChangeMasterKeyWidget(QWidget* parent) { m_ui->setupUi(this); + m_ui->messageWidget->setHidden(true); + connect(m_ui->buttonBox, SIGNAL(accepted()), SLOT(generateKey())); connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(reject())); m_ui->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show")); @@ -52,7 +54,7 @@ void ChangeMasterKeyWidget::createKeyFile() QString errorMsg; bool created = FileKey::create(fileName, &errorMsg); if (!created) { - MessageBox::warning(this, tr("Error"), tr("Unable to create Key File : ") + errorMsg); + m_ui->messageWidget->showMessageError(tr("Unable to create Key File : ").append(errorMsg)); } else { m_ui->keyFileCombo->setEditText(fileName); @@ -110,7 +112,7 @@ void ChangeMasterKeyWidget::generateKey() m_key.addKey(PasswordKey(m_ui->enterPasswordEdit->text())); } else { - MessageBox::warning(this, tr("Error"), tr("Different passwords supplied.")); + m_ui->messageWidget->showMessageError(tr("Different passwords supplied.")); m_ui->enterPasswordEdit->setText(""); m_ui->repeatPasswordEdit->setText(""); return; diff --git a/src/gui/ChangeMasterKeyWidget.ui b/src/gui/ChangeMasterKeyWidget.ui index d14941ccc..4af497a53 100644 --- a/src/gui/ChangeMasterKeyWidget.ui +++ b/src/gui/ChangeMasterKeyWidget.ui @@ -7,10 +7,13 @@ 0 0 438 - 256 + 342
+ + + @@ -151,6 +154,12 @@ QLineEdit
gui/PasswordEdit.h
+ + MessageWidget + QWidget +
gui/MessageWidget.h
+ 1 +
passwordGroup From 8fa070f01cb707550393115cb2399f9ab6540de7 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 19 Jan 2015 23:47:57 +0000 Subject: [PATCH 04/12] Show inline message when unable to load the Key File. --- src/gui/ChangeMasterKeyWidget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/ChangeMasterKeyWidget.cpp b/src/gui/ChangeMasterKeyWidget.cpp index 185ffc26f..ba241875a 100644 --- a/src/gui/ChangeMasterKeyWidget.cpp +++ b/src/gui/ChangeMasterKeyWidget.cpp @@ -121,10 +121,10 @@ void ChangeMasterKeyWidget::generateKey() if (m_ui->keyFileGroup->isChecked()) { FileKey fileKey; QString errorMsg; - if (!fileKey.load(m_ui->keyFileCombo->currentText(), &errorMsg)) { - MessageBox::critical(this, tr("Failed to set key file"), - tr("Failed to set %1 as the Key file:\n%2") - .arg(m_ui->keyFileCombo->currentText(), errorMsg)); + QString fileKeyName = m_ui->keyFileCombo->currentText(); + if (!fileKey.load(fileKeyName, &errorMsg)) { + m_ui->messageWidget->showMessageError( + tr("Failed to set %1 as the Key file:\n%2: ").arg(fileKeyName, errorMsg)); return; } m_key.addKey(fileKey); From c2826bb1afdffe81e5234d28819a6eb9068d0b7a Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Tue, 20 Jan 2015 01:27:56 +0000 Subject: [PATCH 05/12] Replace MessageBox Dialog with inline MessageWidget in EditWidget and in UnlockDatabaseWidget. Add missing method to show Information Message. --- src/gui/EditWidget.cpp | 24 ++++++++++++++++++++++++ src/gui/EditWidget.h | 6 ++++++ src/gui/EditWidget.ui | 9 +++++++++ src/gui/MessageWidget.cpp | 5 +++++ src/gui/entry/EditEntryWidget.cpp | 23 ++++++++++------------- 5 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/gui/EditWidget.cpp b/src/gui/EditWidget.cpp index b3d9842be..c2f9551c4 100644 --- a/src/gui/EditWidget.cpp +++ b/src/gui/EditWidget.cpp @@ -25,6 +25,8 @@ EditWidget::EditWidget(QWidget* parent) m_ui->setupUi(this); setReadOnly(false); + m_ui->messageWidget->setHidden(true); + QFont headerLabelFont = m_ui->headerLabel->font(); headerLabelFont.setBold(true); headerLabelFont.setPointSize(headerLabelFont.pointSize() + 2); @@ -86,3 +88,25 @@ bool EditWidget::readOnly() const { return m_readOnly; } + +void EditWidget::showMessageError(const QString& text) +{ + m_ui->messageWidget->showMessageError(text); +} + +void EditWidget::showMessageWarning(const QString& text) +{ + m_ui->messageWidget->showMessageWarning(text); +} + +void EditWidget::showMessageInformation(const QString& text) +{ + m_ui->messageWidget->showMessageInformation(text); +} + +void EditWidget::hideMessage() +{ + if (m_ui->messageWidget->isVisible()) { + m_ui->messageWidget->animatedHide(); + } +} diff --git a/src/gui/EditWidget.h b/src/gui/EditWidget.h index c5f507ac9..97dfda880 100644 --- a/src/gui/EditWidget.h +++ b/src/gui/EditWidget.h @@ -48,6 +48,12 @@ Q_SIGNALS: void accepted(); void rejected(); +protected: + void showMessageError(const QString& text); + void showMessageWarning(const QString& text); + void showMessageInformation(const QString& text); + void hideMessage(); + private: const QScopedPointer m_ui; bool m_readOnly; diff --git a/src/gui/EditWidget.ui b/src/gui/EditWidget.ui index 3891007a1..05b06b909 100644 --- a/src/gui/EditWidget.ui +++ b/src/gui/EditWidget.ui @@ -11,6 +11,9 @@ + + + @@ -58,6 +61,12 @@ + + MessageWidget + QWidget +
gui/MessageWidget.h
+ 1 +
CategoryListWidget QListWidget diff --git a/src/gui/MessageWidget.cpp b/src/gui/MessageWidget.cpp index 1e6d06044..19badfea8 100644 --- a/src/gui/MessageWidget.cpp +++ b/src/gui/MessageWidget.cpp @@ -33,6 +33,11 @@ void MessageWidget::showMessageWarning(const QString& text) showMessage(text, MessageType::Warning); } +void MessageWidget::showMessageInformation(const QString& text) +{ + showMessage(text, MessageType::Information); +} + void MessageWidget::showMessagePositive(const QString& text) { showMessage(text, MessageType::Positive); diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index f2372a0d5..c56f70232 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -395,12 +395,13 @@ void EditEntryWidget::saveEntry() { if (m_history) { clear(); + hideMessage(); Q_EMIT editFinished(false); return; } if (!passwordsEqual()) { - MessageBox::warning(this, tr("Error"), tr("Different passwords supplied.")); + showMessageError(tr("Different passwords supplied.")); return; } @@ -474,6 +475,7 @@ void EditEntryWidget::cancel() { if (m_history) { clear(); + hideMessage(); Q_EMIT editFinished(false); return; } @@ -497,6 +499,7 @@ void EditEntryWidget::clear() m_autoTypeAssoc->clear(); m_historyModel->clear(); m_iconsWidget->reset(); + hideMessage(); } bool EditEntryWidget::hasBeenModified() const @@ -630,15 +633,13 @@ void EditEntryWidget::insertAttachment() QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { - MessageBox::warning(this, tr("Error"), - tr("Unable to open file").append(":\n").append(file.errorString())); + showMessageError(tr("Unable to open file").append(":\n").append(file.errorString())); return; } QByteArray data; if (!Tools::readAllFromDevice(&file, data)) { - MessageBox::warning(this, tr("Error"), - tr("Unable to open file").append(":\n").append(file.errorString())); + showMessageError(tr("Unable to open file").append(":\n").append(file.errorString())); return; } @@ -665,13 +666,11 @@ void EditEntryWidget::saveCurrentAttachment() QFile file(savePath); if (!file.open(QIODevice::WriteOnly)) { - MessageBox::warning(this, tr("Error"), - tr("Unable to save the attachment:\n").append(file.errorString())); + showMessageError(tr("Unable to save the attachment:\n").append(file.errorString())); return; } if (file.write(attachmentData) != attachmentData.size()) { - MessageBox::warning(this, tr("Error"), - tr("Unable to save the attachment:\n").append(file.errorString())); + showMessageError(tr("Unable to save the attachment:\n").append(file.errorString())); return; } } @@ -692,14 +691,12 @@ void EditEntryWidget::openAttachment(const QModelIndex& index) QTemporaryFile* file = new QTemporaryFile(tmpFileTemplate, this); if (!file->open()) { - MessageBox::warning(this, tr("Error"), - tr("Unable to save the attachment:\n").append(file->errorString())); + showMessageError(tr("Unable to save the attachment:\n").append(file->errorString())); return; } if (file->write(attachmentData) != attachmentData.size()) { - MessageBox::warning(this, tr("Error"), - tr("Unable to save the attachment:\n").append(file->errorString())); + showMessageError(tr("Unable to save the attachment:\n").append(file->errorString())); return; } From 13c85cdfcb507380b9e399229114cf6a3b9e8007 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Wed, 21 Jan 2015 16:19:05 +0000 Subject: [PATCH 06/12] Replace MessageBox with MessageWidget in remaining classes. Chnage to one method to set MessageWidget text passing type as parameter. Only messages with questions requiring user input reamin using MessageBox dialog. Use signal/slots to set message in MessageWidget and hide message, signal/slots only used when required.Maybe need to change all calls to signals/slots in the future. --- src/gui/ChangeMasterKeyWidget.cpp | 9 +++++---- src/gui/DatabaseOpenWidget.cpp | 11 +++++----- src/gui/DatabaseTabWidget.cpp | 22 +++++++++++++------- src/gui/DatabaseTabWidget.h | 6 ++++++ src/gui/DatabaseWidget.cpp | 23 +++++++++++++++++++-- src/gui/DatabaseWidget.h | 9 +++++++++ src/gui/DatabaseWidgetStateSync.cpp | 1 + src/gui/EditWidget.cpp | 14 ++----------- src/gui/EditWidget.h | 7 +++---- src/gui/EditWidgetIcons.cpp | 7 +++---- src/gui/EditWidgetIcons.h | 5 +++++ src/gui/KeePass1OpenWidget.cpp | 5 +++-- src/gui/MainWindow.cpp | 31 +++++++++++++++++++++++++++++ src/gui/MainWindow.h | 4 ++++ src/gui/MainWindow.ui | 30 +++++++++++++++++++++++++++- src/gui/MessageWidget.cpp | 28 +++++--------------------- src/gui/MessageWidget.h | 12 +++++------ src/gui/entry/EditEntryWidget.cpp | 17 +++++++++------- src/gui/group/EditGroupWidget.cpp | 3 +++ src/gui/group/EditGroupWidget.h | 2 ++ 20 files changed, 169 insertions(+), 77 deletions(-) diff --git a/src/gui/ChangeMasterKeyWidget.cpp b/src/gui/ChangeMasterKeyWidget.cpp index ba241875a..37fe9b0d4 100644 --- a/src/gui/ChangeMasterKeyWidget.cpp +++ b/src/gui/ChangeMasterKeyWidget.cpp @@ -54,7 +54,7 @@ void ChangeMasterKeyWidget::createKeyFile() QString errorMsg; bool created = FileKey::create(fileName, &errorMsg); if (!created) { - m_ui->messageWidget->showMessageError(tr("Unable to create Key File : ").append(errorMsg)); + m_ui->messageWidget->showMessage(tr("Unable to create Key File : ").append(errorMsg), MessageWidget::Error); } else { m_ui->keyFileCombo->setEditText(fileName); @@ -112,7 +112,7 @@ void ChangeMasterKeyWidget::generateKey() m_key.addKey(PasswordKey(m_ui->enterPasswordEdit->text())); } else { - m_ui->messageWidget->showMessageError(tr("Different passwords supplied.")); + m_ui->messageWidget->showMessage(tr("Different passwords supplied."), MessageWidget::Error); m_ui->enterPasswordEdit->setText(""); m_ui->repeatPasswordEdit->setText(""); return; @@ -123,13 +123,14 @@ void ChangeMasterKeyWidget::generateKey() QString errorMsg; QString fileKeyName = m_ui->keyFileCombo->currentText(); if (!fileKey.load(fileKeyName, &errorMsg)) { - m_ui->messageWidget->showMessageError( - tr("Failed to set %1 as the Key file:\n%2: ").arg(fileKeyName, errorMsg)); + m_ui->messageWidget->showMessage( + tr("Failed to set %1 as the Key file:\n%2").arg(fileKeyName, errorMsg), MessageWidget::Error); return; } m_key.addKey(fileKey); } + m_ui->messageWidget->hideMessage(); Q_EMIT editFinished(true); } diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index fcc029ab6..c9d266fae 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -108,8 +108,8 @@ void DatabaseOpenWidget::openDatabase() QFile file(m_filename); if (!file.open(QIODevice::ReadOnly)) { - m_ui->messageWidget->showMessageError( - tr("Unable to open the database.").append("\n").append(file.errorString())); + m_ui->messageWidget->showMessage( + tr("Unable to open the database.").append("\n").append(file.errorString()), MessageWidget::Error); return; } if (m_db) { @@ -126,8 +126,8 @@ void DatabaseOpenWidget::openDatabase() Q_EMIT editFinished(true); } else { - m_ui->messageWidget->showMessageError(tr("Unable to open the database.") - .append("\n").append(reader.errorString())); + m_ui->messageWidget->showMessage(tr("Unable to open the database.") + .append("\n").append(reader.errorString()), MessageWidget::Error); m_ui->editPassword->clear(); } } @@ -147,7 +147,8 @@ CompositeKey DatabaseOpenWidget::databaseKey() QString keyFilename = m_ui->comboKeyFile->currentText(); QString errorMsg; if (!key.load(keyFilename, &errorMsg)) { - m_ui->messageWidget->showMessageError(tr("Can't open key file").append(":\n").append(errorMsg)); + m_ui->messageWidget->showMessage(tr("Can't open key file").append(":\n") + .append(errorMsg), MessageWidget::Error); return CompositeKey(); } masterKey.addKey(key); diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 0c784eb2f..b1eb9a0a5 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -116,7 +116,7 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, QFileInfo fileInfo(fileName); QString canonicalFilePath = fileInfo.canonicalFilePath(); if (canonicalFilePath.isEmpty()) { - MessageBox::warning(this, tr("Warning"), tr("File not found!")); + Q_EMIT messageGlobal(tr("File not found!"), MessageWidget::Error); return; } @@ -136,8 +136,9 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, QFile file(fileName); if (!file.open(QIODevice::ReadWrite)) { if (!file.open(QIODevice::ReadOnly)) { - MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n") - .append(file.errorString())); + // can't open + Q_EMIT messageGlobal( + tr("Unable to open the database.").append("\n").append(file.errorString()), MessageWidget::Error); return; } else { @@ -184,6 +185,10 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, insertDatabase(db, dbStruct); + if (dbStruct.readOnly) { + Q_EMIT messageTab(tr("File opened in read only mode."), MessageWidget::Warning); + } + updateLastDatabases(dbStruct.filePath); if (!pw.isNull() || !keyFile.isEmpty()) { @@ -192,6 +197,7 @@ void DatabaseTabWidget::openDatabase(const QString& fileName, const QString& pw, else { dbStruct.dbWidget->switchToOpenDatabase(dbStruct.filePath); } + Q_EMIT messageDismissGlobal(); } void DatabaseTabWidget::mergeDatabase() @@ -332,6 +338,7 @@ bool DatabaseTabWidget::saveDatabase(Database* db) dbStruct.modified = false; dbStruct.dbWidget->databaseSaved(); updateTabName(db); + Q_EMIT messageDismissTab(); return true; } else { @@ -341,8 +348,8 @@ bool DatabaseTabWidget::saveDatabase(Database* db) } } else { - MessageBox::critical(this, tr("Error"), tr("Writing the database failed.") + "\n\n" - + saveFile.errorString()); + Q_EMIT messageTab(tr("Writing the database failed.\n") + .append("\n").append(saveFile.errorString()), MessageWidget::Error); return false; } } @@ -486,8 +493,9 @@ void DatabaseTabWidget::exportToCsv() CsvExporter csvExporter; if (!csvExporter.exportDatabase(fileName, db)) { - MessageBox::critical(this, tr("Error"), tr("Writing the CSV file failed.") + "\n\n" - + csvExporter.errorString()); + Q_EMIT messageGlobal( + tr("Writing the CSV file failed.").append("\n\n") + .append(csvExporter.errorString()), MessageWidget::Error); } } diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h index 24bdbde2f..8f01a987d 100644 --- a/src/gui/DatabaseTabWidget.h +++ b/src/gui/DatabaseTabWidget.h @@ -23,12 +23,14 @@ #include "format/KeePass2Writer.h" #include "gui/DatabaseWidget.h" +#include "gui/MessageWidget.h" class DatabaseWidget; class DatabaseWidgetStateSync; class DatabaseOpenWidget; class QFile; class QLockFile; +class MessageWidget; struct DatabaseManagerStruct { @@ -84,6 +86,10 @@ Q_SIGNALS: void activateDatabaseChanged(DatabaseWidget* dbWidget); void databaseLocked(DatabaseWidget* dbWidget); void databaseUnlocked(DatabaseWidget* dbWidget); + void messageGlobal(const QString&, MessageWidget::MessageType type); + void messageTab(const QString&, MessageWidget::MessageType type); + void messageDismissGlobal(); + void messageDismissTab(); private Q_SLOTS: void updateTabName(Database* db); diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 4a1298deb..74fc2d7cc 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -60,7 +60,14 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) , m_newParent(nullptr) { m_mainWidget = new QWidget(this); - QLayout* layout = new QHBoxLayout(m_mainWidget); + + m_messageWidget = new MessageWidget(this); + m_messageWidget->setHidden(true); + + QVBoxLayout* mainLayout = new QVBoxLayout(); + QLayout* layout = new QHBoxLayout(); + mainLayout->addWidget(m_messageWidget); + mainLayout->addLayout(layout); m_splitter = new QSplitter(m_mainWidget); m_splitter->setChildrenCollapsible(false); @@ -105,7 +112,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) m_splitter->setStretchFactor(1, 70); layout->addWidget(m_splitter); - m_mainWidget->setLayout(layout); + m_mainWidget->setLayout(mainLayout); m_editEntryWidget = new EditEntryWidget(); m_editEntryWidget->setObjectName("editEntryWidget"); @@ -1220,3 +1227,15 @@ void DatabaseWidget::closeUnlockDialog() { m_unlockDatabaseDialog->close(); } + +void DatabaseWidget::showMessage(const QString& text, MessageWidget::MessageType type) +{ + m_messageWidget->showMessage(text, type); +} + +void DatabaseWidget::hideMessage() +{ + if (m_messageWidget->isVisible()) { + m_messageWidget->animatedHide(); + } +} diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 79e58cecf..4133e52b4 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -26,6 +26,7 @@ #include "core/Uuid.h" #include "gui/entry/EntryModel.h" +#include "gui/MessageWidget.h" class ChangeMasterKeyWidget; class DatabaseOpenWidget; @@ -43,9 +44,14 @@ class QMenu; class QSplitter; class QLabel; class UnlockDatabaseWidget; +class MessageWidget; class UnlockDatabaseDialog; class QFileSystemWatcher; +namespace Ui { + class SearchWidget; +} + class DatabaseWidget : public QStackedWidget { Q_OBJECT @@ -145,6 +151,8 @@ public Q_SLOTS: void search(const QString& searchtext); void setSearchCaseSensitive(bool state); void endSearch(); + void showMessage(const QString& text, MessageWidget::MessageType type); + void hideMessage(); private Q_SLOTS: void entryActivationSignalReceived(Entry* entry, EntryModel::ModelColumn column); @@ -192,6 +200,7 @@ private: QString m_filename; Uuid m_groupBeforeLock; Uuid m_entryBeforeLock; + MessageWidget* m_messageWidget; // Search state QString m_lastSearchText; diff --git a/src/gui/DatabaseWidgetStateSync.cpp b/src/gui/DatabaseWidgetStateSync.cpp index fd5719f5a..1510d8440 100644 --- a/src/gui/DatabaseWidgetStateSync.cpp +++ b/src/gui/DatabaseWidgetStateSync.cpp @@ -149,3 +149,4 @@ QVariant DatabaseWidgetStateSync::intListToVariant(const QList& list) return result; } + diff --git a/src/gui/EditWidget.cpp b/src/gui/EditWidget.cpp index c2f9551c4..ef29f0132 100644 --- a/src/gui/EditWidget.cpp +++ b/src/gui/EditWidget.cpp @@ -89,19 +89,9 @@ bool EditWidget::readOnly() const return m_readOnly; } -void EditWidget::showMessageError(const QString& text) +void EditWidget::showMessage(const QString& text, MessageWidget::MessageType type) { - m_ui->messageWidget->showMessageError(text); -} - -void EditWidget::showMessageWarning(const QString& text) -{ - m_ui->messageWidget->showMessageWarning(text); -} - -void EditWidget::showMessageInformation(const QString& text) -{ - m_ui->messageWidget->showMessageInformation(text); + m_ui->messageWidget->showMessage(text, type); } void EditWidget::hideMessage() diff --git a/src/gui/EditWidget.h b/src/gui/EditWidget.h index 97dfda880..6f2c8f2dc 100644 --- a/src/gui/EditWidget.h +++ b/src/gui/EditWidget.h @@ -21,6 +21,7 @@ #include #include "gui/DialogyWidget.h" +#include "gui/MessageWidget.h" class QLabel; @@ -48,10 +49,8 @@ Q_SIGNALS: void accepted(); void rejected(); -protected: - void showMessageError(const QString& text); - void showMessageWarning(const QString& text); - void showMessageInformation(const QString& text); +protected Q_SLOTS: + void showMessage(const QString& text, MessageWidget::MessageType type); void hideMessage(); private: diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp index 145957ab9..fcfff5ca3 100644 --- a/src/gui/EditWidgetIcons.cpp +++ b/src/gui/EditWidgetIcons.cpp @@ -248,7 +248,7 @@ void EditWidgetIcons::addCustomIcon() m_ui->customIconsView->setCurrentIndex(index); } else { - MessageBox::critical(this, tr("Error"), tr("Can't read icon")); + Q_EMIT messageEditEntry(tr("Can't read icon"), MessageWidget::Error); } } } @@ -302,9 +302,8 @@ void EditWidgetIcons::removeCustomIcon() } } else { - MessageBox::information(this, tr("Can't delete icon!"), - tr("Can't delete icon. Still used by %1 items.") - .arg(iconUsedCount)); + Q_EMIT messageEditEntry( + tr("Can't delete icon. Still used by %1 items.").arg(iconUsedCount), MessageWidget::Error); } } } diff --git a/src/gui/EditWidgetIcons.h b/src/gui/EditWidgetIcons.h index 508c56864..ae5f86951 100644 --- a/src/gui/EditWidgetIcons.h +++ b/src/gui/EditWidgetIcons.h @@ -26,6 +26,7 @@ #include "core/Global.h" #include "core/Uuid.h" +#include "gui/MessageWidget.h" class Database; class DefaultIconModel; @@ -58,6 +59,10 @@ public: public Q_SLOTS: void setUrl(const QString &url); +Q_SIGNALS: + void messageEditEntry(QString, MessageWidget::MessageType); + void messageEditEntryDismiss(); + private Q_SLOTS: void downloadFavicon(); void fetchFavicon(QUrl url); diff --git a/src/gui/KeePass1OpenWidget.cpp b/src/gui/KeePass1OpenWidget.cpp index 4f70a9787..c5159aaba 100644 --- a/src/gui/KeePass1OpenWidget.cpp +++ b/src/gui/KeePass1OpenWidget.cpp @@ -65,8 +65,9 @@ void KeePass1OpenWidget::openDatabase() Q_EMIT editFinished(true); } else { - MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n") - .append(reader.errorString())); + m_ui->messageWidget->showMessage(tr("Unable to open the database.").append("\n") + .append(reader.errorString()), MessageWidget::Error); + m_ui->editPassword->clear(); } } diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 819bda5dc..92a9cbdd4 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -104,6 +104,7 @@ MainWindow::MainWindow() #endif setWindowIcon(filePath()->applicationIcon()); + m_ui->globalMessageWidget->setHidden(true); QAction* toggleViewAction = m_ui->toolBar->toggleViewAction(); toggleViewAction->setText(tr("Show toolbar")); m_ui->menuView->addAction(toggleViewAction); @@ -277,6 +278,11 @@ MainWindow::MainWindow() connect(m_ui->actionAbout, SIGNAL(triggered()), SLOT(showAboutDialog())); + connect(m_ui->tabWidget, SIGNAL(messageGlobal(QString,MessageWidget::MessageType)), this, SLOT(displayGlobalMessage(QString, MessageWidget::MessageType))); + connect(m_ui->tabWidget, SIGNAL(messageDismissGlobal()), this, SLOT(hideGlobalMessage())); + connect(m_ui->tabWidget, SIGNAL(messageTab(QString,MessageWidget::MessageType)), this, SLOT(displayTabMessage(QString, MessageWidget::MessageType))); + connect(m_ui->tabWidget, SIGNAL(messageDismissTab()), this, SLOT(hideTabMessage())); + updateTrayIcon(); } @@ -787,3 +793,28 @@ bool MainWindow::isTrayIconEnabled() const && QSystemTrayIcon::isSystemTrayAvailable(); #endif } + +void MainWindow::displayGlobalMessage(const QString& text, MessageWidget::MessageType type) +{ + m_ui->globalMessageWidget->showMessage(text, type); +} + +void MainWindow::displayTabMessage(const QString& text, MessageWidget::MessageType type) +{ + //if (m_ui->stackedWidget->currentIndex() == 0) { + m_ui->tabWidget->currentDatabaseWidget()->showMessage(text, type); + //} +} + +void MainWindow::hideGlobalMessage() +{ + m_ui->globalMessageWidget->hideMessage(); +} + +void MainWindow::hideTabMessage() +{ + if (m_ui->stackedWidget->currentIndex() == 0) { + m_ui->tabWidget->currentDatabaseWidget()->hideMessage(); + } +} + diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index ab9924a75..4182140c7 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -71,6 +71,10 @@ private Q_SLOTS: void toggleWindow(); void lockDatabasesAfterInactivity(); void repairDatabase(); + void displayGlobalMessage(const QString& text, MessageWidget::MessageType type); + void displayTabMessage(const QString& text, MessageWidget::MessageType type); + void hideGlobalMessage(); + void hideTabMessage(); private: static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0); diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index 188ef1586..bb7ff779c 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -2,6 +2,9 @@ MainWindow + + true + 0 @@ -14,6 +17,9 @@ KeePassXC + + true + 0 @@ -27,8 +33,24 @@ 0 + + + + + 0 + 0 + + + + + + + 0 + 0 + + 2 @@ -104,7 +126,7 @@ 0 0 800 - 26 + 29 @@ -452,6 +474,12 @@ + + MessageWidget + QWidget +
gui/MessageWidget.h
+ 1 +
DatabaseTabWidget QTabWidget diff --git a/src/gui/MessageWidget.cpp b/src/gui/MessageWidget.cpp index 19badfea8..15e6b2562 100644 --- a/src/gui/MessageWidget.cpp +++ b/src/gui/MessageWidget.cpp @@ -23,32 +23,14 @@ MessageWidget::MessageWidget(QWidget* parent) } -void MessageWidget::showMessageError(const QString& text) -{ - showMessage(text, MessageType::Error); -} - -void MessageWidget::showMessageWarning(const QString& text) -{ - showMessage(text, MessageType::Warning); -} - -void MessageWidget::showMessageInformation(const QString& text) -{ - showMessage(text, MessageType::Information); -} - -void MessageWidget::showMessagePositive(const QString& text) -{ - showMessage(text, MessageType::Positive); -} - -void MessageWidget::showMessage(const QString& text, MessageType type) +void MessageWidget::showMessage(const QString& text, MessageWidget::MessageType type) { setMessageType(type); setText(text); animatedShow(); } - - +void MessageWidget::hideMessage() +{ + animatedHide(); +} diff --git a/src/gui/MessageWidget.h b/src/gui/MessageWidget.h index 6e8366fae..af97c6f4c 100644 --- a/src/gui/MessageWidget.h +++ b/src/gui/MessageWidget.h @@ -7,15 +7,15 @@ class MessageWidget : public KMessageWidget { + Q_OBJECT + public: explicit MessageWidget(QWidget* parent = 0); - void showMessageError(const QString& text); - void showMessageWarning(const QString& text); - void showMessageInformation(const QString& text); - void showMessagePositive(const QString& text); -private: - void showMessage(const QString& text, MessageType type); +public Q_SLOTS: + void showMessage(const QString& text, MessageWidget::MessageType type); + void hideMessage(); + }; #endif // MESSAGEWIDGET_H diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index c56f70232..d9b235f3b 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -77,6 +77,9 @@ EditEntryWidget::EditEntryWidget(QWidget* parent) connect(this, SIGNAL(accepted()), SLOT(saveEntry())); connect(this, SIGNAL(rejected()), SLOT(cancel())); + + connect(m_iconsWidget, SIGNAL(messageEditEntry(QString, MessageWidget::MessageType)), SLOT(showMessage(QString, MessageWidget::MessageType))); + connect(m_iconsWidget, SIGNAL(messageEditEntryDismiss()), SLOT(hideMessage())); } EditEntryWidget::~EditEntryWidget() @@ -401,7 +404,7 @@ void EditEntryWidget::saveEntry() } if (!passwordsEqual()) { - showMessageError(tr("Different passwords supplied.")); + showMessage(tr("Different passwords supplied."), MessageWidget::Error); return; } @@ -633,13 +636,13 @@ void EditEntryWidget::insertAttachment() QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { - showMessageError(tr("Unable to open file").append(":\n").append(file.errorString())); + showMessage(tr("Unable to open file").append(":\n").append(file.errorString()), MessageWidget::Error); return; } QByteArray data; if (!Tools::readAllFromDevice(&file, data)) { - showMessageError(tr("Unable to open file").append(":\n").append(file.errorString())); + showMessage(tr("Unable to open file").append(":\n").append(file.errorString()), MessageWidget::Error); return; } @@ -666,11 +669,11 @@ void EditEntryWidget::saveCurrentAttachment() QFile file(savePath); if (!file.open(QIODevice::WriteOnly)) { - showMessageError(tr("Unable to save the attachment:\n").append(file.errorString())); + showMessage(tr("Unable to save the attachment:\n").append(file.errorString()), MessageWidget::Error); return; } if (file.write(attachmentData) != attachmentData.size()) { - showMessageError(tr("Unable to save the attachment:\n").append(file.errorString())); + showMessage(tr("Unable to save the attachment:\n").append(file.errorString()), MessageWidget::Error); return; } } @@ -691,12 +694,12 @@ void EditEntryWidget::openAttachment(const QModelIndex& index) QTemporaryFile* file = new QTemporaryFile(tmpFileTemplate, this); if (!file->open()) { - showMessageError(tr("Unable to save the attachment:\n").append(file->errorString())); + showMessage(tr("Unable to save the attachment:\n").append(file->errorString()), MessageWidget::Error); return; } if (file->write(attachmentData) != attachmentData.size()) { - showMessageError(tr("Unable to save the attachment:\n").append(file->errorString())); + showMessage(tr("Unable to save the attachment:\n").append(file->errorString()), MessageWidget::Error); return; } diff --git a/src/gui/group/EditGroupWidget.cpp b/src/gui/group/EditGroupWidget.cpp index 177c62bb0..5b9dfcbc8 100644 --- a/src/gui/group/EditGroupWidget.cpp +++ b/src/gui/group/EditGroupWidget.cpp @@ -43,6 +43,9 @@ EditGroupWidget::EditGroupWidget(QWidget* parent) connect(this, SIGNAL(accepted()), SLOT(save())); connect(this, SIGNAL(rejected()), SLOT(cancel())); + + connect(m_editGroupWidgetIcons, SIGNAL(messageEditEntry(QString, MessageWidget::MessageType)), SLOT(showMessage(QString, MessageWidget::MessageType))); + connect(m_editGroupWidgetIcons, SIGNAL(messageEditEntryDismiss()), SLOT(hideMessage())); } EditGroupWidget::~EditGroupWidget() diff --git a/src/gui/group/EditGroupWidget.h b/src/gui/group/EditGroupWidget.h index 94ad891db..606cc77b0 100644 --- a/src/gui/group/EditGroupWidget.h +++ b/src/gui/group/EditGroupWidget.h @@ -45,6 +45,8 @@ public: Q_SIGNALS: void editFinished(bool accepted); + void messageEditEntry(QString, MessageWidget::MessageType); + void messageEditEntryDismiss(); private Q_SLOTS: void save(); From 6e7f826e19620565d6b6757dd6164af74a95fd4f Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Wed, 21 Jan 2015 17:01:59 +0000 Subject: [PATCH 07/12] Added licence header. --- src/gui/MessageWidget.cpp | 2 +- src/gui/MessageWidget.h | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/gui/MessageWidget.cpp b/src/gui/MessageWidget.cpp index 15e6b2562..9360a6e62 100644 --- a/src/gui/MessageWidget.cpp +++ b/src/gui/MessageWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Felix Geyer + * Copyright (C) 2015 Pedro Alves * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/MessageWidget.h b/src/gui/MessageWidget.h index af97c6f4c..0e7d8a307 100644 --- a/src/gui/MessageWidget.h +++ b/src/gui/MessageWidget.h @@ -1,4 +1,19 @@ - +/* + * Copyright (C) 2015 Pedro Alves + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #ifndef MESSAGEWIDGET_H #define MESSAGEWIDGET_H From 84222e80787cf90358984a449df3846e156692cb Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Sun, 15 Jan 2017 01:10:26 +0100 Subject: [PATCH 08/12] Add license notice for KMessageWidget --- COPYING | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/COPYING b/COPYING index 9322a0e37..0495b912f 100644 --- a/COPYING +++ b/COPYING @@ -198,3 +198,9 @@ Files: src/zxcvbn/zxcvbn.* Copyright: 2015, Tony Evans 2016, KeePassXC Team License: BSD 3-clause + +Files: src/gui/kmessagewidget.h + src/gui/kmessagewidget.cpp +Copyright: 2011 Aurélien Gâteau + 2014 Dominik Haumann +License: LGPL-2.1 From b6ea06ba245e44923fe136f4734b81111d93a155 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Sun, 15 Jan 2017 01:10:46 +0100 Subject: [PATCH 09/12] Update KMessageWidget --- src/gui/kmessagewidget.cpp | 603 ++++++++++++++++++++----------------- src/gui/kmessagewidget.h | 397 +++++++++++++++--------- 2 files changed, 579 insertions(+), 421 deletions(-) diff --git a/src/gui/kmessagewidget.cpp b/src/gui/kmessagewidget.cpp index e5aafd61a..ee3c1b69c 100644 --- a/src/gui/kmessagewidget.cpp +++ b/src/gui/kmessagewidget.cpp @@ -1,6 +1,7 @@ /* This file is part of the KDE libraries - * + * * Copyright (c) 2011 Aurélien Gâteau + * Copyright (c) 2014 Dominik Haumann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,407 +20,461 @@ */ #include "kmessagewidget.h" +#include #include #include -#include +#include #include #include #include #include #include #include -#include + +//--------------------------------------------------------------------- +// KMessageWidgetPrivate +//--------------------------------------------------------------------- +class KMessageWidgetPrivate +{ +public: + void init(KMessageWidget *); + + KMessageWidget *q; + QFrame *content; + QLabel *iconLabel; + QLabel *textLabel; + QToolButton *closeButton; + QTimeLine *timeLine; + QIcon icon; + + KMessageWidget::MessageType messageType; + bool wordWrap; + QList buttons; + QPixmap contentSnapShot; + + void createLayout(); + void updateSnapShot(); + void updateLayout(); + void slotTimeLineChanged(qreal); + void slotTimeLineFinished(); + + int bestContentHeight() const; +}; void KMessageWidgetPrivate::init(KMessageWidget *q_ptr) { - q = q_ptr; - - q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); - - timeLine = new QTimeLine(500, q); - QObject::connect(timeLine, SIGNAL(valueChanged(qreal)), q, SLOT(slotTimeLineChanged(qreal))); - QObject::connect(timeLine, SIGNAL(finished()), q, SLOT(slotTimeLineFinished())); - - content = new QFrame(q); - content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - - wordWrap = false; - - iconLabel = new QLabel(content); - iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - iconLabel->hide(); - - textLabel = new QLabel(content); - textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - textLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - QObject::connect(textLabel, SIGNAL(linkActivated(const QString &)), q, SIGNAL(linkActivated(const QString &))); - QObject::connect(textLabel, SIGNAL(linkHovered(const QString &)), q, SIGNAL(linkHovered(const QString &))); - - QAction *closeAction = new QAction(QObject::tr("Close"), q); - q->connect(closeAction, SIGNAL(triggered(bool)), q, SLOT(animatedHide())); - - closeButton = new QToolButton(content); - closeButton->setAutoRaise(true); - closeButton->setDefaultAction(closeAction); - closeButton->setVisible(true); - q->setMessageType(KMessageWidget::Information); + q = q_ptr; + + q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + + timeLine = new QTimeLine(500, q); + QObject::connect(timeLine, SIGNAL(valueChanged(qreal)), q, SLOT(slotTimeLineChanged(qreal))); + QObject::connect(timeLine, SIGNAL(finished()), q, SLOT(slotTimeLineFinished())); + + content = new QFrame(q); + content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + wordWrap = false; + + iconLabel = new QLabel(content); + iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + iconLabel->hide(); + + textLabel = new QLabel(content); + textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + textLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + QObject::connect(textLabel, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString))); + QObject::connect(textLabel, SIGNAL(linkHovered(QString)), q, SIGNAL(linkHovered(QString))); + + QAction *closeAction = new QAction(q); + closeAction->setText(KMessageWidget::tr("&Close")); + closeAction->setToolTip(KMessageWidget::tr("Close message")); + closeAction->setIcon(q->style()->standardIcon(QStyle::SP_DialogCloseButton)); + + QObject::connect(closeAction, SIGNAL(triggered(bool)), q, SLOT(animatedHide())); + + closeButton = new QToolButton(content); + closeButton->setAutoRaise(true); + closeButton->setDefaultAction(closeAction); + + q->setMessageType(KMessageWidget::Information); } void KMessageWidgetPrivate::createLayout() { - delete content->layout(); - - content->resize(q->size()); - - qDeleteAll(buttons); - buttons.clear(); - - Q_FOREACH (QAction *action, q->actions()) { - QToolButton *button = new QToolButton(content); - button->setDefaultAction(action); - button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - buttons.append(button); - } - - // AutoRaise reduces visual clutter, but we don't want to turn it on if - // there are other buttons, otherwise the close button will look different - // from the others. - closeButton->setAutoRaise(buttons.isEmpty()); - - if (wordWrap) { - QGridLayout *layout = new QGridLayout(content); - // Set alignment to make sure icon does not move down if text wraps - layout->addWidget(iconLabel, 0, 0, 1, 1, Qt::AlignHCenter | Qt::AlignTop); - layout->addWidget(textLabel, 0, 1); - - QDialogButtonBox *buttonLayout = new QDialogButtonBox(); - //buttonLayout->addStretch(); - Q_FOREACH (QToolButton *button, buttons) { - // For some reason, calling show() is necessary if wordwrap is true, - // otherwise the buttons do not show up. It is not needed if - // wordwrap is false. - button->show(); - buttonLayout->addButton(button, QDialogButtonBox::QDialogButtonBox::AcceptRole); - } - buttonLayout->addButton(closeButton, QDialogButtonBox::RejectRole); - layout->addWidget(buttonLayout, 1, 0, 1, 2, Qt::AlignHCenter | Qt::AlignTop); - } else { - bool closeButtonVisible = closeButton->isVisible(); - QHBoxLayout *layout = new QHBoxLayout(content); - layout->addWidget(iconLabel); - layout->addWidget(textLabel); - - QDialogButtonBox *buttonLayout = new QDialogButtonBox(); - Q_FOREACH (QToolButton *button, buttons) { - buttonLayout->addButton(button, QDialogButtonBox::QDialogButtonBox::AcceptRole); - } - - buttonLayout->addButton(closeButton, QDialogButtonBox::RejectRole); - // Something gets changed when added to the buttonLayout - closeButton->setVisible(closeButtonVisible); - layout->addWidget(buttonLayout); - }; - - if (q->isVisible()) { - q->setFixedHeight(content->sizeHint().height()); - } - - q->updateGeometry(); + delete content->layout(); + + content->resize(q->size()); + + qDeleteAll(buttons); + buttons.clear(); + + Q_FOREACH (QAction *action, q->actions()) { + QToolButton *button = new QToolButton(content); + button->setDefaultAction(action); + button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + buttons.append(button); + } + + // AutoRaise reduces visual clutter, but we don't want to turn it on if + // there are other buttons, otherwise the close button will look different + // from the others. + closeButton->setAutoRaise(buttons.isEmpty()); + + if (wordWrap) { + QGridLayout *layout = new QGridLayout(content); + // Set alignment to make sure icon does not move down if text wraps + layout->addWidget(iconLabel, 0, 0, 1, 1, Qt::AlignHCenter | Qt::AlignTop); + layout->addWidget(textLabel, 0, 1); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addStretch(); + Q_FOREACH (QToolButton *button, buttons) { + // For some reason, calling show() is necessary if wordwrap is true, + // otherwise the buttons do not show up. It is not needed if + // wordwrap is false. + button->show(); + buttonLayout->addWidget(button); + } + buttonLayout->addWidget(closeButton); + layout->addItem(buttonLayout, 1, 0, 1, 2); + } else { + QHBoxLayout *layout = new QHBoxLayout(content); + layout->addWidget(iconLabel); + layout->addWidget(textLabel); + + Q_FOREACH (QToolButton *button, buttons) { + layout->addWidget(button); + } + + layout->addWidget(closeButton); + }; + + if (q->isVisible()) { + q->setFixedHeight(content->sizeHint().height()); + } + q->updateGeometry(); } void KMessageWidgetPrivate::updateLayout() { - if (content->layout()) { - createLayout(); - } + if (content->layout()) { + createLayout(); + } } void KMessageWidgetPrivate::updateSnapShot() { - // Attention: updateSnapShot calls QWidget::render(), which causes the whole - // window layouts to be activated. Calling this method from resizeEvent() - // can lead to infinite recursion, see: - // https://bugs.kde.org/show_bug.cgi?id=311336 - contentSnapShot = QPixmap(content->size()); - contentSnapShot.fill(Qt::transparent); - content->render(&contentSnapShot, QPoint(), QRegion(), QWidget::DrawChildren); + // Attention: updateSnapShot calls QWidget::render(), which causes the whole + // window layouts to be activated. Calling this method from resizeEvent() + // can lead to infinite recursion, see: + // https://bugs.kde.org/show_bug.cgi?id=311336 + contentSnapShot = QPixmap(content->size() * q->devicePixelRatio()); + contentSnapShot.setDevicePixelRatio(q->devicePixelRatio()); + contentSnapShot.fill(Qt::transparent); + content->render(&contentSnapShot, QPoint(), QRegion(), QWidget::DrawChildren); } void KMessageWidgetPrivate::slotTimeLineChanged(qreal value) { - q->setFixedHeight(qMin(value * 2, qreal(1.0)) * content->height()); - q->update(); + q->setFixedHeight(qMin(value * 2, qreal(1.0)) * content->height()); + q->update(); } void KMessageWidgetPrivate::slotTimeLineFinished() { - if (timeLine->direction() == QTimeLine::Forward) { - // Show - // We set the whole geometry here, because it may be wrong if a - // KMessageWidget is shown right when the toplevel window is created. - content->setGeometry(0, 0, q->width(), bestContentHeight()); - } else { - // Hide - q->hide(); - } + if (timeLine->direction() == QTimeLine::Forward) { + // Show + // We set the whole geometry here, because it may be wrong if a + // KMessageWidget is shown right when the toplevel window is created. + content->setGeometry(0, 0, q->width(), bestContentHeight()); + + // notify about finished animation + emit q->showAnimationFinished(); + } else { + // hide and notify about finished animation + q->hide(); + emit q->hideAnimationFinished(); + } } int KMessageWidgetPrivate::bestContentHeight() const { - int height = content->heightForWidth(q->width()); - - if (height == -1) { - height = content->sizeHint().height(); - } - - return height; + int height = content->heightForWidth(q->width()); + if (height == -1) { + height = content->sizeHint().height(); + } + return height; } - //--------------------------------------------------------------------- // KMessageWidget //--------------------------------------------------------------------- -KMessageWidget::KMessageWidget(QWidget *parent) : QFrame(parent), d(new KMessageWidgetPrivate) +KMessageWidget::KMessageWidget(QWidget *parent) +: QFrame(parent) +, d(new KMessageWidgetPrivate) { - d->init(this); + d->init(this); } -KMessageWidget::KMessageWidget(const QString &text, QWidget *parent) : QFrame(parent), d(new KMessageWidgetPrivate) +KMessageWidget::KMessageWidget(const QString &text, QWidget *parent) +: QFrame(parent) +, d(new KMessageWidgetPrivate) { - d->init(this); - setText(text); + d->init(this); + setText(text); } KMessageWidget::~KMessageWidget() { - delete d; + delete d; } QString KMessageWidget::text() const { - return d->textLabel->text(); + return d->textLabel->text(); } void KMessageWidget::setText(const QString &text) { - d->textLabel->setText(text); - updateGeometry(); + d->textLabel->setText(text); + updateGeometry(); } -int KMessageWidget::bestContentHeight() const -{ - return d->bestContentHeight(); -} - - KMessageWidget::MessageType KMessageWidget::messageType() const { - return d->messageType; + return d->messageType; +} + +static QColor darkShade(QColor c) +{ + qreal contrast = 0.7; // taken from kcolorscheme for the dark shade + + qreal darkAmount; + if (c.lightnessF() < 0.006) { /* too dark */ + darkAmount = 0.02 + 0.40 * contrast; + } else if (c.lightnessF() > 0.93) { /* too bright */ + darkAmount = -0.06 - 0.60 * contrast; + } else { + darkAmount = (-c.lightnessF()) * (0.55 + contrast * 0.35); + } + + qreal v = c.lightnessF() + darkAmount; + v = v > 0.0 ? (v < 1.0 ? v : 1.0) : 0.0; + c.setHsvF(c.hslHueF(), c.hslSaturationF(), v); + return c; } void KMessageWidget::setMessageType(KMessageWidget::MessageType type) { - d->messageType = type; - QColor bg0, bg1, bg2, border, fg; - - switch (type) { - case Positive: - bg1 = QColor("#72D594"); // nice green - fg = QColor(Qt::white); - break; - - case Information: - bg1 = QColor("#41A8E3"); // nice blue - fg = QColor(Qt::black); - break; - - case Warning: - bg1 = QColor("#FFCD0F"); // nice yellow - fg = QColor(Qt::black); - break; - - case Error: - bg1 = QColor("#FF7D7D"); // nice red. - fg = QColor(Qt::black); - break; - } - - // Colors - bg0 = bg1.lighter(110); - bg2 = bg1.darker(110); - border = bg2.darker(110); - d->content->setStyleSheet( - QString(".QFrame {" - "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," - " stop: 0 %1," - " stop: 0.1 %2," - " stop: 1.0 %3);" - "border-radius: 5px;" - "border: 1px solid %4;" - "margin: %5px;" - "}" - ".QLabel { color: %6; }").arg(bg0.name()) - .arg(bg1.name()) - .arg(bg2.name()) - .arg(border.name()) - /* - DefaultFrameWidth returns the size of the external margin + border width. - We know our border is 1px, so we subtract this from the frame - normal QStyle FrameWidth to get our margin - */ - .arg(style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this) - 1) - .arg(fg.name())); + d->messageType = type; + QColor bg0, bg1, bg2, border, fg; + switch (type) { + case Positive: + bg1.setRgb(0, 110, 40); // values taken from kcolorscheme.cpp (Positive) + break; + case Information: + bg1 = palette().highlight().color(); + break; + case Warning: + bg1.setRgb(176, 128, 0); // values taken from kcolorscheme.cpp (Neutral) + break; + case Error: + bg1.setRgb(191, 3, 3); // values taken from kcolorscheme.cpp (Negative) + break; + } + + // Colors + fg = palette().highlightedText().color(); + bg0 = bg1.lighter(110); + bg2 = bg1.darker(110); + border = darkShade(bg1); + + d->content->setStyleSheet( + QString(QLatin1String(".QFrame {" + "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," + " stop: 0 %1," + " stop: 0.1 %2," + " stop: 1.0 %3);" + "border-radius: 5px;" + "border: 1px solid %4;" + "margin: %5px;" + "}" + ".QLabel { color: %6; }" + )) + .arg(bg0.name()) + .arg(bg1.name()) + .arg(bg2.name()) + .arg(border.name()) + // DefaultFrameWidth returns the size of the external margin + border width. We know our border is 1px, so we subtract this from the frame normal QStyle FrameWidth to get our margin + .arg(style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this) - 1) + .arg(fg.name()) + ); } QSize KMessageWidget::sizeHint() const { - ensurePolished(); - return d->content->sizeHint(); + ensurePolished(); + return d->content->sizeHint(); } QSize KMessageWidget::minimumSizeHint() const { - ensurePolished(); - return d->content->minimumSizeHint(); + ensurePolished(); + return d->content->minimumSizeHint(); } bool KMessageWidget::event(QEvent *event) { - if (event->type() == QEvent::Polish && !d->content->layout()) { - d->createLayout(); - } - - return QFrame::event(event); + if (event->type() == QEvent::Polish && !d->content->layout()) { + d->createLayout(); + } + return QFrame::event(event); } void KMessageWidget::resizeEvent(QResizeEvent *event) { - QFrame::resizeEvent(event); - - if (d->timeLine->state() == QTimeLine::NotRunning) { - d->content->resize(width(), d->bestContentHeight()); - } + QFrame::resizeEvent(event); + + if (d->timeLine->state() == QTimeLine::NotRunning) { + d->content->resize(width(), d->bestContentHeight()); + } } int KMessageWidget::heightForWidth(int width) const { - ensurePolished(); - return d->content->heightForWidth(width); + ensurePolished(); + return d->content->heightForWidth(width); } void KMessageWidget::paintEvent(QPaintEvent *event) { - QFrame::paintEvent(event); - - if (d->timeLine->state() == QTimeLine::Running) { - QPainter painter(this); - painter.setOpacity(d->timeLine->currentValue() * d->timeLine->currentValue()); - painter.drawPixmap(0, 0, d->contentSnapShot); - } -} - -void KMessageWidget::showEvent(QShowEvent *event) -{ - // Keep this method here to avoid breaking binary compatibility: - // QFrame::showEvent() used to be reimplemented. - QFrame::showEvent(event); + QFrame::paintEvent(event); + if (d->timeLine->state() == QTimeLine::Running) { + QPainter painter(this); + painter.setOpacity(d->timeLine->currentValue() * d->timeLine->currentValue()); + painter.drawPixmap(0, 0, d->contentSnapShot); + } } bool KMessageWidget::wordWrap() const { - return d->wordWrap; + return d->wordWrap; } void KMessageWidget::setWordWrap(bool wordWrap) { - d->wordWrap = wordWrap; - d->textLabel->setWordWrap(wordWrap); - QSizePolicy policy = sizePolicy(); - policy.setHeightForWidth(wordWrap); - setSizePolicy(policy); - d->updateLayout(); - - // Without this, when user does wordWrap -> !wordWrap -> wordWrap, a minimum - // height is set, causing the widget to be too high. - // Mostly visible in test programs. - if (wordWrap) { - setMinimumHeight(0); - } + d->wordWrap = wordWrap; + d->textLabel->setWordWrap(wordWrap); + QSizePolicy policy = sizePolicy(); + policy.setHeightForWidth(wordWrap); + setSizePolicy(policy); + d->updateLayout(); + // Without this, when user does wordWrap -> !wordWrap -> wordWrap, a minimum + // height is set, causing the widget to be too high. + // Mostly visible in test programs. + if (wordWrap) { + setMinimumHeight(0); + } } bool KMessageWidget::isCloseButtonVisible() const { - return d->closeButton->isVisible(); + return d->closeButton->isVisible(); } void KMessageWidget::setCloseButtonVisible(bool show) { - d->closeButton->setVisible(show); - updateGeometry(); + d->closeButton->setVisible(show); + updateGeometry(); } void KMessageWidget::addAction(QAction *action) { - QFrame::addAction(action); - d->updateLayout(); + QFrame::addAction(action); + d->updateLayout(); } void KMessageWidget::removeAction(QAction *action) { - QFrame::removeAction(action); - d->updateLayout(); + QFrame::removeAction(action); + d->updateLayout(); } void KMessageWidget::animatedShow() { - if (isVisible()) { - return; - } - - QFrame::show(); - setFixedHeight(0); - int wantedHeight = d->bestContentHeight(); - d->content->setGeometry(0, -wantedHeight, width(), wantedHeight); - - d->updateSnapShot(); - - d->timeLine->setDirection(QTimeLine::Forward); - - if (d->timeLine->state() == QTimeLine::NotRunning) { - d->timeLine->start(); - } + if (!style()->styleHint(QStyle::SH_Widget_Animate, 0, this)) { + show(); + emit showAnimationFinished(); + return; + } + + if (isVisible()) { + return; + } + + QFrame::show(); + setFixedHeight(0); + int wantedHeight = d->bestContentHeight(); + d->content->setGeometry(0, -wantedHeight, width(), wantedHeight); + + d->updateSnapShot(); + + d->timeLine->setDirection(QTimeLine::Forward); + if (d->timeLine->state() == QTimeLine::NotRunning) { + d->timeLine->start(); + } } void KMessageWidget::animatedHide() { - if (!isVisible()) { - hide(); - return; - } + if (!style()->styleHint(QStyle::SH_Widget_Animate, 0, this)) { + hide(); + emit hideAnimationFinished(); + return; + } + + if (!isVisible()) { + hide(); + return; + } + + d->content->move(0, -d->content->height()); + d->updateSnapShot(); + + d->timeLine->setDirection(QTimeLine::Backward); + if (d->timeLine->state() == QTimeLine::NotRunning) { + d->timeLine->start(); + } +} - d->content->move(0, -d->content->height()); - d->updateSnapShot(); +bool KMessageWidget::isHideAnimationRunning() const +{ + return (d->timeLine->direction() == QTimeLine::Backward) + && (d->timeLine->state() == QTimeLine::Running); +} - d->timeLine->setDirection(QTimeLine::Backward); - - if (d->timeLine->state() == QTimeLine::NotRunning) { - d->timeLine->start(); - } +bool KMessageWidget::isShowAnimationRunning() const +{ + return (d->timeLine->direction() == QTimeLine::Forward) + && (d->timeLine->state() == QTimeLine::Running); } QIcon KMessageWidget::icon() const { - return d->icon; + return d->icon; } void KMessageWidget::setIcon(const QIcon &icon) { - d->icon = icon; - - if (d->icon.isNull()) { - d->iconLabel->hide(); - } else { - d->iconLabel->setPixmap(d->icon.pixmap(QSize(16, 16))); - d->iconLabel->show(); - } + d->icon = icon; + if (d->icon.isNull()) { + d->iconLabel->hide(); + } else { + const int size = style()->pixelMetric(QStyle::PM_ToolBarIconSize); + d->iconLabel->setPixmap(d->icon.pixmap(size)); + d->iconLabel->show(); + } } + +#include "moc_kmessagewidget.cpp" diff --git a/src/gui/kmessagewidget.h b/src/gui/kmessagewidget.h index dbc694afa..4398e0f99 100644 --- a/src/gui/kmessagewidget.h +++ b/src/gui/kmessagewidget.h @@ -1,6 +1,7 @@ /* This file is part of the KDE libraries - * + * * Copyright (c) 2011 Aurélien Gâteau + * Copyright (c) 2014 Dominik Haumann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,9 +32,14 @@ class KMessageWidgetPrivate; * feedback, or to implement opportunistic interactions. * * As a feedback widget, KMessageWidget provides a less intrusive alternative - * to "OK Only" message boxes. If you do not need the modalness of KMessageBox, + * to "OK Only" message boxes. If you want to avoid a modal KMessageBox, * consider using KMessageWidget instead. * + * Examples of KMessageWidget look as follows, all of them having an icon set + * with setIcon(), and the first three show a close button: + * + * \image html kmessagewidget.png "KMessageWidget with different message types" + * * Negative feedback * * The KMessageWidget can be used as a secondary indicator of failure: the @@ -67,7 +73,7 @@ class KMessageWidgetPrivate; * @li Confirm success of "critical" transactions * @li Indicate completion of background tasks * - * Example of inadapted uses: + * Example of unadapted uses: * * @li Indicate successful saving of a file * @li Indicate a file has been successfully removed @@ -87,153 +93,250 @@ class KMessageWidgetPrivate; * @author Aurélien Gâteau * @since 4.7 */ -class KMessageWidget : public QFrame { - Q_OBJECT - Q_ENUMS(MessageType) - - Q_PROPERTY(QString text READ text WRITE setText) - Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap) - Q_PROPERTY(bool closeButtonVisible READ isCloseButtonVisible WRITE setCloseButtonVisible) - Q_PROPERTY(MessageType messageType READ messageType WRITE setMessageType) - Q_PROPERTY(QIcon icon READ icon WRITE setIcon) +class KMessageWidget : public QFrame +{ + Q_OBJECT + Q_ENUMS(MessageType) + + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap) + Q_PROPERTY(bool closeButtonVisible READ isCloseButtonVisible WRITE setCloseButtonVisible) + Q_PROPERTY(MessageType messageType READ messageType WRITE setMessageType) + Q_PROPERTY(QIcon icon READ icon WRITE setIcon) public: - enum MessageType { - Positive, - Information, - Warning, - Error - }; - - /** - * Constructs a KMessageWidget with the specified parent. - */ - explicit KMessageWidget(QWidget *parent = 0); - - explicit KMessageWidget(const QString &text, QWidget *parent = 0); - - ~KMessageWidget(); - - QString text() const; - - bool wordWrap() const; - - bool isCloseButtonVisible() const; - - MessageType messageType() const; - - void addAction(QAction *action); - - void removeAction(QAction *action); - - QSize sizeHint() const; - - QSize minimumSizeHint() const; - - int heightForWidth(int width) const; - - /** - * The icon shown on the left of the text. By default, no icon is shown. - * @since 4.11 - */ - QIcon icon() const; - -public -Q_SLOTS: - void setText(const QString &text); - - void setWordWrap(bool wordWrap); - - void setCloseButtonVisible(bool visible); - - void setMessageType(KMessageWidget::MessageType type); - - /** - * Show the widget using an animation, unless - * KGlobalSettings::graphicsEffectLevel() does not allow simple effects. - */ - void animatedShow(); - - /** - * Hide the widget using an animation, unless - * KGlobalSettings::graphicsEffectLevel() does not allow simple effects. - */ - void animatedHide(); - - /** - * Define an icon to be shown on the left of the text - * @since 4.11 - */ - void setIcon(const QIcon &icon); - - int bestContentHeight() const; + + /** + * Available message types. + * The background colors are chosen depending on the message type. + */ + enum MessageType { + Positive, + Information, + Warning, + Error + }; + + /** + * Constructs a KMessageWidget with the specified @p parent. + */ + explicit KMessageWidget(QWidget *parent = 0); + + /** + * Constructs a KMessageWidget with the specified @p parent and + * contents @p text. + */ + explicit KMessageWidget(const QString &text, QWidget *parent = 0); + + /** + * Destructor. + */ + ~KMessageWidget(); + + /** + * Get the text of this message widget. + * @see setText() + */ + QString text() const; + + /** + * Check whether word wrap is enabled. + * + * If word wrap is enabled, the message widget wraps the displayed text + * as required to the available width of the widget. This is useful to + * avoid breaking widget layouts. + * + * @see setWordWrap() + */ + bool wordWrap() const; + + /** + * Check whether the close button is visible. + * + * @see setCloseButtonVisible() + */ + bool isCloseButtonVisible() const; + + /** + * Get the type of this message. + * By default, the type is set to KMessageWidget::Information. + * + * @see KMessageWidget::MessageType, setMessageType() + */ + MessageType messageType() const; + + /** + * Add @p action to the message widget. + * For each action a button is added to the message widget in the + * order the actions were added. + * + * @param action the action to add + * @see removeAction(), QWidget::actions() + */ + void addAction(QAction *action); + + /** + * Remove @p action from the message widget. + * + * @param action the action to remove + * @see KMessageWidget::MessageType, addAction(), setMessageType() + */ + void removeAction(QAction *action); + + /** + * Returns the preferred size of the message widget. + */ + QSize sizeHint() const Q_DECL_OVERRIDE; + + /** + * Returns the minimum size of the message widget. + */ + QSize minimumSizeHint() const Q_DECL_OVERRIDE; + + /** + * Returns the required height for @p width. + * @param width the width in pixels + */ + int heightForWidth(int width) const Q_DECL_OVERRIDE; + + /** + * The icon shown on the left of the text. By default, no icon is shown. + * @since 4.11 + */ + QIcon icon() const; + + /** + * Check whether the hide animation started by calling animatedHide() + * is still running. If animations are disabled, this function always + * returns @e false. + * + * @see animatedHide(), hideAnimationFinished() + * @since 5.0 + */ + bool isHideAnimationRunning() const; + + /** + * Check whether the show animation started by calling animatedShow() + * is still running. If animations are disabled, this function always + * returns @e false. + * + * @see animatedShow(), showAnimationFinished() + * @since 5.0 + */ + bool isShowAnimationRunning() const; + +public Q_SLOTS: + /** + * Set the text of the message widget to @p text. + * If the message widget is already visible, the text changes on the fly. + * + * @param text the text to display, rich text is allowed + * @see text() + */ + void setText(const QString &text); + + /** + * Set word wrap to @p wordWrap. If word wrap is enabled, the text() + * of the message widget is wrapped to fit the available width. + * If word wrap is disabled, the message widget's minimum size is + * such that the entire text fits. + * + * @param wordWrap disable/enable word wrap + * @see wordWrap() + */ + void setWordWrap(bool wordWrap); + + /** + * Set the visibility of the close button. If @p visible is @e true, + * a close button is shown that calls animatedHide() if clicked. + * + * @see closeButtonVisible(), animatedHide() + */ + void setCloseButtonVisible(bool visible); + + /** + * Set the message type to @p type. + * By default, the message type is set to KMessageWidget::Information. + * + * @see messageType(), KMessageWidget::MessageType + */ + void setMessageType(KMessageWidget::MessageType type); + + /** + * Show the widget using an animation. + */ + void animatedShow(); + + /** + * Hide the widget using an animation. + */ + void animatedHide(); + + /** + * Define an icon to be shown on the left of the text + * @since 4.11 + */ + void setIcon(const QIcon &icon); + Q_SIGNALS: - /** - * This signal is emitted when the user clicks a link in the text label. - * The URL referred to by the href anchor is passed in contents. - * @param contents text of the href anchor - * @see QLabel::linkActivated() - * @since 4.10 - */ - void linkActivated(const QString &contents); - - /** - * This signal is emitted when the user hovers over a link in the text label. - * The URL referred to by the href anchor is passed in contents. - * @param contents text of the href anchor - * @see QLabel::linkHovered() - * @since 4.11 - */ - void linkHovered(const QString &contents); - + /** + * This signal is emitted when the user clicks a link in the text label. + * The URL referred to by the href anchor is passed in contents. + * @param contents text of the href anchor + * @see QLabel::linkActivated() + * @since 4.10 + */ + void linkActivated(const QString &contents); + + /** + * This signal is emitted when the user hovers over a link in the text label. + * The URL referred to by the href anchor is passed in contents. + * @param contents text of the href anchor + * @see QLabel::linkHovered() + * @since 4.11 + */ + void linkHovered(const QString &contents); + + /** + * This signal is emitted when the hide animation is finished, started by + * calling animatedHide(). If animations are disabled, this signal is + * emitted immediately after the message widget got hidden. + * + * @note This signal is @e not emitted if the widget was hidden by + * calling hide(), so this signal is only useful in conjunction + * with animatedHide(). + * + * @see animatedHide() + * @since 5.0 + */ + void hideAnimationFinished(); + + /** + * This signal is emitted when the show animation is finished, started by + * calling animatedShow(). If animations are disabled, this signal is + * emitted immediately after the message widget got shown. + * + * @note This signal is @e not emitted if the widget was shown by + * calling show(), so this signal is only useful in conjunction + * with animatedShow(). + * + * @see animatedShow() + * @since 5.0 + */ + void showAnimationFinished(); + protected: - void paintEvent(QPaintEvent *event); - - bool event(QEvent *event); - - void resizeEvent(QResizeEvent *event); - - void showEvent(QShowEvent *event); - + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; + + bool event(QEvent *event) Q_DECL_OVERRIDE; + + void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; + private: - KMessageWidgetPrivate *const d; - friend class KMessageWidgetPrivate; - - Q_PRIVATE_SLOT(d, void slotTimeLineChanged(qreal)) - Q_PRIVATE_SLOT(d, void slotTimeLineFinished()) + KMessageWidgetPrivate *const d; + friend class KMessageWidgetPrivate; + + Q_PRIVATE_SLOT(d, void slotTimeLineChanged(qreal)) + Q_PRIVATE_SLOT(d, void slotTimeLineFinished()) }; -//--------------------------------------------------------------------- -// KMessageWidgetPrivate -//--------------------------------------------------------------------- -class QLabel; -class QToolButton; -class QTimeLine; -#include - -class KMessageWidgetPrivate { -public: - void init(KMessageWidget *); - - KMessageWidget *q; - QFrame *content; - QLabel *iconLabel; - QLabel *textLabel; - QToolButton *closeButton; - QTimeLine *timeLine; - QIcon icon; - - KMessageWidget::MessageType messageType; - bool wordWrap; - QList buttons; - QPixmap contentSnapShot; - - void createLayout(); - void updateSnapShot(); - void updateLayout(); - void slotTimeLineChanged(qreal); - void slotTimeLineFinished(); - - int bestContentHeight() const; -}; - -#endif // KMESSAGEWIDGET_H +#endif /* KMESSAGEWIDGET_H */ From 41d51116847a478725d509debadd5f5622ff061d Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Sun, 15 Jan 2017 01:44:48 +0100 Subject: [PATCH 10/12] Use KMessageWidget also for new error messages --- src/gui/DatabaseTabWidget.cpp | 14 +++++++------- src/gui/DatabaseWidget.cpp | 18 +++++++++--------- src/gui/KeePass1OpenWidget.cpp | 4 ++-- src/gui/MainWindow.cpp | 7 ++++--- src/gui/entry/EditEntryWidget.cpp | 3 +-- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index b1eb9a0a5..8b29cfd03 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -328,8 +328,8 @@ bool DatabaseTabWidget::saveDatabase(Database* db) // write the database to the file m_writer.writeDatabase(&saveFile, db); if (m_writer.hasError()) { - MessageBox::critical(this, tr("Error"), tr("Writing the database failed.") + "\n\n" - + m_writer.errorString()); + Q_EMIT messageTab(tr("Writing the database failed.").append("\n") + .append(m_writer.errorString()), MessageWidget::Error); return false; } @@ -342,14 +342,14 @@ bool DatabaseTabWidget::saveDatabase(Database* db) return true; } else { - MessageBox::critical(this, tr("Error"), tr("Writing the database failed.") + "\n\n" - + saveFile.errorString()); + Q_EMIT messageTab(tr("Writing the database failed.").append("\n") + .append(saveFile.errorString()), MessageWidget::Error); return false; } } else { - Q_EMIT messageTab(tr("Writing the database failed.\n") - .append("\n").append(saveFile.errorString()), MessageWidget::Error); + Q_EMIT messageTab(tr("Writing the database failed.").append("\n") + .append(saveFile.errorString()), MessageWidget::Error); return false; } } @@ -494,7 +494,7 @@ void DatabaseTabWidget::exportToCsv() CsvExporter csvExporter; if (!csvExporter.exportDatabase(fileName, db)) { Q_EMIT messageGlobal( - tr("Writing the CSV file failed.").append("\n\n") + tr("Writing the CSV file failed.").append("\n") .append(csvExporter.errorString()), MessageWidget::Error); } } diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 74fc2d7cc..2d65352f9 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -696,7 +696,7 @@ void DatabaseWidget::updateMasterKey(bool accepted) QApplication::restoreOverrideCursor(); if (!result) { - MessageBox::critical(this, tr("Error"), tr("Unable to calculate master key")); + m_messageWidget->showMessage(tr("Unable to calculate master key"), MessageWidget::Error); return; } } @@ -736,14 +736,14 @@ void DatabaseWidget::mergeDatabase(bool accepted) { if (accepted) { if (!m_db) { - MessageBox::critical(this, tr("Error"), tr("No current database.")); + m_messageWidget->showMessage(tr("No current database."), MessageWidget::Error); return; } Database* srcDb = static_cast(sender())->database(); if (!srcDb) { - MessageBox::critical(this, tr("Error"), tr("No source database, nothing to do.")); + m_messageWidget->showMessage(tr("No source database, nothing to do."), MessageWidget::Error); return; } @@ -1093,15 +1093,15 @@ void DatabaseWidget::reloadDatabaseFile() } else { - MessageBox::critical(this, tr("Autoreload Failed"), - tr("Could not parse or unlock the new database file while attempting" - " to autoreload this database.")); + m_messageWidget->showMessage( + tr("Could not parse or unlock the new database file while attempting" + " to autoreload this database."), MessageWidget::Error); } } else { - MessageBox::critical(this, tr("Autoreload Failed"), - tr("Could not open the new database file while attempting to autoreload" - " this database.")); + m_messageWidget->showMessage( + tr("Could not open the new database file while attempting to autoreload this database."), + MessageWidget::Error); } // Rewatch the database file diff --git a/src/gui/KeePass1OpenWidget.cpp b/src/gui/KeePass1OpenWidget.cpp index c5159aaba..b63bbc485 100644 --- a/src/gui/KeePass1OpenWidget.cpp +++ b/src/gui/KeePass1OpenWidget.cpp @@ -49,8 +49,8 @@ void KeePass1OpenWidget::openDatabase() QFile file(m_filename); if (!file.open(QIODevice::ReadOnly)) { - MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n") - .append(file.errorString())); + m_ui->messageWidget->showMessage( tr("Unable to open the database.").append("\n") + .append(file.errorString()), MessageWidget::Error); return; } if (m_db) { diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 92a9cbdd4..63bc1ba87 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -761,7 +761,7 @@ void MainWindow::repairDatabase() if (fileName.isEmpty()) { return; } - + QScopedPointer dialog(new QDialog(this)); DatabaseRepairWidget* dbRepairWidget = new DatabaseRepairWidget(dialog.data()); connect(dbRepairWidget, SIGNAL(success()), dialog.data(), SLOT(accept())); @@ -776,8 +776,9 @@ void MainWindow::repairDatabase() KeePass2Writer writer; writer.writeDatabase(saveFileName, dbRepairWidget->database()); if (writer.hasError()) { - QMessageBox::critical(this, tr("Error"), - tr("Writing the database failed.").append("\n\n").append(writer.errorString())); + displayGlobalMessage( + tr("Writing the database failed.").append("\n").append(writer.errorString()), + MessageWidget::Error); } } } diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index d9b235f3b..58e2a7707 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -704,8 +704,7 @@ void EditEntryWidget::openAttachment(const QModelIndex& index) } if (!file->flush()) { - MessageBox::warning(this, tr("Error"), - tr("Unable to save the attachment:\n").append(file->errorString())); + showMessage(tr("Unable to save the attachment:\n").append(file->errorString()), MessageWidget::Error); return; } From 94f8650ca4f3ec3998b48d3b88c9462d97635d46 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Fri, 10 Feb 2017 02:11:43 +0100 Subject: [PATCH 11/12] Rename KMessageWidget files to match our coding style --- src/CMakeLists.txt | 2 +- src/gui/EditWidgetIcons.cpp | 5 ++--- src/gui/{kmessagewidget.cpp => KMessageWidget.cpp} | 4 ++-- src/gui/{kmessagewidget.h => KMessageWidget.h} | 0 src/gui/MainWindow.cpp | 4 +--- src/gui/MessageWidget.h | 2 +- 6 files changed, 7 insertions(+), 10 deletions(-) rename src/gui/{kmessagewidget.cpp => KMessageWidget.cpp} (99%) rename src/gui/{kmessagewidget.h => KMessageWidget.h} (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3de167544..c199cbb9d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,7 +86,7 @@ set(keepassx_SOURCES gui/FileDialog.cpp gui/IconModels.cpp gui/KeePass1OpenWidget.cpp - gui/kmessagewidget.cpp + gui/KMessageWidget.cpp gui/LineEdit.cpp gui/MainWindow.cpp gui/MessageBox.cpp diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp index fcfff5ca3..ba395b592 100644 --- a/src/gui/EditWidgetIcons.cpp +++ b/src/gui/EditWidgetIcons.cpp @@ -158,12 +158,11 @@ void EditWidgetIcons::fetchFavicon(QUrl url) void EditWidgetIcons::fetchFaviconFromGoogle(QString domain) { - if (m_fallbackToGoogle) { + if (m_fallbackToGoogle) { abortFaviconDownload(); m_fallbackToGoogle = false; fetchFavicon(QUrl("http://www.google.com/s2/favicons?domain=" + domain)); - } - else { + } else { abortFaviconDownload(); MessageBox::warning(this, tr("Error"), tr("Unable to fetch favicon.")); } diff --git a/src/gui/kmessagewidget.cpp b/src/gui/KMessageWidget.cpp similarity index 99% rename from src/gui/kmessagewidget.cpp rename to src/gui/KMessageWidget.cpp index ee3c1b69c..f2c48c253 100644 --- a/src/gui/kmessagewidget.cpp +++ b/src/gui/KMessageWidget.cpp @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ -#include "kmessagewidget.h" +#include "KMessageWidget.h" #include #include @@ -477,4 +477,4 @@ void KMessageWidget::setIcon(const QIcon &icon) } } -#include "moc_kmessagewidget.cpp" +#include "moc_KMessageWidget.cpp" diff --git a/src/gui/kmessagewidget.h b/src/gui/KMessageWidget.h similarity index 100% rename from src/gui/kmessagewidget.h rename to src/gui/KMessageWidget.h diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 63bc1ba87..b9da4e19e 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -802,9 +802,7 @@ void MainWindow::displayGlobalMessage(const QString& text, MessageWidget::Messag void MainWindow::displayTabMessage(const QString& text, MessageWidget::MessageType type) { - //if (m_ui->stackedWidget->currentIndex() == 0) { - m_ui->tabWidget->currentDatabaseWidget()->showMessage(text, type); - //} + m_ui->tabWidget->currentDatabaseWidget()->showMessage(text, type); } void MainWindow::hideGlobalMessage() diff --git a/src/gui/MessageWidget.h b/src/gui/MessageWidget.h index 0e7d8a307..34c06743c 100644 --- a/src/gui/MessageWidget.h +++ b/src/gui/MessageWidget.h @@ -18,7 +18,7 @@ #ifndef MESSAGEWIDGET_H #define MESSAGEWIDGET_H -#include "gui/kmessagewidget.h" +#include "gui/KMessageWidget.h" class MessageWidget : public KMessageWidget { From bf419d18a98027e5f1ddbeee65fda191286de3dc Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Fri, 10 Feb 2017 02:50:46 +0100 Subject: [PATCH 12/12] Update KMessageWidget files in COPYING also [skip ci] --- COPYING | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/COPYING b/COPYING index 0495b912f..4dbaece33 100644 --- a/COPYING +++ b/COPYING @@ -199,8 +199,8 @@ Copyright: 2015, Tony Evans 2016, KeePassXC Team License: BSD 3-clause -Files: src/gui/kmessagewidget.h - src/gui/kmessagewidget.cpp +Files: src/gui/KMessageWidget.h + src/gui/KMessageWidget.cpp Copyright: 2011 Aurélien Gâteau 2014 Dominik Haumann License: LGPL-2.1