diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9cde2bf8d..4f767a783 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index e866cbb92..a53b25ba7 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -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); } diff --git a/src/gui/EditEntryWidget.cpp b/src/gui/EditEntryWidget.cpp index 06ec022b3..60c589738 100644 --- a/src/gui/EditEntryWidget.cpp +++ b/src/gui/EditEntryWidget.cpp @@ -20,15 +20,17 @@ #include "ui_EditEntryWidgetAdvanced.h" #include "ui_EditEntryWidgetMain.h" #include "ui_EditEntryWidgetNotes.h" +#include "ui_EditEntryWidgetIcons.h" #include -#include #include #include #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); +} diff --git a/src/gui/EditEntryWidget.h b/src/gui/EditEntryWidget.h index bd8125bae..dee356c68 100644 --- a/src/gui/EditEntryWidget.h +++ b/src/gui/EditEntryWidget.h @@ -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 m_ui; const QScopedPointer m_mainUi; const QScopedPointer m_notesUi; const QScopedPointer m_advancedUi; + const QScopedPointer 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) }; diff --git a/src/gui/EditEntryWidgetIcons.ui b/src/gui/EditEntryWidgetIcons.ui new file mode 100644 index 000000000..87fdb8ec0 --- /dev/null +++ b/src/gui/EditEntryWidgetIcons.ui @@ -0,0 +1,103 @@ + + + EditEntryWidgetIcons + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + Use default icon + + + + + + + QAbstractItemView::NoEditTriggers + + + QListView::Static + + + QListView::LeftToRight + + + true + + + QListView::Adjust + + + 8 + + + QListView::IconMode + + + + + + + Use custom icon + + + + + + + QAbstractItemView::NoEditTriggers + + + QListView::Static + + + QListView::LeftToRight + + + true + + + QListView::Adjust + + + 8 + + + QListView::IconMode + + + + + + + + + Add custom icon + + + + + + + Delete custom icon + + + + + + + + + + diff --git a/src/gui/IconModels.cpp b/src/gui/IconModels.cpp new file mode 100644 index 000000000..eaf2a490e --- /dev/null +++ b/src/gui/IconModels.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "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 icons) +{ + beginResetModel(); + + m_icons = icons; + m_uuids.clear(); + QHash::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::const_iterator iter; + for (iter = m_uuids.constBegin(); iter != m_uuids.constEnd(); ++iter) { + if (iter.value() == uuid) { + return createIndex(iter.key(), 0); + } + } + return QModelIndex(); +} diff --git a/src/gui/IconModels.h b/src/gui/IconModels.h new file mode 100644 index 000000000..7f7e1d089 --- /dev/null +++ b/src/gui/IconModels.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_ICONMODELS_H +#define KEEPASSX_ICONMODELS_H + +#include +#include + +#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 icons); + Uuid uuidFromIndex(const QModelIndex& index) const; + QModelIndex indexFromUuid(const Uuid& uuid) const; + +private: + QHash m_icons; + QHash m_uuids; + +}; + +#endif // KEEPASSX_ICONMODELS_H