mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Merge pull request #162 from keepassxreboot/migrate/78-inline-messages
KeePassX PR Migration: #78 Inline Messages
This commit is contained in:
commit
586e6f1e1b
6
COPYING
6
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 <agateau@kde.org>
|
||||
2014 Dominik Haumann <dhaumann@kde.org>
|
||||
License: LGPL-2.1
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -149,3 +149,4 @@ QVariant DatabaseWidgetStateSync::intListToVariant(const QList<int>& list)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
480
src/gui/KMessageWidget.cpp
Normal 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
342
src/gui/KMessageWidget.h
Normal 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 */
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
36
src/gui/MessageWidget.cpp
Normal 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
36
src/gui/MessageWidget.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -45,6 +45,8 @@ public:
|
||||
|
||||
Q_SIGNALS:
|
||||
void editFinished(bool accepted);
|
||||
void messageEditEntry(QString, MessageWidget::MessageType);
|
||||
void messageEditEntryDismiss();
|
||||
|
||||
private Q_SLOTS:
|
||||
void save();
|
||||
|
Loading…
Reference in New Issue
Block a user