Add icon selection for entries.

Refs #22.
This commit is contained in:
Florian Geyer 2012-05-09 10:46:22 +02:00 committed by Felix Geyer
parent 65f2790170
commit 0d2ce4c038
7 changed files with 422 additions and 5 deletions

View File

@ -67,6 +67,7 @@ set(keepassx_SOURCES
gui/FileDialog.cpp
gui/GroupModel.cpp
gui/GroupView.cpp
gui/IconModels.cpp
gui/MainWindow.cpp
keys/CompositeKey.cpp
keys/FileKey.cpp
@ -100,6 +101,7 @@ set(keepassx_MOC
gui/EntryView.h
gui/GroupModel.h
gui/GroupView.h
gui/IconModels.h
gui/MainWindow.h
keys/CompositeKey_p.h
streams/HashedBlockStream.h
@ -115,6 +117,7 @@ set(keepassx_FORMS
gui/DatabaseSettingsWidget.ui
gui/EditEntryWidget.ui
gui/EditEntryWidgetAdvanced.ui
gui/EditEntryWidgetIcons.ui
gui/EditEntryWidgetMain.ui
gui/EditEntryWidgetNotes.ui
gui/EditGroupWidget.ui

View File

@ -244,7 +244,8 @@ void DatabaseWidget::switchToEntryEdit(Entry* entry)
void DatabaseWidget::switchToEntryEdit(Entry* entry, bool create)
{
m_editEntryWidget->loadEntry(entry, create, m_groupView->currentGroup()->name());
m_editEntryWidget->loadEntry(entry, create, m_groupView->currentGroup()->name(),
m_db->metadata());
setCurrentIndex(1);
}

View File

@ -20,15 +20,17 @@
#include "ui_EditEntryWidgetAdvanced.h"
#include "ui_EditEntryWidgetMain.h"
#include "ui_EditEntryWidgetNotes.h"
#include "ui_EditEntryWidgetIcons.h"
#include <QtGui/QDesktopServices>
#include <QtGui/QListWidget>
#include <QtGui/QStackedLayout>
#include <QtGui/QMessageBox>
#include "core/Entry.h"
#include "core/Group.h"
#include "core/Metadata.h"
#include "core/Tools.h"
#include "gui/IconModels.h"
#include "gui/EntryAttachmentsModel.h"
#include "gui/EntryAttributesModel.h"
#include "gui/FileDialog.h"
@ -40,9 +42,11 @@ EditEntryWidget::EditEntryWidget(QWidget* parent)
, m_mainUi(new Ui::EditEntryWidgetMain())
, m_notesUi(new Ui::EditEntryWidgetNotes())
, m_advancedUi(new Ui::EditEntryWidgetAdvanced())
, m_iconsUi(new Ui::EditEntryWidgetIcons())
, m_mainWidget(new QWidget(this))
, m_notesWidget(new QWidget(this))
, m_advancedWidget(new QWidget(this))
, m_iconsWidget(new QWidget(this))
{
m_ui->setupUi(this);
@ -54,6 +58,7 @@ EditEntryWidget::EditEntryWidget(QWidget* parent)
m_ui->categoryList->addItem(tr("Entry"));
m_ui->categoryList->addItem(tr("Description"));
m_ui->categoryList->addItem(tr("Advanced"));
m_ui->categoryList->addItem(tr("Icon"));
m_mainUi->setupUi(m_mainWidget);
m_ui->stackedWidget->addWidget(m_mainWidget);
@ -64,6 +69,9 @@ EditEntryWidget::EditEntryWidget(QWidget* parent)
m_advancedUi->setupUi(m_advancedWidget);
m_ui->stackedWidget->addWidget(m_advancedWidget);
m_iconsUi->setupUi(m_iconsWidget);
m_ui->stackedWidget->addWidget(m_iconsWidget);
m_entryAttachments = new EntryAttachments(this);
m_attachmentsModel = new EntryAttachmentsModel(m_advancedWidget);
m_attachmentsModel->setEntryAttachments(m_entryAttachments);
@ -92,6 +100,23 @@ EditEntryWidget::EditEntryWidget(QWidget* parent)
connect(m_mainUi->passwordEdit, SIGNAL(textEdited(QString)), SLOT(setPasswordCheckColors()));
connect(m_mainUi->passwordRepeatEdit, SIGNAL(textEdited(QString)), SLOT(setPasswordCheckColors()));
m_defaultIconModel = new DefaultIconModel(m_iconsWidget);
m_iconsUi->defaultIconsView->setModel(m_defaultIconModel);
m_customIconModel = new CustomIconModel(m_iconsWidget);
m_iconsUi->customIconsView->setModel(m_customIconModel);
connect(m_iconsUi->defaultIconsView, SIGNAL(clicked(QModelIndex)),
this, SLOT(updateRadioButtonDefaultIcons()));
connect(m_iconsUi->customIconsView, SIGNAL(clicked(QModelIndex)),
this, SLOT(updateRadioButtonCustomIcons()));
connect(m_iconsUi->defaultIconsRadio, SIGNAL(toggled(bool)),
this, SLOT(updateIndexDefaultIcons(bool)));
connect(m_iconsUi->customIconsRadio, SIGNAL(toggled(bool)),
this, SLOT(updateIndexCustomIcons(bool)));
connect(m_iconsUi->addButton, SIGNAL(clicked()), SLOT(addCustomIcon()));
connect(m_iconsUi->deleteButton, SIGNAL(clicked()), SLOT(removeCustomIcon()));
connect(m_ui->buttonBox, SIGNAL(accepted()), SLOT(saveEntry()));
connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(cancel()));
}
@ -104,9 +129,11 @@ const QColor EditEntryWidget::normalColor = Qt::white;
const QColor EditEntryWidget::correctSoFarColor = QColor(255, 205, 15);
const QColor EditEntryWidget::errorColor = QColor(255, 125, 125);
void EditEntryWidget::loadEntry(Entry* entry, bool create, const QString& groupName)
void EditEntryWidget::loadEntry(Entry* entry, bool create, const QString& groupName,
Metadata* metadata)
{
m_entry = entry;
m_metadata = metadata;
if (create) {
m_ui->headerLabel->setText(groupName+" > "+tr("Add entry"));
@ -140,6 +167,34 @@ void EditEntryWidget::loadEntry(Entry* entry, bool create, const QString& groupN
m_advancedUi->attributesEdit->setEnabled(false);
}
if (metadata) {
m_iconsWidget->setEnabled(true);
m_customIconModel->setIcons(metadata->customIcons());
Uuid iconUuid = entry->iconUuid();
if (iconUuid.isNull()) {
int iconNumber = entry->iconNumber();
m_iconsUi->defaultIconsView->setCurrentIndex(m_defaultIconModel->index(iconNumber, 0));
m_iconsUi->defaultIconsRadio->setChecked(true);
}
else {
QModelIndex index = m_customIconModel->indexFromUuid(iconUuid);
if (index.isValid()) {
m_iconsUi->customIconsView->setCurrentIndex(index);
m_iconsUi->customIconsRadio->setChecked(true);
}
else {
m_iconsUi->defaultIconsView->setCurrentIndex(m_defaultIconModel->index(0, 0));
m_iconsUi->defaultIconsRadio->setChecked(true);
}
}
}
else {
m_iconsWidget->setEnabled(false);
}
m_mainUi->titleEdit->setFocus();
}
@ -172,6 +227,25 @@ void EditEntryWidget::saveEntry()
m_entry->attributes()->copyCustomKeysFrom(m_entryAttributes);
*m_entry->attachments() = *m_entryAttachments;
if (m_iconsUi->defaultIconsRadio->isChecked()) {
QModelIndex index = m_iconsUi->defaultIconsView->currentIndex();
if (index.isValid()) {
m_entry->setIcon(index.row());
}
else {
m_entry->setIcon(0);
}
}
else {
QModelIndex index = m_iconsUi->customIconsView->currentIndex();
if (index.isValid()) {
m_entry->setIcon(m_customIconModel->uuidFromIndex(m_iconsUi->customIconsView->currentIndex()));
}
else {
m_entry->setIcon(0);
}
}
m_entry->endUpdate();
m_entry = 0;
@ -345,3 +419,66 @@ void EditEntryWidget::removeCurrentAttachment()
QString key = m_attachmentsModel->keyByIndex(index);
m_entryAttachments->remove(key);
}
void EditEntryWidget::addCustomIcon()
{
if (m_metadata) {
QString filename = QFileDialog::getOpenFileName(
this, tr("Select Image"), "", tr("Image Files (*.png *.jpg *.bmp)"));
QImage image(filename);
if (!image.isNull()) {
m_metadata->addCustomIcon(Uuid::random(), image.scaled(16, 16));
m_customIconModel->setIcons(m_metadata->customIcons());
}
else {
; // TODO show error
}
}
}
void EditEntryWidget::removeCustomIcon()
{
if (m_metadata) {
QModelIndex index = m_iconsUi->customIconsView->currentIndex();
if (index.isValid()) {
m_metadata->removeCustomIcon(m_customIconModel->uuidFromIndex(index));
m_customIconModel->setIcons(m_metadata->customIcons());
}
else {
// TODO show error
}
}
}
void EditEntryWidget::updateIndexDefaultIcons(bool check)
{
if (check) {
QModelIndex index = m_iconsUi->defaultIconsView->currentIndex();
if (!index.isValid())
{
m_iconsUi->defaultIconsView->setCurrentIndex(m_defaultIconModel->index(0, 0));
}
}
}
void EditEntryWidget::updateIndexCustomIcons(bool check)
{
if (check) {
QModelIndex index = m_iconsUi->customIconsView->currentIndex();
if (!index.isValid())
{
m_iconsUi->customIconsView->setCurrentIndex(m_customIconModel->index(0, 0));;
}
}
}
void EditEntryWidget::updateRadioButtonDefaultIcons()
{
m_iconsUi->defaultIconsRadio->setChecked(true);
}
void EditEntryWidget::updateRadioButtonCustomIcons()
{
m_iconsUi->customIconsRadio->setChecked(true);
}

View File

@ -28,7 +28,9 @@ class EntryAttachments;
class EntryAttachmentsModel;
class EntryAttributes;
class EntryAttributesModel;
class QListWidget;
class DefaultIconModel;
class CustomIconModel;
class Metadata;
class QStackedLayout;
namespace Ui {
@ -36,6 +38,7 @@ namespace Ui {
class EditEntryWidgetAdvanced;
class EditEntryWidgetMain;
class EditEntryWidgetNotes;
class EditEntryWidgetIcons;
}
class EditEntryWidget : public DialogyWidget
@ -46,7 +49,7 @@ public:
explicit EditEntryWidget(QWidget* parent = 0);
~EditEntryWidget();
void loadEntry(Entry* entry, bool create, const QString& groupName);
void loadEntry(Entry* entry, bool create, const QString& groupName, Metadata* metadata);
static const QColor normalColor;
static const QColor correctSoFarColor;
@ -67,24 +70,35 @@ private Q_SLOTS:
void insertAttachment();
void saveCurrentAttachment();
void removeCurrentAttachment();
void addCustomIcon();
void removeCustomIcon();
void updateIndexDefaultIcons(bool checked);
void updateIndexCustomIcons(bool checked);
void updateRadioButtonDefaultIcons();
void updateRadioButtonCustomIcons();
private:
bool passwordsEqual();
Entry* m_entry;
Metadata* m_metadata;
const QScopedPointer<Ui::EditEntryWidget> m_ui;
const QScopedPointer<Ui::EditEntryWidgetMain> m_mainUi;
const QScopedPointer<Ui::EditEntryWidgetNotes> m_notesUi;
const QScopedPointer<Ui::EditEntryWidgetAdvanced> m_advancedUi;
const QScopedPointer<Ui::EditEntryWidgetIcons> m_iconsUi;
QWidget* const m_mainWidget;
QWidget* const m_notesWidget;
QWidget* const m_advancedWidget;
QWidget* const m_iconsWidget;
EntryAttachmentsModel* m_attachmentsModel;
EntryAttributesModel* m_attributesModel;
EntryAttachments* m_entryAttachments;
EntryAttributes* m_entryAttributes;
QPersistentModelIndex m_currentAttribute;
DefaultIconModel* m_defaultIconModel;
CustomIconModel* m_customIconModel;
Q_DISABLE_COPY(EditEntryWidget)
};

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditEntryWidgetIcons</class>
<widget class="QWidget" name="EditEntryWidgetIcons">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="defaultIconsRadio">
<property name="text">
<string>Use default icon</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="defaultIconsView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="movement">
<enum>QListView::Static</enum>
</property>
<property name="flow">
<enum>QListView::LeftToRight</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>true</bool>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="spacing">
<number>8</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="customIconsRadio">
<property name="text">
<string>Use custom icon</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="customIconsView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="movement">
<enum>QListView::Static</enum>
</property>
<property name="flow">
<enum>QListView::LeftToRight</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>true</bool>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="spacing">
<number>8</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="addButton">
<property name="text">
<string>Add custom icon</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="text">
<string>Delete custom icon</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

105
src/gui/IconModels.cpp Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
*
* 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 "IconModels.h"
#include "core/DatabaseIcons.h"
DefaultIconModel::DefaultIconModel(QObject* parent) :
QAbstractListModel(parent)
{
}
int DefaultIconModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return databaseIcons()->iconCount();
}
QVariant DefaultIconModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
Q_ASSERT(index.row() < databaseIcons()->iconCount());
if (role == Qt::DecorationRole) {
return databaseIcons()->iconPixmap(index.row());
}
return QVariant();
}
CustomIconModel::CustomIconModel(QObject* parent) :
QAbstractListModel(parent)
{
}
void CustomIconModel::setIcons(QHash<Uuid, QImage> icons)
{
beginResetModel();
m_icons = icons;
m_uuids.clear();
QHash<Uuid, QImage>::const_iterator iter;
int i = 0;
for (iter = m_icons.constBegin(); iter != m_icons.constEnd(); ++iter) {
m_uuids.insert(i, iter.key());
i++;
}
Q_ASSERT(m_uuids.count() == m_icons.size());
endResetModel();
}
int CustomIconModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return m_icons.size();
}
QVariant CustomIconModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
if (role == Qt::DecorationRole) {
return m_icons.value(uuidFromIndex(index));
}
return QVariant();
}
Uuid CustomIconModel::uuidFromIndex(const QModelIndex& index) const
{
Q_ASSERT(index.isValid());
return m_uuids.value(index.row());
}
QModelIndex CustomIconModel::indexFromUuid(const Uuid& uuid) const
{
QHash<int, Uuid>::const_iterator iter;
for (iter = m_uuids.constBegin(); iter != m_uuids.constEnd(); ++iter) {
if (iter.value() == uuid) {
return createIndex(iter.key(), 0);
}
}
return QModelIndex();
}

54
src/gui/IconModels.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
*
* 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 KEEPASSX_ICONMODELS_H
#define KEEPASSX_ICONMODELS_H
#include <QtCore/QAbstractListModel>
#include <QtGui/QImage>
#include "core/Uuid.h"
class DefaultIconModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit DefaultIconModel(QObject* parent = 0);
int rowCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
};
class CustomIconModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit CustomIconModel(QObject* parent = 0);
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
void setIcons(QHash<Uuid, QImage> icons);
Uuid uuidFromIndex(const QModelIndex& index) const;
QModelIndex indexFromUuid(const Uuid& uuid) const;
private:
QHash<Uuid, QImage> m_icons;
QHash<int, Uuid> m_uuids;
};
#endif // KEEPASSX_ICONMODELS_H