1
0
forked from blue/squawk

VCard: email list now displays and stores on server vcard

This commit is contained in:
Blue 2019-11-04 18:22:39 +03:00
parent 0b57e6a77f
commit 5bbacad84a
9 changed files with 235 additions and 7 deletions

View File

@ -1361,6 +1361,23 @@ void Core::Account::onVCardReceived(const QXmppVCardIq& card)
vCard.setOrgUnit(org.unit()); vCard.setOrgUnit(org.unit());
vCard.setOrgTitle(org.title()); vCard.setOrgTitle(org.title());
QList<QXmppVCardEmail> emails = card.emails();
std::deque<Shared::VCard::Email>& 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->hasAvatar()) {
if (!item->isAvatarAutoGenerated()) { if (!item->isAvatarAutoGenerated()) {
vCard.setAvatarType(Shared::Avatar::valid); vCard.setAvatarType(Shared::Avatar::valid);
@ -1483,6 +1500,24 @@ void Core::Account::onOwnVCardReceived(const QXmppVCardIq& card)
vCard.setAvatarType(Shared::Avatar::empty); vCard.setAvatarType(Shared::Avatar::empty);
} }
QList<QXmppVCardEmail> emails = card.emails();
std::deque<Shared::VCard::Email>& 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); emit receivedVCard(getLogin() + "@" + getServer(), vCard);
} }
@ -1535,6 +1570,27 @@ void Core::Account::uploadVCard(const Shared::VCard& card)
org.setTitle(card.getOrgTitle()); org.setTitle(card.getOrgTitle());
iq.setOrganization(org); iq.setOrganization(org);
const std::deque<Shared::VCard::Email>& myEmails = card.getEmails();
QList<QXmppVCardEmail> 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; bool avatarChanged = false;
if (card.getAvatarType() == Shared::Avatar::empty) { if (card.getAvatarType() == Shared::Avatar::empty) {
if (avatarType.size() > 0) { if (avatarType.size() > 0) {

View File

@ -538,6 +538,36 @@ QDateTime Shared::VCard::getReceivingTime() const
return receivingTime; return receivingTime;
} }
std::deque<Shared::VCard::Email> & Shared::VCard::getEmails()
{
return emails;
}
std::deque<Shared::VCard::Address> & Shared::VCard::getAddresses()
{
return addresses;
}
std::deque<Shared::VCard::Phone> & Shared::VCard::getPhones()
{
return phones;
}
const std::deque<Shared::VCard::Email> & Shared::VCard::getEmails() const
{
return emails;
}
const std::deque<Shared::VCard::Address> & Shared::VCard::getAddresses() const
{
return addresses;
}
const std::deque<Shared::VCard::Phone> & Shared::VCard::getPhones() const
{
return phones;
}
const std::deque<QString>Shared::VCard::Contact::roleNames = {"Not specified", "Personal", "Business"}; const std::deque<QString>Shared::VCard::Contact::roleNames = {"Not specified", "Personal", "Business"};
QIcon Shared::availabilityIcon(Shared::Availability av, bool big) QIcon Shared::availabilityIcon(Shared::Availability av, bool big)

View File

@ -302,6 +302,12 @@ public:
QString getOrgTitle() const; QString getOrgTitle() const;
void setOrgTitle(const QString& title); void setOrgTitle(const QString& title);
QDateTime getReceivingTime() const; QDateTime getReceivingTime() const;
std::deque<Email>& getEmails();
const std::deque<Email>& getEmails() const;
std::deque<Phone>& getPhones();
const std::deque<Phone>& getPhones() const;
std::deque<Address>& getAddresses();
const std::deque<Address>& getAddresses() const;
private: private:
QString fullName; QString fullName;

View File

@ -15,18 +15,21 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "QTimer"
#include "comboboxdelegate.h" #include "comboboxdelegate.h"
ComboboxDelegate::ComboboxDelegate(QObject *parent): ComboboxDelegate::ComboboxDelegate(QObject *parent):
QStyledItemDelegate(parent), QStyledItemDelegate(parent),
entries() entries(),
ff(new FocusFilter())
{ {
} }
ComboboxDelegate::~ComboboxDelegate() ComboboxDelegate::~ComboboxDelegate()
{ {
delete ff;
} }
@ -48,6 +51,7 @@ void ComboboxDelegate::setEditorData(QWidget *editor, const QModelIndex &index)
int currentIndex = index.data(Qt::EditRole).toInt(); int currentIndex = index.data(Qt::EditRole).toInt();
if (currentIndex >= 0) { if (currentIndex >= 0) {
cb->setCurrentIndex(currentIndex); cb->setCurrentIndex(currentIndex);
cb->installEventFilter(ff);
} }
} }
@ -62,3 +66,20 @@ void ComboboxDelegate::addEntry(const QString& title, const QIcon& icon)
{ {
entries.emplace_back(title, icon); entries.emplace_back(title, icon);
} }
bool ComboboxDelegate::FocusFilter::eventFilter(QObject* src, QEvent* evt)
{
if (evt->type() == QEvent::FocusIn) {
QComboBox* cb = static_cast<QComboBox*>(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);
}

View File

@ -21,6 +21,7 @@
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QComboBox> #include <QComboBox>
#include <QFocusEvent>
#include <deque> #include <deque>
@ -30,6 +31,12 @@
class ComboboxDelegate : public QStyledItemDelegate class ComboboxDelegate : public QStyledItemDelegate
{ {
Q_OBJECT Q_OBJECT
class FocusFilter : public QObject {
public:
bool eventFilter(QObject *src, QEvent *evt) override;
};
public: public:
ComboboxDelegate(QObject *parent = nullptr); ComboboxDelegate(QObject *parent = nullptr);
~ComboboxDelegate(); ~ComboboxDelegate();
@ -42,6 +49,9 @@ public:
private: private:
std::deque<std::pair<QString, QIcon>> entries; std::deque<std::pair<QString, QIcon>> entries;
FocusFilter* ff;
}; };
#endif // COMBOBOXDELEGATE_H #endif // COMBOBOXDELEGATE_H

View File

@ -43,6 +43,7 @@ QVariant UI::VCard::EMailsModel::data(const QModelIndex& index, int role) const
case 0: case 0:
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
case Qt::EditRole:
return deque[index.row()].address; return deque[index.row()].address;
default: default:
return QVariant(); return QVariant();
@ -143,3 +144,57 @@ QModelIndex UI::VCard::EMailsModel::addNewEmptyLine()
endInsertRows(); endInsertRows();
return createIndex(deque.size() - 1, 0, &(deque.back())); 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<Shared::VCard::Email>::const_iterator itr = deque.begin() + index;
std::deque<Shared::VCard::Email>::const_iterator end = itr + count;
deque.erase(itr, end);
endRemoveRows();
}
}
}
void UI::VCard::EMailsModel::getEmails(std::deque<Shared::VCard::Email>& emails) const
{
for (const Shared::VCard::Email& my : deque) {
emails.emplace_back(my);
}
}
void UI::VCard::EMailsModel::setEmails(const std::deque<Shared::VCard::Email>& 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));
}

View File

@ -40,9 +40,15 @@ public:
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex &index) const 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<Shared::VCard::Email>& emails);
void getEmails(std::deque<Shared::VCard::Email>& emails) const;
public slots: public slots:
QModelIndex addNewEmptyLine(); QModelIndex addNewEmptyLine();
void revertPreferred(int row);
private: private:
bool edit; bool edit;

View File

@ -21,6 +21,8 @@
#include <QDebug> #include <QDebug>
#include <algorithm>
const std::set<QString> VCard::supportedTypes = {"image/jpeg", "image/png"}; const std::set<QString> VCard::supportedTypes = {"image/jpeg", "image/png"};
VCard::VCard(const QString& jid, bool edit, QWidget* parent): 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->setContextMenuPolicy(Qt::CustomContextMenu);
m_ui->emailsView->setModel(&emails); m_ui->emailsView->setModel(&emails);
m_ui->emailsView->setItemDelegateForColumn(1, roleDelegate); m_ui->emailsView->setItemDelegateForColumn(1, roleDelegate);
m_ui->emailsView->setColumnWidth(2, 30);
m_ui->emailsView->horizontalHeader()->setStretchLastSection(false); m_ui->emailsView->horizontalHeader()->setStretchLastSection(false);
m_ui->emailsView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); 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); m_ui->avatarButton->setMenu(avatarMenu);
avatarMenu->addAction(setAvatar); avatarMenu->addAction(setAvatar);
avatarMenu->addAction(clearAvatar); avatarMenu->addAction(clearAvatar);
m_ui->title->setText(tr("Your card")); m_ui->title->setText(tr("Account %1 card").arg(jid));
} else { } else {
m_ui->buttonBox->hide(); m_ui->buttonBox->hide();
m_ui->fullName->setReadOnly(true); m_ui->fullName->setReadOnly(true);
@ -149,6 +152,9 @@ void VCard::setVCard(const Shared::VCard& card)
currentAvatarPath = card.getAvatarPath(); currentAvatarPath = card.getAvatarPath();
updateAvatar(); updateAvatar();
const std::deque<Shared::VCard::Email>& ems = card.getEmails();
emails.setEmails(ems);
} }
QString VCard::getJid() const QString VCard::getJid() const
@ -174,6 +180,8 @@ void VCard::onButtonBoxAccepted()
card.setAvatarPath(currentAvatarPath); card.setAvatarPath(currentAvatarPath);
card.setAvatarType(currentAvatarType); card.setAvatarType(currentAvatarType);
emails.getEmails(card.getEmails());
emit saveVCard(card); emit saveVCard(card);
} }
@ -278,6 +286,25 @@ void VCard::onContextMenu(const QPoint& point)
hasMenu = true; hasMenu = true;
QAction* add = contextMenu->addAction(Shared::icon("list-add"), tr("Add email address")); QAction* add = contextMenu->addAction(Shared::icon("list-add"), tr("Add email address"));
connect(add, &QAction::triggered, this, &VCard::onAddEmail); 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() void VCard::onRemoveEmail()
{ {
QItemSelection selection(m_ui->emailsView->selectionModel()->selection());
QList<int> 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() void VCard::onRemovePhone()

View File

@ -84,7 +84,7 @@
<enum>QTabWidget::Rounded</enum> <enum>QTabWidget::Rounded</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>0</number>
</property> </property>
<property name="elideMode"> <property name="elideMode">
<enum>Qt::ElideNone</enum> <enum>Qt::ElideNone</enum>
@ -564,7 +564,7 @@
<height>497</height> <height>497</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="1,3,1,0"> <layout class="QGridLayout" name="gridLayout_3" columnstretch="1,3,1">
<item row="7" column="1"> <item row="7" column="1">
<widget class="Line" name="phonesLine"> <widget class="Line" name="phonesLine">
<property name="orientation"> <property name="orientation">
@ -644,7 +644,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt; font-weight:600;&quot;&gt;Addresses&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt; font-weight:600;&quot;&gt;Addresses&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
@ -670,7 +670,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt; font-weight:600;&quot;&gt;E-Mail addresses&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt; font-weight:600;&quot;&gt;E-Mail addresses&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
@ -752,7 +752,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt; font-weight:600;&quot;&gt;Phone numbers&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt; font-weight:600;&quot;&gt;Phone numbers&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignCenter</set>
</property> </property>
</widget> </widget>
</item> </item>