Merge pull request #162 from keepassxreboot/migrate/78-inline-messages

KeePassX PR Migration: #78 Inline Messages
This commit is contained in:
Jonathan White 2017-02-09 20:56:21 -05:00 committed by GitHub
commit 586e6f1e1b
27 changed files with 1135 additions and 65 deletions

View File

@ -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 <agateau@kde.org>
2014 Dominik Haumann <dhaumann@kde.org>
License: LGPL-2.1

View File

@ -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

View File

@ -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->showMessage(tr("Unable to create Key File : ").append(errorMsg), MessageWidget::Error);
}
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->showMessage(tr("Different passwords supplied."), MessageWidget::Error);
m_ui->enterPasswordEdit->setText("");
m_ui->repeatPasswordEdit->setText("");
return;
@ -119,15 +121,16 @@ 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->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);
}

View File

@ -7,10 +7,13 @@
<x>0</x>
<y>0</y>
<width>438</width>
<height>256</height>
<height>342</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="MessageWidget" name="messageWidget" native="true"/>
</item>
<item>
<widget class="QLabel" name="headlineLabel"/>
</item>
@ -151,6 +154,12 @@
<extends>QLineEdit</extends>
<header>gui/PasswordEdit.h</header>
</customwidget>
<customwidget>
<class>MessageWidget</class>
<extends>QWidget</extends>
<header>gui/MessageWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>passwordGroup</tabstop>

View File

@ -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->showMessage(
tr("Unable to open the database.").append("\n").append(file.errorString()), MessageWidget::Error);
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->showMessage(tr("Unable to open the database.")
.append("\n").append(reader.errorString()), MessageWidget::Error);
m_ui->editPassword->clear();
}
}
@ -142,7 +147,8 @@ 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->showMessage(tr("Can't open key file").append(":\n")
.append(errorMsg), MessageWidget::Error);
return CompositeKey();
}
masterKey.addKey(key);

View File

@ -10,10 +10,13 @@
<height>250</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,0,1,0,0,3">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0,0,1,0,0,3">
<property name="spacing">
<number>8</number>
</property>
<item>
<widget class="MessageWidget" name="messageWidget" native="true"/>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@ -144,6 +147,12 @@
<extends>QLineEdit</extends>
<header>gui/PasswordEdit.h</header>
</customwidget>
<customwidget>
<class>MessageWidget</class>
<extends>QWidget</extends>
<header>gui/MessageWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>checkPassword</tabstop>

View File

@ -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()
@ -322,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;
}
@ -332,17 +338,18 @@ bool DatabaseTabWidget::saveDatabase(Database* db)
dbStruct.modified = false;
dbStruct.dbWidget->databaseSaved();
updateTabName(db);
Q_EMIT messageDismissTab();
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 {
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;
}
}
@ -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")
.append(csvExporter.errorString()), MessageWidget::Error);
}
}

View File

@ -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);

View File

@ -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");
@ -689,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;
}
}
@ -729,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<DatabaseOpenWidget*>(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;
}
@ -1086,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
@ -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();
}
}

View File

@ -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;

View File

@ -149,3 +149,4 @@ QVariant DatabaseWidgetStateSync::intListToVariant(const QList<int>& list)
return result;
}

View File

@ -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,15 @@ bool EditWidget::readOnly() const
{
return m_readOnly;
}
void EditWidget::showMessage(const QString& text, MessageWidget::MessageType type)
{
m_ui->messageWidget->showMessage(text, type);
}
void EditWidget::hideMessage()
{
if (m_ui->messageWidget->isVisible()) {
m_ui->messageWidget->animatedHide();
}
}

View File

@ -21,6 +21,7 @@
#include <QScopedPointer>
#include "gui/DialogyWidget.h"
#include "gui/MessageWidget.h"
class QLabel;
@ -48,6 +49,10 @@ Q_SIGNALS:
void accepted();
void rejected();
protected Q_SLOTS:
void showMessage(const QString& text, MessageWidget::MessageType type);
void hideMessage();
private:
const QScopedPointer<Ui::EditWidget> m_ui;
bool m_readOnly;

View File

@ -11,6 +11,9 @@
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="MessageWidget" name="messageWidget" native="true"/>
</item>
<item>
<widget class="QLabel" name="headerLabel">
<property name="text">
@ -58,6 +61,12 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>MessageWidget</class>
<extends>QWidget</extends>
<header>gui/MessageWidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>CategoryListWidget</class>
<extends>QListWidget</extends>

View File

@ -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."));
}
@ -248,7 +247,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 +301,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);
}
}
}

View File

@ -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);

480
src/gui/KMessageWidget.cpp Normal file
View File

@ -0,0 +1,480 @@
/* This file is part of the KDE libraries
*
* Copyright (c) 2011 Aurélien Gâteau <agateau@kde.org>
* Copyright (c) 2014 Dominik Haumann <dhaumann@kde.org>
*
* 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 <QAction>
#include <QEvent>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPainter>
#include <QShowEvent>
#include <QTimeLine>
#include <QToolButton>
#include <QStyle>
//---------------------------------------------------------------------
// 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<QToolButton *> 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(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);
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();
}
}
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() * 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();
}
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());
// 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;
}
//---------------------------------------------------------------------
// 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();
}
KMessageWidget::MessageType KMessageWidget::messageType() const
{
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.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();
}
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);
}
}
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 (!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 (!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();
}
}
bool KMessageWidget::isHideAnimationRunning() const
{
return (d->timeLine->direction() == QTimeLine::Backward)
&& (d->timeLine->state() == QTimeLine::Running);
}
bool KMessageWidget::isShowAnimationRunning() const
{
return (d->timeLine->direction() == QTimeLine::Forward)
&& (d->timeLine->state() == QTimeLine::Running);
}
QIcon KMessageWidget::icon() const
{
return d->icon;
}
void KMessageWidget::setIcon(const QIcon &icon)
{
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"

342
src/gui/KMessageWidget.h Normal file
View File

@ -0,0 +1,342 @@
/* This file is part of the KDE libraries
*
* Copyright (c) 2011 Aurélien Gâteau <agateau@kde.org>
* Copyright (c) 2014 Dominik Haumann <dhaumann@kde.org>
*
* 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 <QFrame>
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 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"
*
* <b>Negative feedback</b>
*
* 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.
*
* <b>Positive feedback</b>
*
* 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 unadapted uses:
*
* @li Indicate successful saving of a file
* @li Indicate a file has been successfully removed
*
* <b>Opportunistic interaction</b>
*
* 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 <agateau@kde.org>
* @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:
/**
* 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 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) 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())
};
#endif /* KMESSAGEWIDGET_H */

View File

@ -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) {
@ -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();
}
}

View File

@ -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();
}
@ -755,7 +761,7 @@ void MainWindow::repairDatabase()
if (fileName.isEmpty()) {
return;
}
QScopedPointer<QDialog> dialog(new QDialog(this));
DatabaseRepairWidget* dbRepairWidget = new DatabaseRepairWidget(dialog.data());
connect(dbRepairWidget, SIGNAL(success()), dialog.data(), SLOT(accept()));
@ -770,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);
}
}
}
@ -787,3 +794,26 @@ 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)
{
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();
}
}

View File

@ -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);

View File

@ -2,6 +2,9 @@
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
@ -14,6 +17,9 @@
<string notr="true">KeePassXC</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="enabled">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
@ -27,8 +33,24 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="MessageWidget" name="globalMessageWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>2</number>
</property>
@ -104,7 +126,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
<height>26</height>
<height>29</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -452,6 +474,12 @@
</action>
</widget>
<customwidgets>
<customwidget>
<class>MessageWidget</class>
<extends>QWidget</extends>
<header>gui/MessageWidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>DatabaseTabWidget</class>
<extends>QTabWidget</extends>

36
src/gui/MessageWidget.cpp Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2015 Pedro Alves <devel@pgalves.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "MessageWidget.h"
MessageWidget::MessageWidget(QWidget* parent)
:KMessageWidget(parent)
{
}
void MessageWidget::showMessage(const QString& text, MessageWidget::MessageType type)
{
setMessageType(type);
setText(text);
animatedShow();
}
void MessageWidget::hideMessage()
{
animatedHide();
}

36
src/gui/MessageWidget.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2015 Pedro Alves <devel@pgalves.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef MESSAGEWIDGET_H
#define MESSAGEWIDGET_H
#include "gui/KMessageWidget.h"
class MessageWidget : public KMessageWidget
{
Q_OBJECT
public:
explicit MessageWidget(QWidget* parent = 0);
public Q_SLOTS:
void showMessage(const QString& text, MessageWidget::MessageType type);
void hideMessage();
};
#endif // MESSAGEWIDGET_H

View File

@ -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()
@ -395,12 +398,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."));
showMessage(tr("Different passwords supplied."), MessageWidget::Error);
return;
}
@ -474,6 +478,7 @@ void EditEntryWidget::cancel()
{
if (m_history) {
clear();
hideMessage();
Q_EMIT editFinished(false);
return;
}
@ -497,6 +502,7 @@ void EditEntryWidget::clear()
m_autoTypeAssoc->clear();
m_historyModel->clear();
m_iconsWidget->reset();
hideMessage();
}
bool EditEntryWidget::hasBeenModified() const
@ -630,15 +636,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()));
showMessage(tr("Unable to open file").append(":\n").append(file.errorString()), MessageWidget::Error);
return;
}
QByteArray data;
if (!Tools::readAllFromDevice(&file, data)) {
MessageBox::warning(this, tr("Error"),
tr("Unable to open file").append(":\n").append(file.errorString()));
showMessage(tr("Unable to open file").append(":\n").append(file.errorString()), MessageWidget::Error);
return;
}
@ -665,13 +669,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()));
showMessage(tr("Unable to save the attachment:\n").append(file.errorString()), MessageWidget::Error);
return;
}
if (file.write(attachmentData) != attachmentData.size()) {
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;
}
}
@ -692,20 +694,17 @@ 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()));
showMessage(tr("Unable to save the attachment:\n").append(file->errorString()), MessageWidget::Error);
return;
}
if (file->write(attachmentData) != attachmentData.size()) {
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;
}
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;
}

View File

@ -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()

View File

@ -45,6 +45,8 @@ public:
Q_SIGNALS:
void editFinished(bool accepted);
void messageEditEntry(QString, MessageWidget::MessageType);
void messageEditEntryDismiss();
private Q_SLOTS:
void save();