diff --git a/ui/models/info/emails.cpp b/ui/models/info/emails.cpp index 6c902bf..4bb8a17 100644 --- a/ui/models/info/emails.cpp +++ b/ui/models/info/emails.cpp @@ -89,6 +89,22 @@ Qt::ItemFlags Models::EMails::flags(const QModelIndex& index) const { return f; } +bool Models::EMails::setEditable(bool editable) { + if (edit != editable) { + edit = editable; + + if (deque.size() > 0) { + int lastRow = deque.size() - 1; + QModelIndex begin = createIndex(0, 0, &(deque[0])); + QModelIndex end = createIndex(lastRow, columnCount() - 1, &(deque[lastRow])); + emit dataChanged(begin, end); + } + return true; + } + return false; +} + + bool Models::EMails::setData(const QModelIndex& index, const QVariant& value, int role) { if (role == Qt::EditRole && checkIndex(index)) { Shared::VCard::Email& item = deque[index.row()]; diff --git a/ui/models/info/emails.h b/ui/models/info/emails.h index bb05a5c..f07d238 100644 --- a/ui/models/info/emails.h +++ b/ui/models/info/emails.h @@ -33,6 +33,7 @@ class EMails : public QAbstractTableModel { public: EMails(bool edit = false, QObject *parent = nullptr); + bool setEditable(bool editable); int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; diff --git a/ui/models/info/phones.cpp b/ui/models/info/phones.cpp index 7c3b04f..99c52c2 100644 --- a/ui/models/info/phones.cpp +++ b/ui/models/info/phones.cpp @@ -107,6 +107,22 @@ Qt::ItemFlags Models::Phones::flags(const QModelIndex& index) const { return f; } +bool Models::Phones::setEditable(bool editable) { + if (edit != editable) { + edit = editable; + + if (deque.size() > 0) { + int lastRow = deque.size() - 1; + QModelIndex begin = createIndex(0, 0, &(deque[0])); + QModelIndex end = createIndex(lastRow, columnCount() - 1, &(deque[lastRow])); + emit dataChanged(begin, end); + } + return true; + } + return false; +} + + bool Models::Phones::dropPrefered() { bool dropped = false; int i = 0; diff --git a/ui/models/info/phones.h b/ui/models/info/phones.h index dec27d9..aea03ed 100644 --- a/ui/models/info/phones.h +++ b/ui/models/info/phones.h @@ -30,9 +30,10 @@ class Phones : public QAbstractTableModel { public: Phones(bool edit = false, QObject *parent = nullptr); + bool setEditable(bool editable); QVariant data(const QModelIndex& index, int role) const override; - int columnCount(const QModelIndex& parent) const override; - int rowCount(const QModelIndex& parent) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex &index) const override; bool isPreferred(quint32 row) const; diff --git a/ui/widgets/info/contactcontacts.cpp b/ui/widgets/info/contactcontacts.cpp index 620d235..1196aa9 100644 --- a/ui/widgets/info/contactcontacts.cpp +++ b/ui/widgets/info/contactcontacts.cpp @@ -17,15 +17,222 @@ #include "contactcontacts.h" #include "ui_contactcontacts.h" -UI::ContactContacts::ContactContacts(const QString& jid, QWidget* parent): +UI::ContactContacts::ContactContacts(QWidget* parent): QWidget(parent), - m_ui(new Ui::ContactContacts) + m_ui(new Ui::ContactContacts), + contextMenu(new QMenu()), + emails(), + phones(), + roleDelegate(new ComboboxDelegate()), + phoneTypeDelegate(new ComboboxDelegate()), + editable(false) { m_ui->setupUi(this); - m_ui->jabberID->setText(jid); m_ui->jabberID->setReadOnly(true); + + initializeDelegates(); + initializeViews(); } UI::ContactContacts::~ContactContacts() { + contextMenu->deleteLater(); +} + +void UI::ContactContacts::setVCard(const QString& jid, const Shared::VCard& card, bool p_editable) { + editable = p_editable; + m_ui->jabberID->setText(jid); + m_ui->url->setText(card.getUrl()); + m_ui->url->setReadOnly(!p_editable); + + emails.setEditable(editable); + phones.setEditable(editable); + emails.setEmails(card.getEmails()); + phones.setPhones(card.getPhones()); +} + +void UI::ContactContacts::initializeDelegates() { + roleDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Email::roleNames[0].toStdString().c_str())); + roleDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Email::roleNames[1].toStdString().c_str())); + roleDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Email::roleNames[2].toStdString().c_str())); + + phoneTypeDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Phone::typeNames[0].toStdString().c_str())); + phoneTypeDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Phone::typeNames[1].toStdString().c_str())); + phoneTypeDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Phone::typeNames[2].toStdString().c_str())); + phoneTypeDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Phone::typeNames[3].toStdString().c_str())); + phoneTypeDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Phone::typeNames[4].toStdString().c_str())); + phoneTypeDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Phone::typeNames[5].toStdString().c_str())); + phoneTypeDelegate->addEntry(QCoreApplication::translate("Global", Shared::VCard::Phone::typeNames[6].toStdString().c_str())); +} + +void UI::ContactContacts::initializeViews() { + m_ui->emailsView->setContextMenuPolicy(Qt::CustomContextMenu); + m_ui->emailsView->setModel(&emails); + m_ui->emailsView->setItemDelegateForColumn(1, roleDelegate); + m_ui->emailsView->setColumnWidth(2, 25); + m_ui->emailsView->horizontalHeader()->setStretchLastSection(false); + m_ui->emailsView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + + m_ui->phonesView->setContextMenuPolicy(Qt::CustomContextMenu); + m_ui->phonesView->setModel(&phones); + m_ui->phonesView->setItemDelegateForColumn(1, roleDelegate); + m_ui->phonesView->setItemDelegateForColumn(2, phoneTypeDelegate); + m_ui->phonesView->setColumnWidth(3, 25); + m_ui->phonesView->horizontalHeader()->setStretchLastSection(false); + m_ui->phonesView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + + connect(m_ui->phonesView, &QWidget::customContextMenuRequested, this, &UI::ContactContacts::onContextMenu); + connect(m_ui->emailsView, &QWidget::customContextMenuRequested, this, &UI::ContactContacts::onContextMenu); +} + +void UI::ContactContacts::onContextMenu(const QPoint& point) { + contextMenu->clear(); + bool hasMenu = false; + QAbstractItemView* snd = static_cast(sender()); + if (snd == m_ui->emailsView) { + hasMenu = true; + if (editable) { + QAction* add = contextMenu->addAction(Shared::icon("list-add"), tr("Add email address")); + connect(add, &QAction::triggered, this, &UI::ContactContacts::onAddEmail); + + QItemSelectionModel* sm = m_ui->emailsView->selectionModel(); + int selectionSize = sm->selectedRows().size(); + + if (selectionSize > 0) { + if (selectionSize == 1) { + int row = sm->selectedRows().at(0).row(); + if (emails.isPreferred(row)) { + QAction* rev = contextMenu->addAction(Shared::icon("unfavorite"), tr("Unset this email as preferred")); + connect(rev, &QAction::triggered, std::bind(&Models::EMails::revertPreferred, &emails, row)); + } else { + QAction* rev = contextMenu->addAction(Shared::icon("favorite"), tr("Set this email as preferred")); + connect(rev, &QAction::triggered, std::bind(&Models::EMails::revertPreferred, &emails, row)); + } + } + + QAction* del = contextMenu->addAction(Shared::icon("edit-delete"), tr("Remove selected email addresses")); + connect(del, &QAction::triggered, this, &UI::ContactContacts::onRemoveEmail); + } + } + + QAction* cp = contextMenu->addAction(Shared::icon("edit-copy"), tr("Copy selected emails to clipboard")); + connect(cp, &QAction::triggered, this, &UI::ContactContacts::onCopyEmail); + } else if (snd == m_ui->phonesView) { + hasMenu = true; + if (editable) { + QAction* add = contextMenu->addAction(Shared::icon("list-add"), tr("Add phone number")); + connect(add, &QAction::triggered, this, &UI::ContactContacts::onAddPhone); + + QItemSelectionModel* sm = m_ui->phonesView->selectionModel(); + int selectionSize = sm->selectedRows().size(); + + if (selectionSize > 0) { + if (selectionSize == 1) { + int row = sm->selectedRows().at(0).row(); + if (phones.isPreferred(row)) { + QAction* rev = contextMenu->addAction(Shared::icon("view-media-favorite"), tr("Unset this phone as preferred")); + connect(rev, &QAction::triggered, std::bind(&Models::Phones::revertPreferred, &phones, row)); + } else { + QAction* rev = contextMenu->addAction(Shared::icon("favorite"), tr("Set this phone as preferred")); + connect(rev, &QAction::triggered, std::bind(&Models::Phones::revertPreferred, &phones, row)); + } + } + + QAction* del = contextMenu->addAction(Shared::icon("edit-delete"), tr("Remove selected phone numbers")); + connect(del, &QAction::triggered, this, &UI::ContactContacts::onRemovePhone); + } + } + + QAction* cp = contextMenu->addAction(Shared::icon("edit-copy"), tr("Copy selected phones to clipboard")); + connect(cp, &QAction::triggered, this, &UI::ContactContacts::onCopyPhone); + } + + if (hasMenu) { + contextMenu->popup(snd->viewport()->mapToGlobal(point)); + } +} + +void UI::ContactContacts::onAddEmail() { + QModelIndex index = emails.addNewEmptyLine(); + m_ui->emailsView->setCurrentIndex(index); + m_ui->emailsView->edit(index); +} + +void UI::ContactContacts::onAddAddress() {} //TODO +void UI::ContactContacts::onAddPhone() { + QModelIndex index = phones.addNewEmptyLine(); + m_ui->phonesView->setCurrentIndex(index); + m_ui->phonesView->edit(index); +} +void UI::ContactContacts::onRemoveAddress() {} //TODO +void UI::ContactContacts::onRemoveEmail() { + QItemSelection selection(m_ui->emailsView->selectionModel()->selection()); + + QList rows; + for (const QModelIndex& index : selection.indexes()) { + rows.append(index.row()); + } + + std::sort(rows.begin(), rows.end()); + + int prev = -1; + for (int i = rows.count() - 1; i >= 0; i -= 1) { + int current = rows[i]; + if (current != prev) { + emails.removeLines(current, 1); + prev = current; + } + } +} + +void UI::ContactContacts::onRemovePhone() { + QItemSelection selection(m_ui->phonesView->selectionModel()->selection()); + + QList rows; + for (const QModelIndex& index : selection.indexes()) { + rows.append(index.row()); + } + + std::sort(rows.begin(), rows.end()); + + int prev = -1; + for (int i = rows.count() - 1; i >= 0; i -= 1) { + int current = rows[i]; + if (current != prev) { + phones.removeLines(current, 1); + prev = current; + } + } +} + +void UI::ContactContacts::onCopyEmail() { + QList selection(m_ui->emailsView->selectionModel()->selectedRows()); + + QList addrs; + for (const QModelIndex& index : selection) { + addrs.push_back(emails.getEmail(index.row())); + } + + QString list = addrs.join("\n"); + + QClipboard* cb = QApplication::clipboard(); + cb->setText(list); +} + +void UI::ContactContacts::onCopyPhone() { + QList selection(m_ui->phonesView->selectionModel()->selectedRows()); + + QList phs; + for (const QModelIndex& index : selection) { + phs.push_back(phones.getPhone(index.row())); + } + + QString list = phs.join("\n"); + + QClipboard* cb = QApplication::clipboard(); + cb->setText(list); +} + +QString UI::ContactContacts::title() const { + return m_ui->contactHeading->text(); } diff --git a/ui/widgets/info/contactcontacts.h b/ui/widgets/info/contactcontacts.h index 7b26eed..d2c7e9f 100644 --- a/ui/widgets/info/contactcontacts.h +++ b/ui/widgets/info/contactcontacts.h @@ -19,6 +19,16 @@ #include #include +#include +#include +#include +#include + +#include "shared/vcard.h" +#include "shared/icons.h" +#include "ui/models/info/emails.h" +#include "ui/models/info/phones.h" +#include "ui/utils/comboboxdelegate.h" namespace UI { namespace Ui @@ -29,11 +39,36 @@ class ContactContacts; class ContactContacts : public QWidget { Q_OBJECT public: - ContactContacts(const QString& jid, QWidget* parent = nullptr); + ContactContacts(QWidget* parent = nullptr); ~ContactContacts(); + void setVCard(const QString& jid, const Shared::VCard& card, bool editable = false); + void fillVCard(Shared::VCard& card) const; + QString title() const; + +private slots: + void onContextMenu(const QPoint& point); + void onAddAddress(); + void onRemoveAddress(); + void onAddEmail(); + void onCopyEmail(); + void onRemoveEmail(); + void onAddPhone(); + void onCopyPhone(); + void onRemovePhone(); + +private: + void initializeDelegates(); + void initializeViews(); + private: QScopedPointer m_ui; + QMenu* contextMenu; + Models::EMails emails; + Models::Phones phones; + ComboboxDelegate* roleDelegate; + ComboboxDelegate* phoneTypeDelegate; + bool editable; }; } diff --git a/ui/widgets/info/contactgeneral.cpp b/ui/widgets/info/contactgeneral.cpp index 57ce700..ccc6996 100644 --- a/ui/widgets/info/contactgeneral.cpp +++ b/ui/widgets/info/contactgeneral.cpp @@ -196,3 +196,18 @@ void UI::ContactGeneral::setVCard(const QString& jid, const Shared::VCard& card, updateAvatar(); } + +void UI::ContactGeneral::fillVCard(Shared::VCard& card) const { + card.setFullName(m_ui->fullName->text()); + card.setFirstName(m_ui->firstName->text()); + card.setMiddleName(m_ui->middleName->text()); + card.setLastName(m_ui->lastName->text()); + card.setNickName(m_ui->nickName->text()); + card.setBirthday(m_ui->birthday->date()); + card.setOrgName(m_ui->organizationName->text()); + card.setOrgUnit(m_ui->organizationDepartment->text()); + card.setOrgRole(m_ui->organizationRole->text()); + card.setOrgTitle(m_ui->organizationTitle->text()); + card.setAvatarPath(currentAvatarPath); + card.setAvatarType(currentAvatarType); +} diff --git a/ui/widgets/info/contactgeneral.h b/ui/widgets/info/contactgeneral.h index 6233c83..2817e91 100644 --- a/ui/widgets/info/contactgeneral.h +++ b/ui/widgets/info/contactgeneral.h @@ -45,6 +45,7 @@ public: ~ContactGeneral(); void setVCard(const QString& jid, const Shared::VCard& card, bool editable = false); + void fillVCard(Shared::VCard& card) const; QString title() const; private: