From 652381b06762b5d1387dcc27efdea2a9ff2604bd Mon Sep 17 00:00:00 2001 From: blue Date: Wed, 23 Oct 2019 17:49:56 +0300 Subject: [PATCH] changing avatar in local vcard, no uploading yet --- ui/models/roster.cpp | 20 +++--- ui/squawk.cpp | 16 +++++ ui/squawk.h | 2 + ui/utils/image.cpp | 16 ----- ui/utils/image.h | 3 - ui/widgets/conversation.cpp | 6 +- ui/widgets/vcard.cpp | 135 ++++++++++++++++++++++++++++++------ ui/widgets/vcard.h | 23 +++++- ui/widgets/vcard.ui | 63 +++++++++++++++-- 9 files changed, 221 insertions(+), 63 deletions(-) diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index 5ea5b2e..33998dc 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -29,17 +29,14 @@ Models::Roster::Roster(QObject* parent): groups(), contacts() { - connect(accountsModel, - SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector&)), - this, - SLOT(onAccountDataChanged(const QModelIndex&, const QModelIndex&, const QVector&))); - connect(root, SIGNAL(childChanged(Models::Item*, int, int)), this, SLOT(onChildChanged(Models::Item*, int, int))); - connect(root, SIGNAL(childIsAboutToBeInserted(Item*, int, int)), this, SLOT(onChildIsAboutToBeInserted(Item*, int, int))); - connect(root, SIGNAL(childInserted()), this, SLOT(onChildInserted())); - connect(root, SIGNAL(childIsAboutToBeRemoved(Item*, int, int)), this, SLOT(onChildIsAboutToBeRemoved(Item*, int, int))); - connect(root, SIGNAL(childRemoved()), this, SLOT(onChildRemoved())); - connect(root, SIGNAL(childIsAboutToBeMoved(Item*, int, int, Item*, int)), this, SLOT(onChildIsAboutToBeMoved(Item*, int, int, Item*, int))); - connect(root, SIGNAL(childMoved()), this, SLOT(onChildMoved())); + connect(accountsModel, &Accounts::dataChanged, this, &Roster::onAccountDataChanged); + connect(root, &Item::childChanged, this, &Roster::onChildChanged); + connect(root, &Item::childIsAboutToBeInserted, this, &Roster::onChildIsAboutToBeInserted); + connect(root, &Item::childInserted, this, &Roster::onChildInserted); + connect(root, &Item::childIsAboutToBeRemoved, this, &Roster::onChildIsAboutToBeRemoved); + connect(root, &Item::childRemoved, this, &Roster::onChildRemoved); + connect(root, &Item::childIsAboutToBeMoved, this, &Roster::onChildIsAboutToBeMoved); + connect(root, &Item::childMoved, this, &Roster::onChildMoved); } Models::Roster::~Roster() @@ -69,6 +66,7 @@ QVariant Models::Roster::data (const QModelIndex& index, int role) const case Qt::DisplayRole: { if (index.column() != 0) { + result = ""; break; } switch (item->type) { diff --git a/ui/squawk.cpp b/ui/squawk.cpp index 051e691..b5cb84c 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -56,6 +56,8 @@ Squawk::Squawk(QWidget *parent) : connect(rosterModel.accountsModel, SIGNAL(sizeChanged(unsigned int)), this, SLOT(onAccountsSizeChanged(unsigned int))); //m_ui->mainToolBar->addWidget(m_ui->comboBox); + + setWindowTitle(tr("Contact list")); } Squawk::~Squawk() { @@ -768,10 +770,16 @@ void Squawk::onActivateVCard(const QString& account, const QString& jid, bool ed card = itr->second; } else { card = new VCard(jid, edition); + if (edition) { + card->setWindowTitle(tr("%1 account card").arg(account)); + } else { + card->setWindowTitle(tr("%1 contact card").arg(jid)); + } card->setAttribute(Qt::WA_DeleteOnClose); vCards.insert(std::make_pair(jid, card)); connect(card, &VCard::destroyed, this, &Squawk::onVCardClosed); + connect(card, &VCard::saveVCard, std::bind( &Squawk::onVCardSave, this, std::placeholders::_1, account)); } card->show(); @@ -780,3 +788,11 @@ void Squawk::onActivateVCard(const QString& account, const QString& jid, bool ed emit requestVCard(account, jid); } + +void Squawk::onVCardSave(const Shared::VCard& card, const QString& account) +{ + VCard* widget = static_cast(sender()); + emit uploadVCard(account, card); + + widget->deleteLater(); +} diff --git a/ui/squawk.h b/ui/squawk.h index 7308882..bf6582f 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -73,6 +73,7 @@ signals: void fileLocalPathRequest(const QString& messageId, const QString& url); void downloadFileRequest(const QString& messageId, const QString& url); void requestVCard(const QString& account, const QString& jid); + void uploadVCard(const QString& account, const Shared::VCard& card); public slots: void newAccount(const QMap& account); @@ -126,6 +127,7 @@ private slots: void onAccountsClosed(QObject* parent = 0); void onConversationClosed(QObject* parent = 0); void onVCardClosed(); + void onVCardSave(const Shared::VCard& card, const QString& account); void onActivateVCard(const QString& account, const QString& jid, bool edition = false); void onComboboxActivated(int index); void onRosterItemDoubleClicked(const QModelIndex& item); diff --git a/ui/utils/image.cpp b/ui/utils/image.cpp index dca8153..1d09709 100644 --- a/ui/utils/image.cpp +++ b/ui/utils/image.cpp @@ -29,16 +29,6 @@ Image::Image(const QString& path, quint16 p_minWidth, QWidget* parent): recalculateAspectRatio(); } -Image::Image(const QString& path, quint16 width, quint16 height, quint16 p_minWidth, QWidget* parent): - QLabel(parent), - pixmap(QIcon(path).pixmap(QSize(width, height))), - aspectRatio(0), - minWidth(p_minWidth) -{ - setScaledContents(true); - recalculateAspectRatio(); -} - Image::~Image() { @@ -83,9 +73,3 @@ void Image::setPath(const QString& path) pixmap = QPixmap(path); recalculateAspectRatio(); } - -void Image::setPath(const QString& path, quint16 width, quint16 height) -{ - pixmap = QPixmap(QIcon(path).pixmap(QSize(width, height))); - recalculateAspectRatio(); -} diff --git a/ui/utils/image.h b/ui/utils/image.h index 82071ca..883ddf4 100644 --- a/ui/utils/image.h +++ b/ui/utils/image.h @@ -21,7 +21,6 @@ #include #include -#include /** * @todo write docs @@ -30,7 +29,6 @@ class Image : public QLabel { public: Image(const QString& path, quint16 minWidth = 50, QWidget* parent = nullptr); - Image(const QString& path, quint16 width, quint16 height, quint16 minWidth = 50, QWidget* parent = nullptr); ~Image(); @@ -38,7 +36,6 @@ public: int widthForHeight(int height) const; bool hasHeightForWidth() const override; void setPath(const QString& path); - void setPath(const QString& path, quint16 width, quint16 height); void setMinWidth(quint16 minWidth); private: diff --git a/ui/widgets/conversation.cpp b/ui/widgets/conversation.cpp index d661a5c..c281258 100644 --- a/ui/widgets/conversation.cpp +++ b/ui/widgets/conversation.cpp @@ -257,11 +257,11 @@ void Conversation::showEvent(QShowEvent* event) void Conversation::onAttach() { - QFileDialog* d = new QFileDialog(this, "Chose a file to send"); + QFileDialog* d = new QFileDialog(this, tr("Chose a file to send")); d->setFileMode(QFileDialog::ExistingFile); - connect(d, SIGNAL(accepted()), this, SLOT(onFileSelected())); - connect(d, SIGNAL(rejected()), d, SLOT(deleteLater())); + connect(d, &QFileDialog::accepted, this, &Conversation::onFileSelected); + connect(d, &QFileDialog::rejected, d, &QFileDialog::deleteLater); d->show(); } diff --git a/ui/widgets/vcard.cpp b/ui/widgets/vcard.cpp index e19538a..552e078 100644 --- a/ui/widgets/vcard.cpp +++ b/ui/widgets/vcard.cpp @@ -19,22 +19,37 @@ #include "vcard.h" #include "ui_vcard.h" +#include + +const std::set VCard::supportedTypes = {"image/jpeg", "image/png"}; + VCard::VCard(const QString& jid, bool edit, QWidget* parent): QWidget(parent), m_ui(new Ui::VCard()), - avatar(QApplication::palette().window().color().lightnessF() > 0.5 ? ":/images/fallback/dark/big/user.svg" : ":/images/fallback/light/big/user.svg", 256, 256, 256) + avatarButtonMargins(), + avatarMenu(nullptr), + editable(edit), + currentAvatarType(Shared::Avatar::empty), + currentAvatarPath("") { m_ui->setupUi(this); m_ui->jabberID->setText(jid); m_ui->jabberID->setReadOnly(true); - QGridLayout* general = static_cast(m_ui->General->layout()); - general->addWidget(&avatar, 2, 2, 1, 1); - avatar.setFrameShape(QFrame::StyledPanel); - avatar.setFrameShadow(QFrame::Sunken); - avatar.setMargin(6); + + QAction* setAvatar = m_ui->actionSetAvatar; + QAction* clearAvatar = m_ui->actionClearAvatar; + + connect(setAvatar, &QAction::triggered, this, &VCard::onSetAvatar); + connect(clearAvatar, &QAction::triggered, this, &VCard::onClearAvatar); + + setAvatar->setEnabled(true); + clearAvatar->setEnabled(false); if (edit) { - + avatarMenu = new QMenu(); + m_ui->avatarButton->setMenu(avatarMenu); + avatarMenu->addAction(setAvatar); + avatarMenu->addAction(clearAvatar); } else { m_ui->buttonBox->hide(); m_ui->firstName->setReadOnly(true); @@ -53,13 +68,17 @@ VCard::VCard(const QString& jid, bool edit, QWidget* parent): connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &VCard::onButtonBoxAccepted); connect(m_ui->buttonBox, &QDialogButtonBox::rejected, m_ui->buttonBox, &QDialogButtonBox::deleteLater); - int height = m_ui->personalForm->minimumSize().height(); - avatar.setMaximumSize(avatar.widthForHeight(height), height); - avatar.setMinimumSize(avatar.widthForHeight(height), height); + avatarButtonMargins = m_ui->avatarButton->size(); + + int height = m_ui->personalForm->minimumSize().height() - avatarButtonMargins.height(); + m_ui->avatarButton->setIconSize(QSize(height, height)); } VCard::~VCard() { + if (editable) { + avatarMenu->deleteLater(); + } } void VCard::setVCard(const QString& jid, const Shared::VCard& card) @@ -80,20 +99,10 @@ void VCard::setVCard(const Shared::VCard& card) //m_ui->organizationTitle->setText(card.get()); //m_ui->organizationRole->setText(card.get()); m_ui->description->setText(card.getDescription()); + currentAvatarType = card.getAvatarType(); + currentAvatarPath = card.getAvatarPath(); - switch (card.getAvatarType()) { - case Shared::Avatar::empty: - avatar.setPath(QApplication::palette().window().color().lightnessF() > 0.5 ? ":/images/fallback/dark/big/user.svg" : ":/images/fallback/light/big/user.svg", 256, 256); - break; - case Shared::Avatar::autocreated: - case Shared::Avatar::valid: - avatar.setPath(card.getAvatarPath()); - break; - } - - int height = m_ui->personalForm->minimumSize().height(); - avatar.setMaximumSize(avatar.widthForHeight(height), height); - avatar.setMinimumSize(avatar.widthForHeight(height), height); + updateAvatar(); } QString VCard::getJid() const @@ -110,6 +119,86 @@ void VCard::onButtonBoxAccepted() card.setNickName(m_ui->nickName->text()); card.setBirthday(m_ui->birthday->date()); card.setDescription(m_ui->description->toPlainText()); + card.setAvatarPath(currentAvatarPath); + card.setAvatarType(currentAvatarType); emit saveVCard(card); } + +void VCard::onClearAvatar() +{ + currentAvatarType = Shared::Avatar::empty; + currentAvatarPath = ""; + + updateAvatar(); +} + +void VCard::onSetAvatar() +{ + QFileDialog* d = new QFileDialog(this, tr("Chose your new avatar")); + d->setFileMode(QFileDialog::ExistingFile); + d->setNameFilter(tr("Images (*.png *.jpg *.jpeg)")); + + connect(d, &QFileDialog::accepted, this, &VCard::onAvatarSelected); + connect(d, &QFileDialog::rejected, d, &QFileDialog::deleteLater); + + d->show(); +} + +void VCard::updateAvatar() +{ + int height = m_ui->personalForm->minimumSize().height() - avatarButtonMargins.height(); + switch (currentAvatarType) { + case Shared::Avatar::empty: + m_ui->avatarButton->setIcon(Shared::icon("user", true)); + m_ui->avatarButton->setIconSize(QSize(height, height)); + m_ui->actionClearAvatar->setEnabled(false); + break; + case Shared::Avatar::autocreated: + case Shared::Avatar::valid: + QPixmap pixmap(currentAvatarPath); + qreal h = pixmap.height(); + qreal w = pixmap.width(); + qreal aspectRatio = w / h; + m_ui->avatarButton->setIconSize(QSize(height * aspectRatio, height)); + m_ui->avatarButton->setIcon(QIcon(currentAvatarPath)); + m_ui->actionClearAvatar->setEnabled(true); + break; + } +} + +void VCard::onAvatarSelected() +{ + QFileDialog* d = static_cast(sender()); + QMimeDatabase db; + QString path = d->selectedFiles().front(); + QMimeType type = db.mimeTypeForFile(path); + d->deleteLater(); + + if (supportedTypes.find(type.name()) == supportedTypes.end()) { + qDebug() << "Selected for avatar file is not supported, skipping"; + } else { + QImage src(path); + QImage dst; + if (src.width() > 160 || src.height() > 160) { + dst = src.scaled(160, 160, Qt::KeepAspectRatio); + } + QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + m_ui->jabberID->text() + ".temp." + type.preferredSuffix(); + QFile oldTemp(path); + if (oldTemp.exists()) { + if (!oldTemp.remove()) { + qDebug() << "Error removing old temp avatar" << path; + return; + } + } + bool success = dst.save(path); + if (success) { + currentAvatarPath = path; + currentAvatarType = Shared::Avatar::valid; + + updateAvatar(); + } else { + qDebug() << "couldn't save avatar" << path << ", skipping"; + } + } +} diff --git a/ui/widgets/vcard.h b/ui/widgets/vcard.h index f4c81be..afba227 100644 --- a/ui/widgets/vcard.h +++ b/ui/widgets/vcard.h @@ -21,9 +21,16 @@ #include #include +#include +#include +#include +#include +#include +#include + +#include #include "../../global.h" -#include "../utils/image.h" namespace Ui { @@ -49,10 +56,22 @@ signals: private slots: void onButtonBoxAccepted(); + void onClearAvatar(); + void onSetAvatar(); + void onAvatarSelected(); private: QScopedPointer m_ui; - Image avatar; + QSize avatarButtonMargins; + QMenu* avatarMenu; + bool editable; + Shared::Avatar currentAvatarType; + QString currentAvatarPath; + + static const std::set supportedTypes; + +private: + void updateAvatar(); }; #endif // VCARD_H diff --git a/ui/widgets/vcard.ui b/ui/widgets/vcard.ui index 179e235..406ca9a 100644 --- a/ui/widgets/vcard.ui +++ b/ui/widgets/vcard.ui @@ -6,8 +6,8 @@ 0 0 - 560 - 534 + 537 + 539 @@ -411,6 +411,43 @@ + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + + + + QToolButton::InstantPopup + + + Qt::ToolButtonIconOnly + + + Qt::NoArrow + + + @@ -459,8 +496,8 @@ 0 0 - 548 - 410 + 525 + 415 @@ -625,7 +662,7 @@ - + <html><head/><body><p><span style=" font-style:italic;">User has no contact e-mail addresses</span></p></body></html> @@ -717,6 +754,22 @@ + + + + + + Set avatar + + + + + + + + Clear avatar + + firstName