diff --git a/core/account.cpp b/core/account.cpp index ff8c334..ed6da44 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -1361,6 +1361,23 @@ void Core::Account::onVCardReceived(const QXmppVCardIq& card) vCard.setOrgUnit(org.unit()); vCard.setOrgTitle(org.title()); + QList emails = card.emails(); + std::deque& myEmails = vCard.getEmails(); + for (const QXmppVCardEmail& em : emails) { + Shared::VCard::Email mEm(em.address()); + QXmppVCardEmail::Type et = em.type(); + if (et & QXmppVCardEmail::Preferred) { + mEm.prefered = true; + } + if (et & QXmppVCardEmail::Home && !(et & QXmppVCardEmail::Work)) { + mEm.role = Shared::VCard::Email::home; + } else if (!(et & QXmppVCardEmail::Home) && et & QXmppVCardEmail::Work) { + mEm.role = Shared::VCard::Email::work; + } + + myEmails.emplace_back(mEm); + } + if (item->hasAvatar()) { if (!item->isAvatarAutoGenerated()) { vCard.setAvatarType(Shared::Avatar::valid); @@ -1483,6 +1500,24 @@ void Core::Account::onOwnVCardReceived(const QXmppVCardIq& card) vCard.setAvatarType(Shared::Avatar::empty); } + + QList emails = card.emails(); + std::deque& myEmails = vCard.getEmails(); + for (const QXmppVCardEmail& em : emails) { + Shared::VCard::Email mEm(em.address()); + QXmppVCardEmail::Type et = em.type(); + if (et & QXmppVCardEmail::Preferred) { + mEm.prefered = true; + } + if (et & QXmppVCardEmail::Home && !(et & QXmppVCardEmail::Work)) { + mEm.role = Shared::VCard::Email::home; + } else if (!(et & QXmppVCardEmail::Home) && et & QXmppVCardEmail::Work) { + mEm.role = Shared::VCard::Email::work; + } + + myEmails.emplace_back(mEm); + } + emit receivedVCard(getLogin() + "@" + getServer(), vCard); } @@ -1535,6 +1570,27 @@ void Core::Account::uploadVCard(const Shared::VCard& card) org.setTitle(card.getOrgTitle()); iq.setOrganization(org); + const std::deque& myEmails = card.getEmails(); + QList emails; + for (const Shared::VCard::Email& mEm : myEmails) { + QXmppVCardEmail em; + QXmppVCardEmail::Type t = QXmppVCardEmail::Internet; + if (mEm.prefered) { + t = t | QXmppVCardEmail::Preferred; + } + if (mEm.role == Shared::VCard::Email::home) { + t = t | QXmppVCardEmail::Home; + } else if (mEm.role == Shared::VCard::Email::work) { + t = t | QXmppVCardEmail::Work; + } + em.setType(t); + em.setAddress(mEm.address); + + emails.push_back(em); + } + + iq.setEmails(emails); + bool avatarChanged = false; if (card.getAvatarType() == Shared::Avatar::empty) { if (avatarType.size() > 0) { diff --git a/global.cpp b/global.cpp index e3ffb11..e223a45 100644 --- a/global.cpp +++ b/global.cpp @@ -538,6 +538,36 @@ QDateTime Shared::VCard::getReceivingTime() const return receivingTime; } +std::deque & Shared::VCard::getEmails() +{ + return emails; +} + +std::deque & Shared::VCard::getAddresses() +{ + return addresses; +} + +std::deque & Shared::VCard::getPhones() +{ + return phones; +} + +const std::deque & Shared::VCard::getEmails() const +{ + return emails; +} + +const std::deque & Shared::VCard::getAddresses() const +{ + return addresses; +} + +const std::deque & Shared::VCard::getPhones() const +{ + return phones; +} + const std::dequeShared::VCard::Contact::roleNames = {"Not specified", "Personal", "Business"}; QIcon Shared::availabilityIcon(Shared::Availability av, bool big) diff --git a/global.h b/global.h index c33bd38..34d892c 100644 --- a/global.h +++ b/global.h @@ -302,6 +302,12 @@ public: QString getOrgTitle() const; void setOrgTitle(const QString& title); QDateTime getReceivingTime() const; + std::deque& getEmails(); + const std::deque& getEmails() const; + std::deque& getPhones(); + const std::deque& getPhones() const; + std::deque
& getAddresses(); + const std::deque
& getAddresses() const; private: QString fullName; diff --git a/ui/utils/comboboxdelegate.cpp b/ui/utils/comboboxdelegate.cpp index 824d1cf..7153405 100644 --- a/ui/utils/comboboxdelegate.cpp +++ b/ui/utils/comboboxdelegate.cpp @@ -15,18 +15,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include "QTimer" #include "comboboxdelegate.h" ComboboxDelegate::ComboboxDelegate(QObject *parent): QStyledItemDelegate(parent), - entries() + entries(), + ff(new FocusFilter()) { } ComboboxDelegate::~ComboboxDelegate() { + delete ff; } @@ -48,6 +51,7 @@ void ComboboxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) int currentIndex = index.data(Qt::EditRole).toInt(); if (currentIndex >= 0) { cb->setCurrentIndex(currentIndex); + cb->installEventFilter(ff); } } @@ -62,3 +66,20 @@ void ComboboxDelegate::addEntry(const QString& title, const QIcon& icon) { entries.emplace_back(title, icon); } + +bool ComboboxDelegate::FocusFilter::eventFilter(QObject* src, QEvent* evt) +{ + if (evt->type() == QEvent::FocusIn) { + QComboBox* cb = static_cast(src); + cb->removeEventFilter(this); + QTimer* timer = new QTimer; //TODO that is ridiculous! I refuse to believe there is no better way than that one! + QObject::connect(timer, &QTimer::timeout, [timer, cb]() { + cb->showPopup(); + timer->deleteLater(); + }); + + timer->setSingleShot(true); + timer->start(100); + } + return QObject::eventFilter(src, evt); +} diff --git a/ui/utils/comboboxdelegate.h b/ui/utils/comboboxdelegate.h index 1d23a5c..a5d79e4 100644 --- a/ui/utils/comboboxdelegate.h +++ b/ui/utils/comboboxdelegate.h @@ -21,6 +21,7 @@ #include #include +#include #include @@ -30,6 +31,12 @@ class ComboboxDelegate : public QStyledItemDelegate { Q_OBJECT + + class FocusFilter : public QObject { + public: + bool eventFilter(QObject *src, QEvent *evt) override; + }; + public: ComboboxDelegate(QObject *parent = nullptr); ~ComboboxDelegate(); @@ -42,6 +49,9 @@ public: private: std::deque> entries; + FocusFilter* ff; }; + + #endif // COMBOBOXDELEGATE_H diff --git a/ui/widgets/vcard/emailsmodel.cpp b/ui/widgets/vcard/emailsmodel.cpp index 4a5024f..2babaad 100644 --- a/ui/widgets/vcard/emailsmodel.cpp +++ b/ui/widgets/vcard/emailsmodel.cpp @@ -43,6 +43,7 @@ QVariant UI::VCard::EMailsModel::data(const QModelIndex& index, int role) const case 0: switch (role) { case Qt::DisplayRole: + case Qt::EditRole: return deque[index.row()].address; default: return QVariant(); @@ -143,3 +144,57 @@ QModelIndex UI::VCard::EMailsModel::addNewEmptyLine() endInsertRows(); return createIndex(deque.size() - 1, 0, &(deque.back())); } + +bool UI::VCard::EMailsModel::isPreferred(int row) const +{ + if (row < deque.size()) { + return deque[row].prefered; + } else { + return false; + } +} + +void UI::VCard::EMailsModel::removeLines(int index, int count) +{ + if (index < deque.size()) { + int maxCount = deque.size() - index; + if (count > maxCount) { + count = maxCount; + } + + if (count > 0) { + beginRemoveRows(QModelIndex(), index, index + count - 1); + std::deque::const_iterator itr = deque.begin() + index; + std::deque::const_iterator end = itr + count; + deque.erase(itr, end); + endRemoveRows(); + } + } +} + +void UI::VCard::EMailsModel::getEmails(std::deque& emails) const +{ + for (const Shared::VCard::Email& my : deque) { + emails.emplace_back(my); + } +} + +void UI::VCard::EMailsModel::setEmails(const std::deque& emails) +{ + if (deque.size() > 0) { + removeLines(0, deque.size()); + } + + if (emails.size() > 0) { + beginInsertRows(QModelIndex(), 0, emails.size() - 1); + for (const Shared::VCard::Email& comming : emails) { + deque.emplace_back(comming); + } + endInsertRows(); + } +} + +void UI::VCard::EMailsModel::revertPreferred(int row) +{ + setData(createIndex(row, 2), !isPreferred(row)); +} diff --git a/ui/widgets/vcard/emailsmodel.h b/ui/widgets/vcard/emailsmodel.h index ddb0a57..10a610f 100644 --- a/ui/widgets/vcard/emailsmodel.h +++ b/ui/widgets/vcard/emailsmodel.h @@ -40,9 +40,15 @@ public: QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) 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(int row) const; + + void removeLines(int index, int count); + void setEmails(const std::deque& emails); + void getEmails(std::deque& emails) const; public slots: QModelIndex addNewEmptyLine(); + void revertPreferred(int row); private: bool edit; diff --git a/ui/widgets/vcard/vcard.cpp b/ui/widgets/vcard/vcard.cpp index 3f7778e..850830d 100644 --- a/ui/widgets/vcard/vcard.cpp +++ b/ui/widgets/vcard/vcard.cpp @@ -21,6 +21,8 @@ #include +#include + const std::set VCard::supportedTypes = {"image/jpeg", "image/png"}; VCard::VCard(const QString& jid, bool edit, QWidget* parent): @@ -58,6 +60,7 @@ VCard::VCard(const QString& jid, bool edit, QWidget* parent): m_ui->emailsView->setContextMenuPolicy(Qt::CustomContextMenu); m_ui->emailsView->setModel(&emails); m_ui->emailsView->setItemDelegateForColumn(1, roleDelegate); + m_ui->emailsView->setColumnWidth(2, 30); m_ui->emailsView->horizontalHeader()->setStretchLastSection(false); m_ui->emailsView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); @@ -68,7 +71,7 @@ VCard::VCard(const QString& jid, bool edit, QWidget* parent): m_ui->avatarButton->setMenu(avatarMenu); avatarMenu->addAction(setAvatar); avatarMenu->addAction(clearAvatar); - m_ui->title->setText(tr("Your card")); + m_ui->title->setText(tr("Account %1 card").arg(jid)); } else { m_ui->buttonBox->hide(); m_ui->fullName->setReadOnly(true); @@ -149,6 +152,9 @@ void VCard::setVCard(const Shared::VCard& card) currentAvatarPath = card.getAvatarPath(); updateAvatar(); + + const std::deque& ems = card.getEmails(); + emails.setEmails(ems); } QString VCard::getJid() const @@ -174,6 +180,8 @@ void VCard::onButtonBoxAccepted() card.setAvatarPath(currentAvatarPath); card.setAvatarType(currentAvatarType); + emails.getEmails(card.getEmails()); + emit saveVCard(card); } @@ -278,6 +286,25 @@ void VCard::onContextMenu(const QPoint& point) hasMenu = true; QAction* add = contextMenu->addAction(Shared::icon("list-add"), tr("Add email address")); connect(add, &QAction::triggered, this, &VCard::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("view-media-favorite"), tr("Unset this email as preferred")); + connect(rev, &QAction::triggered, std::bind(&UI::VCard::EMailsModel::revertPreferred, &emails, row)); + } else { + QAction* rev = contextMenu->addAction(Shared::icon("favorite"), tr("Set this email as preferred")); + connect(rev, &QAction::triggered, std::bind(&UI::VCard::EMailsModel::revertPreferred, &emails, row)); + } + } + + QAction* del = contextMenu->addAction(Shared::icon("remove"), tr("Remove selected email addresses")); + connect(del, &QAction::triggered, this, &VCard::onRemoveEmail); + } } } @@ -305,6 +332,23 @@ void VCard::onRemoveAddress() } void VCard::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 VCard::onRemovePhone() diff --git a/ui/widgets/vcard/vcard.ui b/ui/widgets/vcard/vcard.ui index a4381b3..e08bf49 100644 --- a/ui/widgets/vcard/vcard.ui +++ b/ui/widgets/vcard/vcard.ui @@ -84,7 +84,7 @@ QTabWidget::Rounded - 1 + 0 Qt::ElideNone @@ -564,7 +564,7 @@ 497 - + @@ -644,7 +644,7 @@ <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">Addresses</span></p></body></html> - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignCenter @@ -670,7 +670,7 @@ <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">E-Mail addresses</span></p></body></html> - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignCenter @@ -752,7 +752,7 @@ <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">Phone numbers</span></p></body></html> - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignCenter