From 1de0129e1e41a5a57c95bbbb92cfa3e68727a620 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 2 May 2017 14:32:35 +0200 Subject: [PATCH] fix(ui/views/App/Main/ContactEdit): smart edition --- .../src/components/calls/CallsListModel.cpp | 2 +- .../src/components/contact/ContactModel.cpp | 62 +++- .../src/components/contact/ContactModel.hpp | 19 +- .../src/components/contact/VcardModel.cpp | 15 +- .../src/components/contact/VcardModel.hpp | 6 +- .../ui/modules/Common/Form/ListForm.qml | 11 - linphone-desktop/ui/scripts/Utils/utils.js | 14 +- .../ui/views/App/Main/ContactEdit.js | 82 +++--- .../ui/views/App/Main/ContactEdit.qml | 275 +++++++++--------- 9 files changed, 248 insertions(+), 238 deletions(-) diff --git a/linphone-desktop/src/components/calls/CallsListModel.cpp b/linphone-desktop/src/components/calls/CallsListModel.cpp index 6a7eb6c27..9bb5ca8e3 100644 --- a/linphone-desktop/src/components/calls/CallsListModel.cpp +++ b/linphone-desktop/src/components/calls/CallsListModel.cpp @@ -195,7 +195,7 @@ void CallsListModel::removeCall (const shared_ptr &call) { } catch (const out_of_range &) { // Can be a bug. Or the call model not exists because the linphone call state // `CallStateIncomingReceived`/`CallStateOutgoingInit` was not notified. - qWarning() << QStringLiteral("Unable to found call in:") << callModel; + qWarning() << QStringLiteral("Unable to found linphone call:") << &(*call); return; } diff --git a/linphone-desktop/src/components/contact/ContactModel.cpp b/linphone-desktop/src/components/contact/ContactModel.cpp index d1e78475b..17ff9a324 100644 --- a/linphone-desktop/src/components/contact/ContactModel.cpp +++ b/linphone-desktop/src/components/contact/ContactModel.cpp @@ -31,28 +31,39 @@ using namespace std; // ============================================================================= ContactModel::ContactModel (QObject *parent, shared_ptr linphoneFriend) : QObject(parent) { - mLinphoneFriend = linphoneFriend; - mVcard = make_shared(linphoneFriend->getVcard()); + Q_ASSERT(linphoneFriend != nullptr); + + mLinphoneFriend = linphoneFriend; + + mVcardModel = new VcardModel(linphoneFriend->getVcard()); + App::getInstance()->getEngine()->setObjectOwnership(mVcardModel, QQmlEngine::CppOwnership); - App::getInstance()->getEngine()->setObjectOwnership(mVcard.get(), QQmlEngine::CppOwnership); mLinphoneFriend->setData("contact-model", *this); } -ContactModel::ContactModel (QObject *parent, VcardModel *vcard) : QObject(parent) { - Q_ASSERT(vcard != nullptr); +ContactModel::ContactModel (QObject *parent, VcardModel *vcardModel) : QObject(parent) { + Q_ASSERT(vcardModel != nullptr); QQmlEngine *engine = App::getInstance()->getEngine(); - if (engine->objectOwnership(vcard) == QQmlEngine::CppOwnership) - throw invalid_argument("A contact is already linked to this vcard."); + if (engine->objectOwnership(vcardModel) == QQmlEngine::CppOwnership) { + qWarning() << QStringLiteral("A contact is already linked to this vcard:") << vcardModel; + abort(); + } - mLinphoneFriend = linphone::Friend::newFromVcard(vcard->mVcard); + Q_ASSERT(vcardModel->mVcard != nullptr); + + mLinphoneFriend = linphone::Friend::newFromVcard(vcardModel->mVcard); mLinphoneFriend->setData("contact-model", *this); - mVcard.reset(vcard); + mVcardModel = vcardModel; - engine->setObjectOwnership(vcard, QQmlEngine::CppOwnership); + engine->setObjectOwnership(vcardModel, QQmlEngine::CppOwnership); + + qInfo() << QStringLiteral("Create contact from vcard:") << this << vcardModel; } +// ----------------------------------------------------------------------------- + void ContactModel::refreshPresence () { Presence::PresenceStatus status = static_cast( mLinphoneFriend->getConsolidatedPresence() @@ -62,15 +73,17 @@ void ContactModel::refreshPresence () { emit presenceLevelChanged(Presence::getPresenceLevel(status)); } +// ----------------------------------------------------------------------------- + void ContactModel::startEdit () { mLinphoneFriend->edit(); - mOldSipAddresses = mVcard->getSipAddresses(); + mOldSipAddresses = mVcardModel->getSipAddresses(); } void ContactModel::endEdit () { mLinphoneFriend->done(); - QVariantList sipAddresses = mVcard->getSipAddresses(); + QVariantList sipAddresses = mVcardModel->getSipAddresses(); QSet done; for (const auto &variantA : mOldSipAddresses) { @@ -104,13 +117,13 @@ next: } void ContactModel::abortEdit () { - // TODO: call linphone friend abort function when available. - // mLinphoneFriend->abort(); mOldSipAddresses.clear(); emit contactUpdated(); } +// ----------------------------------------------------------------------------- + Presence::PresenceStatus ContactModel::getPresenceStatus () const { return static_cast(mLinphoneFriend->getConsolidatedPresence()); } @@ -118,3 +131,24 @@ Presence::PresenceStatus ContactModel::getPresenceStatus () const { Presence::PresenceLevel ContactModel::getPresenceLevel () const { return Presence::getPresenceLevel(getPresenceStatus()); } + +// ----------------------------------------------------------------------------- + +VcardModel *ContactModel::getVcardModel () const { + return mVcardModel; +} + +void ContactModel::setVcardModel (VcardModel *vcardModel) { + Q_ASSERT(vcardModel != nullptr); + Q_ASSERT(vcardModel != mVcardModel); + + QQmlEngine *engine = App::getInstance()->getEngine(); + engine->setObjectOwnership(vcardModel, QQmlEngine::CppOwnership); + engine->setObjectOwnership(mVcardModel, QQmlEngine::JavaScriptOwnership); + + qInfo() << QStringLiteral("Set vcard on contact:") << this << vcardModel; + qInfo() << QStringLiteral("Remove vcard on contact:") << this << mVcardModel; + + mLinphoneFriend->setVcard(vcardModel->mVcard); + mVcardModel = vcardModel; +} diff --git a/linphone-desktop/src/components/contact/ContactModel.hpp b/linphone-desktop/src/components/contact/ContactModel.hpp index 0e5059773..10db0f7a6 100644 --- a/linphone-desktop/src/components/contact/ContactModel.hpp +++ b/linphone-desktop/src/components/contact/ContactModel.hpp @@ -33,29 +33,30 @@ class ContactModel : public QObject { Q_PROPERTY(Presence::PresenceStatus presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged); Q_PROPERTY(Presence::PresenceLevel presenceLevel READ getPresenceLevel NOTIFY presenceLevelChanged); - Q_PROPERTY(VcardModel * vcard READ getVcardModelPtr NOTIFY contactUpdated); + Q_PROPERTY(VcardModel * vcard READ getVcardModel WRITE setVcardModel NOTIFY contactUpdated); + // Grant access to `mLinphoneFriend`. friend class ContactsListModel; friend class ContactsListProxyModel; friend class SmartSearchBarModel; public: ContactModel (QObject *parent, std::shared_ptr linphoneFriend); - ContactModel (QObject *parent, VcardModel *vcard); + ContactModel (QObject *parent, VcardModel *vcardModel); ~ContactModel () = default; - std::shared_ptr getVcardModel () const { - return mVcard; - } - void refreshPresence (); Q_INVOKABLE void startEdit (); Q_INVOKABLE void endEdit (); Q_INVOKABLE void abortEdit (); + VcardModel *getVcardModel () const; + void setVcardModel (VcardModel *vcardModel); + signals: void contactUpdated (); + void presenceStatusChanged (Presence::PresenceStatus status); void presenceLevelChanged (Presence::PresenceLevel level); void sipAddressAdded (const QString &sipAddress); @@ -65,13 +66,9 @@ private: Presence::PresenceStatus getPresenceStatus () const; Presence::PresenceLevel getPresenceLevel () const; - VcardModel *getVcardModelPtr () const { - return mVcard.get(); - } - QVariantList mOldSipAddresses; - std::shared_ptr mVcard; + VcardModel *mVcardModel; std::shared_ptr mLinphoneFriend; }; diff --git a/linphone-desktop/src/components/contact/VcardModel.cpp b/linphone-desktop/src/components/contact/VcardModel.cpp index c7bb24417..68a18b35a 100644 --- a/linphone-desktop/src/components/contact/VcardModel.cpp +++ b/linphone-desktop/src/components/contact/VcardModel.cpp @@ -71,6 +71,8 @@ inline shared_ptr findBelCardPhoto (const list vcard) : mVcard(vcard) {} + VcardModel::~VcardModel () { // If it's a detached Vcard, the linked photo must be destroyed from fs. if (App::getInstance()->getEngine()->objectOwnership(this) != QQmlEngine::CppOwnership) { @@ -87,7 +89,16 @@ VcardModel::~VcardModel () { if (!QFile::remove(imagePath)) qWarning() << QStringLiteral("Unable to remove `%1`.").arg(imagePath); - } + + qInfo() << QStringLiteral("Destroy detached vcard:") << this; + } else + qInfo() << QStringLiteral("Destroy attached vcard:") << this; +} + +// ----------------------------------------------------------------------------- + +VcardModel *VcardModel::clone () const { + return new VcardModel(mVcard->clone()); } // ----------------------------------------------------------------------------- @@ -113,7 +124,7 @@ QString VcardModel::getAvatar () const { // No path found. if (!photo) - return ""; + return QStringLiteral(""); // Returns right path. return QStringLiteral("image://%1/%2").arg(AvatarProvider::PROVIDER_ID).arg( diff --git a/linphone-desktop/src/components/contact/VcardModel.hpp b/linphone-desktop/src/components/contact/VcardModel.hpp index 93a0e175f..637e59c63 100644 --- a/linphone-desktop/src/components/contact/VcardModel.hpp +++ b/linphone-desktop/src/components/contact/VcardModel.hpp @@ -29,7 +29,7 @@ // ============================================================================= class VcardModel : public QObject { - friend class ContactModel; + friend class ContactModel; // Grant access to `mVcard`. Q_OBJECT; @@ -42,13 +42,15 @@ class VcardModel : public QObject { Q_PROPERTY(QVariantList urls READ getUrls NOTIFY vcardUpdated); public: - VcardModel (std::shared_ptr vcard) : mVcard(vcard) {} + VcardModel (std::shared_ptr vcard); ~VcardModel (); QString getUsername () const; QVariantList getSipAddresses () const; + Q_INVOKABLE VcardModel *clone () const; + Q_INVOKABLE bool addSipAddress (const QString &sipAddress); Q_INVOKABLE void removeSipAddress (const QString &sipAddress); Q_INVOKABLE bool updateSipAddress (const QString &oldSipAddress, const QString &sipAddress); diff --git a/linphone-desktop/ui/modules/Common/Form/ListForm.qml b/linphone-desktop/ui/modules/Common/Form/ListForm.qml index 83670af95..d71d22120 100644 --- a/linphone-desktop/ui/modules/Common/Form/ListForm.qml +++ b/linphone-desktop/ui/modules/Common/Form/ListForm.qml @@ -16,7 +16,6 @@ RowLayout { property alias title: text.text property bool readOnly: false property int inputMethodHints - property var defaultData: [] property var minValues readonly property int count: values.count @@ -193,15 +192,5 @@ RowLayout { } model: ListModel {} - - // ------------------------------------------------------------------------- - // Init values. - // ------------------------------------------------------------------------- - - Component.onCompleted: { - if (defaultData) { - setData(defaultData) - } - } } } diff --git a/linphone-desktop/ui/scripts/Utils/utils.js b/linphone-desktop/ui/scripts/Utils/utils.js index af8f1249c..5673dddd7 100644 --- a/linphone-desktop/ui/scripts/Utils/utils.js +++ b/linphone-desktop/ui/scripts/Utils/utils.js @@ -332,7 +332,7 @@ function extractProperties (obj, pattern) { // ----------------------------------------------------------------------------- -// Returns an array from a `object` or `array` argument. +// Returns an array from an `object` or `array` argument. function ensureArray (obj) { if (isArray(obj)) { return obj @@ -502,18 +502,6 @@ function includes (obj, value, startIndex) { // ----------------------------------------------------------------------------- -function invert (obj) { - var out = {} - - for (var key in obj) { - out[key] = obj[key] - } - - return out -} - -// ----------------------------------------------------------------------------- - function isArray (array) { return (array instanceof Array) } diff --git a/linphone-desktop/ui/views/App/Main/ContactEdit.js b/linphone-desktop/ui/views/App/Main/ContactEdit.js index bebb0aa55..768295db2 100644 --- a/linphone-desktop/ui/views/App/Main/ContactEdit.js +++ b/linphone-desktop/ui/views/App/Main/ContactEdit.js @@ -16,31 +16,37 @@ function handleCreation () { if (!contact) { var vcard = Linphone.CoreManager.createDetachedVcardModel() - contactEdit._vcard = vcard if (sipAddress && sipAddress.length > 0) { vcard.addSipAddress(sipAddress) } + contactEdit._vcard = vcard contactEdit._edition = true } else { - contactEdit._vcard = contact.vcard } } -function handleDestruction () { - var contact = contactEdit._contact - - if (contactEdit._edition && contact) { - contact.abortEdit() +function handleVcardChanged (vcard) { + if (!vcard) { + vcard = {} } + + addresses.setData(vcard.sipAddresses) + companies.setData(vcard.companies) + emails.setData(vcard.emails) + urls.setData(vcard.urls) } // ----------------------------------------------------------------------------- function editContact () { - contactEdit._contact.startEdit() + var contact = contactEdit._contact + + contact.startEdit() + + contactEdit._vcard = contact.vcard.clone() contactEdit._edition = true window.lockView({ @@ -64,12 +70,14 @@ function removeContact () { function save () { var contact = contactEdit._contact + var vcard = contactEdit._vcard if (contact) { + contact.vcard = vcard contact.endEdit() window.unlockView() } else { - contactEdit._contact = Linphone.ContactsListModel.addContact(contactEdit._vcard) + contactEdit._contact = Linphone.ContactsListModel.addContact(vcard) } contactEdit._edition = false @@ -79,9 +87,11 @@ function cancel () { var contact = contactEdit._contact if (contact) { + contactEdit._vcard = contact.vcard contact.abortEdit() - contactEdit._edition = false window.unlockView() + + contactEdit._edition = false } else { window.setView('Contacts') } @@ -104,51 +114,41 @@ function setUsername (username) { // ----------------------------------------------------------------------------- -function handleSipAddressChanged (sipAddresses, index, defaultValue, newValue) { +function handleValueChanged (fields, index, defaultValue, newValue, add, update) { if (newValue === defaultValue) { return } var vcard = contactEdit._vcard var soFarSoGood = (defaultValue.length === 0) - ? vcard.addSipAddress(newValue) - : vcard.updateSipAddress(defaultValue, newValue) + ? vcard[add](newValue) + : vcard[update](defaultValue, newValue) - sipAddresses.setInvalid(index, !soFarSoGood) + fields.setInvalid(index, !soFarSoGood) } -function handleCompanyChanged (companies, index, defaultValue, newValue) { - var vcard = contactEdit._vcard - var soFarSoGood = (defaultValue.length === 0) - ? vcard.addCompany(newValue) - : vcard.updateCompany(defaultValue, newValue) - - companies.setInvalid(index, !soFarSoGood) +function handleSipAddressChanged () { + var args = Array.prototype.slice.call(arguments) + args.push('addSipAddress', 'updateSipAddress') + handleValueChanged.apply(this, args) } -function handleEmailChanged (emails, index, defaultValue, newValue) { - var vcard = contactEdit._vcard - var soFarSoGood = (defaultValue.length === 0) - ? vcard.addEmail(newValue) - : vcard.updateEmail(defaultValue, newValue) - - emails.setInvalid(index, !soFarSoGood) +function handleCompanyChanged () { + var args = Array.prototype.slice.call(arguments) + args.push('addCompany', 'updateCompany') + handleValueChanged.apply(this, args) } -function handleUrlChanged (urls, index, defaultValue, newValue) { - var url = Utils.extractFirstUri(newValue) - if (url === defaultValue) { - return - } +function handleEmailChanged () { + var args = Array.prototype.slice.call(arguments) + args.push('addEmail', 'updateEmail') + handleValueChanged.apply(this, args) +} - var vcard = contactEdit._vcard - var soFarSoGood = url && ( - defaultValue.length === 0 - ? vcard.addUrl(newValue) - : vcard.updateUrl(defaultValue, newValue) - ) - - urls.setInvalid(index, !soFarSoGood) +function handleUrlChanged () { + var args = Array.prototype.slice.call(arguments) + args.push('addUrl', 'updateUrl') + handleValueChanged.apply(this, args) } // ----------------------------------------------------------------------------- diff --git a/linphone-desktop/ui/views/App/Main/ContactEdit.qml b/linphone-desktop/ui/views/App/Main/ContactEdit.qml index 5a57278f7..4d482b769 100644 --- a/linphone-desktop/ui/views/App/Main/ContactEdit.qml +++ b/linphone-desktop/ui/views/App/Main/ContactEdit.qml @@ -18,6 +18,8 @@ ColumnLayout { property string sipAddress + readonly property alias vcard: contactEdit._vcard + property bool _edition: false property var _contact property var _vcard @@ -27,10 +29,20 @@ ColumnLayout { spacing: 0 Component.onCompleted: Logic.handleCreation() - Component.onDestruction: Logic.handleDestruction() + + onVcardChanged: Logic.handleVcardChanged(vcard) // --------------------------------------------------------------------------- + Loader { + active: contactEdit._contact != null + sourceComponent: Connections { + target: contactEdit._contact + + onContactUpdated: Logic.handleVcardChanged(contactEdit._contact.vcard) + } + } + FileDialog { id: avatarChooser @@ -163,163 +175,140 @@ ColumnLayout { color: ContactEditStyle.content.color - Loader { + Flickable { + id: flick + + ScrollBar.vertical: ForceScrollBar {} + anchors.fill: parent + boundsBehavior: Flickable.StopAtBounds + clip: true + contentHeight: infoList.height + contentWidth: width - ScrollBar.vertical.width + flickableDirection: Flickable.VerticalFlick - active: _vcard != null - sourceComponent: Flickable { - id: flick + // ----------------------------------------------------------------------- - ScrollBar.vertical: ForceScrollBar {} + ColumnLayout { + id: infoList - boundsBehavior: Flickable.StopAtBounds - clip: true - contentHeight: infoList.height - contentWidth: width - ScrollBar.vertical.width - flickableDirection: Flickable.VerticalFlick + width: flick.contentWidth - // --------------------------------------------------------------------- + ListForm { + id: addresses - Connections { - target: _vcard + Layout.leftMargin: ContactEditStyle.values.leftMargin + Layout.rightMargin: ContactEditStyle.values.rightMargin + Layout.topMargin: ContactEditStyle.values.topMargin - onVcardUpdated: { - addresses.setData(_vcard.sipAddresses) - companies.setData(_vcard.companies) - emails.setData(_vcard.emails) - urls.setData(_vcard.urls) - } + minValues: _contact ? 1 : 0 + placeholder: qsTr('sipAccountsPlaceholder') + readOnly: !_edition + title: qsTr('sipAccounts') + + onChanged: Logic.handleSipAddressChanged(addresses, index, defaultValue, newValue) + onRemoved: _vcard.removeSipAddress(value) + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: ContactEditStyle.values.separator.height + color: ContactEditStyle.values.separator.color + } + + ListForm { + id: companies + + Layout.leftMargin: ContactEditStyle.values.leftMargin + Layout.rightMargin: ContactEditStyle.values.rightMargin + + placeholder: qsTr('companiesPlaceholder') + readOnly: !_edition + title: qsTr('companies') + + onChanged: Logic.handleCompanyChanged(companies, index, defaultValue, newValue) + onRemoved: _vcard.removeCompany(value) + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: ContactEditStyle.values.separator.height + color: ContactEditStyle.values.separator.color + } + + ListForm { + id: emails + + Layout.leftMargin: ContactEditStyle.values.leftMargin + Layout.rightMargin: ContactEditStyle.values.rightMargin + + placeholder: qsTr('emailsPlaceholder') + readOnly: !_edition + title: qsTr('emails') + + onChanged: Logic.handleEmailChanged(emails, index, defaultValue, newValue) + onRemoved: _vcard.removeEmail(value) + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: ContactEditStyle.values.separator.height + color: ContactEditStyle.values.separator.color + } + + ListForm { + id: urls + + Layout.leftMargin: ContactEditStyle.values.leftMargin + Layout.rightMargin: ContactEditStyle.values.rightMargin + + placeholder: qsTr('webSitesPlaceholder') + readOnly: !_edition + title: qsTr('webSites') + + onChanged: Logic.handleUrlChanged(urls, index, defaultValue, newValue) + onRemoved: _vcard.removeUrl(value) + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: ContactEditStyle.values.separator.height + color: ContactEditStyle.values.separator.color + } + + StaticListForm { + Layout.leftMargin: ContactEditStyle.values.leftMargin + Layout.rightMargin: ContactEditStyle.values.rightMargin + + fields: Logic.buildAddressFields() + + readOnly: !_edition + title: qsTr('address') + + onChanged: Logic.handleAddressChanged(index, value) } + // --------------------------------------------------------------------- + // Edition buttons. // --------------------------------------------------------------------- - ColumnLayout { - id: infoList + Row { + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: ContactEditStyle.values.bottomMargin + Layout.topMargin: ContactEditStyle.buttons.topMargin - width: flick.contentWidth + spacing: ContactEditStyle.buttons.spacing + visible: _edition - ListForm { - id: addresses - - Layout.leftMargin: ContactEditStyle.values.leftMargin - Layout.rightMargin: ContactEditStyle.values.rightMargin - Layout.topMargin: ContactEditStyle.values.topMargin - - defaultData: _vcard.sipAddresses - minValues: _contact ? 1 : 0 - placeholder: qsTr('sipAccountsPlaceholder') - readOnly: !_edition - title: qsTr('sipAccounts') - - onChanged: Logic.handleSipAddressChanged(addresses, index, defaultValue, newValue) - onRemoved: _vcard.removeSipAddress(value) + TextButtonA { + text: qsTr('cancel') + onClicked: Logic.cancel() } - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: ContactEditStyle.values.separator.height - color: ContactEditStyle.values.separator.color - } - - ListForm { - id: companies - - Layout.leftMargin: ContactEditStyle.values.leftMargin - Layout.rightMargin: ContactEditStyle.values.rightMargin - - defaultData: _vcard.companies - placeholder: qsTr('companiesPlaceholder') - readOnly: !_edition - title: qsTr('companies') - - onChanged: Logic.handleCompanyChanged(companies, index, defaultValue, newValue) - onRemoved: _vcard.removeCompany(value) - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: ContactEditStyle.values.separator.height - color: ContactEditStyle.values.separator.color - } - - ListForm { - id: emails - - Layout.leftMargin: ContactEditStyle.values.leftMargin - Layout.rightMargin: ContactEditStyle.values.rightMargin - - defaultData: _vcard.emails - inputMethodHints: Qt.ImhEmailCharactersOnly - placeholder: qsTr('emailsPlaceholder') - readOnly: !_edition - title: qsTr('emails') - - onChanged: Logic.handleEmailChanged(emails, index, defaultValue, newValue) - onRemoved: _vcard.removeEmail(value) - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: ContactEditStyle.values.separator.height - color: ContactEditStyle.values.separator.color - } - - ListForm { - id: urls - - Layout.leftMargin: ContactEditStyle.values.leftMargin - Layout.rightMargin: ContactEditStyle.values.rightMargin - - defaultData: _vcard.urls - inputMethodHints: Qt.ImhUrlCharactersOnly - placeholder: qsTr('webSitesPlaceholder') - readOnly: !_edition - title: qsTr('webSites') - - onChanged: Logic.handleUrlChanged(urls, index, defaultValue, newValue) - onRemoved: _vcard.removeUrl(value) - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: ContactEditStyle.values.separator.height - color: ContactEditStyle.values.separator.color - } - - StaticListForm { - Layout.leftMargin: ContactEditStyle.values.leftMargin - Layout.rightMargin: ContactEditStyle.values.rightMargin - - fields: Logic.buildAddressFields() - - readOnly: !_edition - title: qsTr('address') - - onChanged: Logic.handleAddressChanged(index, value) - } - - // ------------------------------------------------------------------- - // Edition buttons. - // ------------------------------------------------------------------- - - Row { - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: ContactEditStyle.values.bottomMargin - Layout.topMargin: ContactEditStyle.buttons.topMargin - - spacing: ContactEditStyle.buttons.spacing - visible: _edition - - TextButtonA { - text: qsTr('cancel') - onClicked: Logic.cancel() - } - - TextButtonB { - enabled: usernameInput.text.length > 0 && _vcard.sipAddresses.length > 0 - text: qsTr('save') - onClicked: Logic.save() - } + TextButtonB { + enabled: usernameInput.text.length > 0 && _vcard.sipAddresses.length > 0 + text: qsTr('save') + onClicked: Logic.save() } } }