summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp3
-rw-r--r--Swift/Controllers/MainController.cpp5
-rw-r--r--Swift/Controllers/MainController.h2
-rw-r--r--Swift/Controllers/ProfileController.cpp1
-rw-r--r--Swift/Controllers/SConscript1
-rw-r--r--Swift/Controllers/ShowProfileController.cpp76
-rw-r--r--Swift/Controllers/ShowProfileController.h36
-rw-r--r--Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h25
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/ProfileWindow.h5
-rw-r--r--Swift/QtUI/QtAvatarWidget.cpp3
-rw-r--r--Swift/QtUI/QtAvatarWidget.h10
-rw-r--r--Swift/QtUI/QtProfileWindow.cpp158
-rw-r--r--Swift/QtUI/QtProfileWindow.h77
-rw-r--r--Swift/QtUI/QtProfileWindow.ui85
-rw-r--r--Swift/QtUI/QtSwiftUtil.h2
-rw-r--r--Swift/QtUI/QtVCardWidget/QtCloseButton.cpp55
-rw-r--r--Swift/QtUI/QtVCardWidget/QtCloseButton.h28
-rw-r--r--Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.cpp42
-rw-r--r--Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.h27
-rw-r--r--Swift/QtUI/QtVCardWidget/QtResizableLineEdit.cpp49
-rw-r--r--Swift/QtUI/QtVCardWidget/QtResizableLineEdit.h33
-rw-r--r--Swift/QtUI/QtVCardWidget/QtTagComboBox.cpp102
-rw-r--r--Swift/QtUI/QtVCardWidget/QtTagComboBox.h46
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardAddressField.cpp165
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardAddressField.h60
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardAddressLabelField.cpp97
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardAddressLabelField.h49
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardBirthdayField.cpp61
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardBirthdayField.h43
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardDescriptionField.cpp64
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardDescriptionField.h42
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h52
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardGeneralField.cpp115
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardGeneralField.h77
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardHomeWork.cpp40
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardHomeWork.h31
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardInternetEMailField.cpp80
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardInternetEMailField.h43
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardJIDField.cpp71
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardJIDField.h42
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardOrganizationField.cpp129
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardOrganizationField.h50
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.cpp176
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.h73
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.ui251
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardRoleField.cpp50
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardRoleField.h41
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardTelephoneField.cpp100
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardTelephoneField.h42
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardTitleField.cpp51
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardTitleField.h41
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardURLField.cpp68
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardURLField.h42
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp368
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardWidget.h60
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardWidget.ui137
-rw-r--r--Swift/QtUI/Roster/QtOccupantListWidget.cpp1
-rw-r--r--Swift/QtUI/Roster/QtRosterWidget.cpp5
-rw-r--r--Swift/QtUI/SConscript30
-rw-r--r--Swift/QtUI/Swift.qrc2
-rw-r--r--Swift/resources/icons/star-checked2.pngbin0 -> 1346 bytes
-rw-r--r--Swift/resources/icons/star-checked2.svg88
-rw-r--r--Swift/resources/icons/star-unchecked2.pngbin0 -> 894 bytes
-rw-r--r--Swift/resources/icons/star-unchecked2.svg88
-rw-r--r--Swiften/Elements/VCard.h193
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp73
-rw-r--r--Swiften/Parser/PayloadParsers/VCardParser.cpp166
-rw-r--r--Swiften/Parser/PayloadParsers/VCardParser.h4
-rw-r--r--Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp80
-rw-r--r--Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp206
71 files changed, 4452 insertions, 168 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index 937116f..a61b5f0 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -24,6 +24,7 @@
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h>
+#include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swiften/Avatars/AvatarManager.h>
@@ -150,6 +151,7 @@ void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item
if (muc_->getOccupant(item->getJID().getResource()).getRealJID()) {
actions.push_back(ChatWindow::AddContact);
}
+ actions.push_back(ChatWindow::ShowProfile);
}
chatWindow_->setAvailableOccupantActions(actions);
}
@@ -168,6 +170,7 @@ void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction a
case ChatWindow::MakeParticipant: muc_->changeOccupantRole(mucJID, MUCOccupant::Participant);break;
case ChatWindow::MakeVisitor: muc_->changeOccupantRole(mucJID, MUCOccupant::Visitor);break;
case ChatWindow::AddContact: if (occupant.getRealJID()) events_->send(boost::make_shared<RequestAddUserDialogUIEvent>(realJID, occupant.getNick()));break;
+ case ChatWindow::ShowProfile: events_->send(boost::make_shared<ShowProfileForRosterItemUIEvent>(mucJID));break;
}
}
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index bb74ed7..87ec94d 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -75,6 +75,7 @@
#include "Swift/Controllers/Storages/CertificateStorageTrustChecker.h"
#include "Swiften/Network/NetworkFactories.h"
#include <Swift/Controllers/ProfileController.h>
+#include <Swift/Controllers/ShowProfileController.h>
#include <Swift/Controllers/ContactEditController.h>
#include <Swift/Controllers/XMPPURIController.h>
#include "Swift/Controllers/AdHocManager.h"
@@ -129,6 +130,7 @@ MainController::MainController(
historyViewController_ = NULL;
eventWindowController_ = NULL;
profileController_ = NULL;
+ showProfileController_ = NULL;
contactEditController_ = NULL;
userSearchControllerChat_ = NULL;
userSearchControllerAdd_ = NULL;
@@ -239,6 +241,8 @@ void MainController::resetClient() {
contactEditController_ = NULL;
delete profileController_;
profileController_ = NULL;
+ delete showProfileController_;
+ showProfileController_ = NULL;
delete eventWindowController_;
eventWindowController_ = NULL;
delete chatsManager_;
@@ -311,6 +315,7 @@ void MainController::handleConnected() {
myStatusLooksOnline_ = true;
if (freshLogin) {
profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
+ showProfileController_ = new ShowProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
srand(static_cast<unsigned int>(time(NULL)));
int randomPort = 10000 + rand() % 10000;
client_->getFileTransferManager()->startListeningOnPort(randomPort);
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index fc8d518..4f37e12 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -43,6 +43,7 @@ namespace Swift {
class MUCController;
class Notifier;
class ProfileController;
+ class ShowProfileController;
class ContactEditController;
class TogglableNotifier;
class PresenceNotifier;
@@ -155,6 +156,7 @@ namespace Swift {
FileTransferListController* fileTransferListController_;
ChatsManager* chatsManager_;
ProfileController* profileController_;
+ ShowProfileController* showProfileController_;
ContactEditController* contactEditController_;
JID jid_;
JID boundJID_;
diff --git a/Swift/Controllers/ProfileController.cpp b/Swift/Controllers/ProfileController.cpp
index 101e283..e641988 100644
--- a/Swift/Controllers/ProfileController.cpp
+++ b/Swift/Controllers/ProfileController.cpp
@@ -37,6 +37,7 @@ void ProfileController::handleUIEvent(UIEvent::ref event) {
if (!profileWindow) {
profileWindow = profileWindowFactory->createProfileWindow();
+ profileWindow->setEditable(true);
profileWindow->onVCardChangeRequest.connect(boost::bind(&ProfileController::handleVCardChangeRequest, this, _1));
vcardManager->onOwnVCardChanged.connect(boost::bind(&ProfileController::handleOwnVCardChanged, this, _1));
}
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index cd88dd9..26b9334 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -30,6 +30,7 @@ if env["SCONS_STAGE"] == "build" :
"Chat/UserSearchController.cpp",
"MainController.cpp",
"ProfileController.cpp",
+ "ShowProfileController.cpp",
"ContactEditController.cpp",
"FileTransfer/FileTransferController.cpp",
"FileTransfer/FileTransferOverview.cpp",
diff --git a/Swift/Controllers/ShowProfileController.cpp b/Swift/Controllers/ShowProfileController.cpp
new file mode 100644
index 0000000..ee0854b
--- /dev/null
+++ b/Swift/Controllers/ShowProfileController.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "ShowProfileController.h"
+
+#include <boost/bind.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/VCards/VCardManager.h>
+
+#include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ProfileWindowFactory.h>
+
+namespace Swift {
+
+ShowProfileController::ShowProfileController(VCardManager* vcardManager, ProfileWindowFactory* profileWindowFactory, UIEventStream* uiEventStream) : vcardManager(vcardManager), profileWindowFactory(profileWindowFactory), uiEventStream(uiEventStream) {
+ uiEventStream->onUIEvent.connect(boost::bind(&ShowProfileController::handleUIEvent, this, _1));
+ vcardManager->onVCardChanged.connect(boost::bind(&ShowProfileController::handleVCardChanged, this, _1, _2));
+}
+
+ShowProfileController::~ShowProfileController() {
+ typedef std::pair<JID, ProfileWindow*> JIDProfileWindowPair;
+ foreach(const JIDProfileWindowPair& jidWndPair, openedProfileWindows) {
+ jidWndPair.second->onWindowClosed.disconnect(boost::bind(&ShowProfileController::handleProfileWindowClosed, this, _1));
+ delete jidWndPair.second;
+ }
+
+ vcardManager->onVCardChanged.disconnect(boost::bind(&ShowProfileController::handleVCardChanged, this, _1, _2));
+ uiEventStream->onUIEvent.disconnect(boost::bind(&ShowProfileController::handleUIEvent, this, _1));
+}
+
+void ShowProfileController::handleUIEvent(UIEvent::ref event) {
+ ShowProfileForRosterItemUIEvent::ref showProfileEvent = boost::dynamic_pointer_cast<ShowProfileForRosterItemUIEvent>(event);
+ if (!showProfileEvent) {
+ return;
+ }
+
+ if (openedProfileWindows.find(showProfileEvent->getJID()) == openedProfileWindows.end()) {
+ ProfileWindow* newProfileWindow = profileWindowFactory->createProfileWindow();
+ newProfileWindow->setJID(showProfileEvent->getJID());
+ newProfileWindow->onWindowClosed.connect(boost::bind(&ShowProfileController::handleProfileWindowClosed, this, _1));
+ openedProfileWindows[showProfileEvent->getJID()] = newProfileWindow;
+ VCard::ref vcard = vcardManager->getVCardAndRequestWhenNeeded(showProfileEvent->getJID());
+ if (vcard) {
+ newProfileWindow->setVCard(vcard);
+ } else {
+ newProfileWindow->setProcessing(true);
+ }
+ newProfileWindow->show();
+ } else {
+ openedProfileWindows[showProfileEvent->getJID()]->show();
+ }
+}
+
+void ShowProfileController::handleVCardChanged(const JID& jid, VCard::ref vcard) {
+ if (openedProfileWindows.find(jid) == openedProfileWindows.end()) {
+ return;
+ }
+
+ ProfileWindow* profileWindow = openedProfileWindows[jid];
+ profileWindow->setVCard(vcard);
+ profileWindow->setProcessing(false);
+ profileWindow->show();
+}
+
+void ShowProfileController::handleProfileWindowClosed(const JID& profileJid) {
+ ProfileWindow* profileWindow = openedProfileWindows[profileJid];
+ openedProfileWindows.erase(profileJid);
+ delete profileWindow;
+}
+
+}
diff --git a/Swift/Controllers/ShowProfileController.h b/Swift/Controllers/ShowProfileController.h
new file mode 100644
index 0000000..5646f5e
--- /dev/null
+++ b/Swift/Controllers/ShowProfileController.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/VCard.h>
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+ class VCardManager;
+ class ProfileWindow;
+ class ProfileWindowFactory;
+ class UIEventStream;
+
+ class ShowProfileController {
+ public:
+ ShowProfileController(VCardManager* vcardManager, ProfileWindowFactory* profileWindowFactory, UIEventStream* uiEventStream);
+ ~ShowProfileController();
+
+ private:
+ void handleUIEvent(UIEvent::ref event);
+ void handleVCardChanged(const JID&, VCard::ref);
+ void handleProfileWindowClosed(const JID& profileJid);
+
+ private:
+ VCardManager* vcardManager;
+ ProfileWindowFactory* profileWindowFactory;
+ UIEventStream* uiEventStream;
+ std::map<JID, ProfileWindow*> openedProfileWindows;
+ };
+}
diff --git a/Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h b/Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h
new file mode 100644
index 0000000..4a603ea
--- /dev/null
+++ b/Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/JID/JID.h>
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+
+class ShowProfileForRosterItemUIEvent : public UIEvent {
+ public:
+ typedef boost::shared_ptr<ShowProfileForRosterItemUIEvent> ref;
+ public:
+ ShowProfileForRosterItemUIEvent(const JID& jid) : jid_(jid) {}
+ virtual ~ShowProfileForRosterItemUIEvent() {}
+ JID getJID() const {return jid_;}
+ private:
+ JID jid_;
+};
+
+}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 252e43d..d6b3656 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -35,7 +35,7 @@ namespace Swift {
enum AckState {Pending, Received, Failed};
enum ReceiptState {ReceiptRequested, ReceiptReceived};
enum Tristate {Yes, No, Maybe};
- enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact};
+ enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact, ShowProfile};
enum RoomAction {ChangeSubject, Configure, Affiliations, Destroy, Invite};
enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed};
enum WhiteboardSessionState {WhiteboardAccepted, WhiteboardTerminated, WhiteboardRejected};
diff --git a/Swift/Controllers/UIInterfaces/ProfileWindow.h b/Swift/Controllers/UIInterfaces/ProfileWindow.h
index 2ed1bc1..0ce2ccf 100644
--- a/Swift/Controllers/UIInterfaces/ProfileWindow.h
+++ b/Swift/Controllers/UIInterfaces/ProfileWindow.h
@@ -12,19 +12,24 @@
#include <Swiften/Elements/VCard.h>
namespace Swift {
+ class JID;
+
class ProfileWindow {
public:
virtual ~ProfileWindow() {}
+ virtual void setJID(const JID& jid) = 0;
virtual void setVCard(VCard::ref vcard) = 0;
virtual void setEnabled(bool b) = 0;
virtual void setProcessing(bool b) = 0;
virtual void setError(const std::string&) = 0;
+ virtual void setEditable(bool b) = 0;
virtual void show() = 0;
virtual void hide() = 0;
boost::signal<void (VCard::ref)> onVCardChangeRequest;
+ boost::signal<void (const JID&)> onWindowClosed;
};
}
diff --git a/Swift/QtUI/QtAvatarWidget.cpp b/Swift/QtUI/QtAvatarWidget.cpp
index f0bdf3c..ae9559a 100644
--- a/Swift/QtUI/QtAvatarWidget.cpp
+++ b/Swift/QtUI/QtAvatarWidget.cpp
@@ -68,6 +68,9 @@ void QtAvatarWidget::setAvatar(const ByteArray& data, const std::string& type) {
}
void QtAvatarWidget::mousePressEvent(QMouseEvent* event) {
+ if (!editable) {
+ return;
+ }
QMenu menu;
QAction* selectPicture = new QAction(tr("Select picture ..."), this);
diff --git a/Swift/QtUI/QtAvatarWidget.h b/Swift/QtUI/QtAvatarWidget.h
index 8830d82..f4ac4cf 100644
--- a/Swift/QtUI/QtAvatarWidget.h
+++ b/Swift/QtUI/QtAvatarWidget.h
@@ -15,6 +15,7 @@ class QLabel;
namespace Swift {
class QtAvatarWidget : public QWidget {
Q_OBJECT
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable)
public:
QtAvatarWidget(QWidget* parent);
@@ -28,9 +29,18 @@ namespace Swift {
return type;
}
+ void setEditable(bool b) {
+ editable = b;
+ }
+
+ bool isEditable() const {
+ return editable;
+ }
+
void mousePressEvent(QMouseEvent* event);
private:
+ bool editable;
ByteArray data;
std::string type;
QLabel* label;
diff --git a/Swift/QtUI/QtProfileWindow.cpp b/Swift/QtUI/QtProfileWindow.cpp
index 0faa78f..ccc6ae9 100644
--- a/Swift/QtUI/QtProfileWindow.cpp
+++ b/Swift/QtUI/QtProfileWindow.cpp
@@ -4,97 +4,80 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
#include "QtProfileWindow.h"
+#include "ui_QtProfileWindow.h"
-#include <QImage>
-#include <QPixmap>
-#include <QSizePolicy>
-#include <QGridLayout>
-#include <QLabel>
-#include <QLineEdit>
-#include <QPushButton>
+#include <QCloseEvent>
#include <QMovie>
+#include <QShortcut>
+#include <QTextDocument>
-#include "QtSwiftUtil.h"
-#include "QtAvatarWidget.h"
+#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
-QtProfileWindow::QtProfileWindow() {
- setWindowTitle(tr("Edit Profile"));
-
- QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
- sizePolicy.setHorizontalStretch(0);
- sizePolicy.setVerticalStretch(0);
- sizePolicy.setHeightForWidth(this->sizePolicy().hasHeightForWidth());
- setSizePolicy(sizePolicy);
-
- QVBoxLayout* layout = new QVBoxLayout(this);
- layout->setContentsMargins(10, 10, 10, 10);
-
- QHBoxLayout* topLayout = new QHBoxLayout();
-
- avatar = new QtAvatarWidget(this);
- topLayout->addWidget(avatar);
-
- QVBoxLayout* fieldsLayout = new QVBoxLayout();
-
- QHBoxLayout* horizontalLayout_2 = new QHBoxLayout();
- nicknameLabel = new QLabel(tr("Nickname:"), this);
- horizontalLayout_2->addWidget(nicknameLabel);
- nickname = new QLineEdit(this);
- horizontalLayout_2->addWidget(nickname);
-
- fieldsLayout->addLayout(horizontalLayout_2);
-
- errorLabel = new QLabel(this);
- errorLabel->setAlignment(Qt::AlignHCenter);
- fieldsLayout->addWidget(errorLabel);
-
- fieldsLayout->addItem(new QSpacerItem(198, 17, QSizePolicy::Minimum, QSizePolicy::Expanding));
- topLayout->addLayout(fieldsLayout);
-
- layout->addLayout(topLayout);
-
- QHBoxLayout* horizontalLayout = new QHBoxLayout();
- horizontalLayout->setContentsMargins(0, 0, 0, 0);
- horizontalLayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
-
- throbberLabel = new QLabel(this);
- throbberLabel->setMovie(new QMovie(":/icons/throbber.gif", QByteArray(), this));
- horizontalLayout->addWidget(throbberLabel);
-
- saveButton = new QPushButton(tr("Save"), this);
- saveButton->setDefault( true );
- connect(saveButton, SIGNAL(clicked()), SLOT(handleSave()));
- horizontalLayout->addWidget(saveButton);
+QtProfileWindow::QtProfileWindow(QWidget* parent) :
+ QWidget(parent),
+ ui(new Ui::QtProfileWindow) {
+ ui->setupUi(this);
+ new QShortcut(QKeySequence::Close, this, SLOT(close()));
+ ui->throbberLabel->setMovie(new QMovie(":/icons/throbber.gif", QByteArray(), this));
+ connect(ui->savePushButton, SIGNAL(clicked()), SLOT(handleSave()));
+ setEditable(false);
+}
- fieldsLayout->addLayout(horizontalLayout);
+QtProfileWindow::~QtProfileWindow() {
+ delete ui;
+}
- resize(360, 120);
+void QtProfileWindow::setJID(const JID& jid) {
+ this->jid = jid;
+ updateTitle();
}
-void QtProfileWindow::setVCard(Swift::VCard::ref vcard) {
- this->vcard = vcard;
- nickname->setText(P2QSTRING(vcard->getNickname()));
- avatar->setAvatar(vcard->getPhoto(), vcard->getPhotoType());
+void QtProfileWindow::setVCard(VCard::ref vcard) {
+ ui->vcard->setVCard(vcard);
}
void QtProfileWindow::setEnabled(bool b) {
- nickname->setEnabled(b);
- nicknameLabel->setEnabled(b);
- avatar->setEnabled(b);
- saveButton->setEnabled(b);
+ ui->vcard->setEnabled(b);
+ ui->savePushButton->setEnabled(b);
+}
+
+void QtProfileWindow::setEditable(bool b) {
+ if (b) {
+ ui->savePushButton->show();
+ ui->vcard->setEditable(true);
+ } else {
+ ui->savePushButton->hide();
+ ui->vcard->setEditable(false);
+ }
+ updateTitle();
}
void QtProfileWindow::setProcessing(bool processing) {
if (processing) {
- throbberLabel->movie()->start();
- throbberLabel->show();
+ ui->throbberLabel->movie()->start();
+ ui->throbberLabel->show();
+ }
+ else {
+ ui->throbberLabel->hide();
+ ui->throbberLabel->movie()->stop();
+ }
+}
+
+void QtProfileWindow::setError(const std::string& error) {
+ if (!error.empty()) {
+ ui->errorLabel->setText("<font color='red'>" + Qt::escape(P2QSTRING(error)) + "</font>");
}
else {
- throbberLabel->hide();
- throbberLabel->movie()->stop();
+ ui->errorLabel->setText("");
}
}
@@ -103,31 +86,30 @@ void QtProfileWindow::show() {
QWidget::activateWindow();
}
-void QtProfileWindow::hideEvent(QHideEvent* event) {
- QWidget::hideEvent(event);
-}
-
void QtProfileWindow::hide() {
QWidget::hide();
}
-void QtProfileWindow::handleSave() {
- assert(vcard);
- vcard->setNickname(Q2PSTRING(nickname->text()));
- vcard->setPhoto(avatar->getAvatarData());
- vcard->setPhotoType(avatar->getAvatarType());
- onVCardChangeRequest(vcard);
-}
-
-void QtProfileWindow::setError(const std::string& error) {
- if (!error.empty()) {
- errorLabel->setText("<font color='red'>" + P2QSTRING(error) + "</font>");
+void QtProfileWindow::updateTitle() {
+ QString jidString;
+ if (jid.isValid()) {
+ jidString = QString(" ( %1 )").arg(P2QSTRING(jid.toString()));
}
- else {
- errorLabel->setText("");
+
+ if (ui->vcard->isEditable()) {
+ setWindowTitle(tr("Edit Profile") + jidString);
+ } else {
+ setWindowTitle(tr("Show Profile") + jidString);
}
}
+void QtProfileWindow::closeEvent(QCloseEvent* event) {
+ onWindowClosed(jid);
+ event->accept();
+}
+void QtProfileWindow::handleSave() {
+ onVCardChangeRequest(ui->vcard->getVCard());
+}
}
diff --git a/Swift/QtUI/QtProfileWindow.h b/Swift/QtUI/QtProfileWindow.h
index edb9cce..1dbc0fb 100644
--- a/Swift/QtUI/QtProfileWindow.h
+++ b/Swift/QtUI/QtProfileWindow.h
@@ -4,45 +4,54 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
#pragma once
-#include <QWidget>
+#include <Swiften/JID/JID.h>
#include <Swift/Controllers/UIInterfaces/ProfileWindow.h>
-class QLabel;
-class QLineEdit;
-class QHBoxLayout;
-class QPushButton;
+#include <QWidget>
+
+namespace Ui {
+ class QtProfileWindow;
+}
namespace Swift {
- class QtAvatarWidget;
-
- class QtProfileWindow : public QWidget, public ProfileWindow {
- Q_OBJECT
- public:
- QtProfileWindow();
-
- void setVCard(Swift::VCard::ref);
- void setEnabled(bool);
- void setProcessing(bool);
- virtual void setError(const std::string&);
- void show();
- void hide();
-
- void hideEvent (QHideEvent* event);
-
- private slots:
- void handleSave();
-
- private:
- VCard::ref vcard;
- QtAvatarWidget* avatar;
- QLabel* nicknameLabel;
- QLineEdit* nickname;
- QLabel* throbberLabel;
- QLabel* errorLabel;
- QHBoxLayout* horizontalLayout;
- QPushButton* saveButton;
- };
+
+class QtProfileWindow : public QWidget, public ProfileWindow {
+ Q_OBJECT
+
+ public:
+ explicit QtProfileWindow(QWidget* parent = 0);
+ virtual ~QtProfileWindow();
+
+ virtual void setJID(const JID& jid);
+ virtual void setVCard(VCard::ref vcard);
+
+ virtual void setEnabled(bool b);
+ virtual void setProcessing(bool processing);
+ virtual void setError(const std::string& error);
+ virtual void setEditable(bool b);
+
+ virtual void show();
+ virtual void hide();
+
+ private:
+ void updateTitle();
+ virtual void closeEvent(QCloseEvent* event);
+
+ private slots:
+ void handleSave();
+
+ private:
+ Ui::QtProfileWindow* ui;
+ JID jid;
+};
+
}
diff --git a/Swift/QtUI/QtProfileWindow.ui b/Swift/QtUI/QtProfileWindow.ui
new file mode 100644
index 0000000..68a36da
--- /dev/null
+++ b/Swift/QtUI/QtProfileWindow.ui
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtProfileWindow</class>
+ <widget class="QWidget" name="QtProfileWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>334</width>
+ <height>197</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Edit Profile</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="Swift::QtVCardWidget" name="vcard" native="true"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="errorLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="throbberLabel">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::NoTextInteraction</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="savePushButton">
+ <property name="text">
+ <string>Save</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Swift::QtVCardWidget</class>
+ <extends>QWidget</extends>
+ <header>Swift/QtUI/QtVCardWidget/QtVCardWidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Swift/QtUI/QtSwiftUtil.h b/Swift/QtUI/QtSwiftUtil.h
index 2d0f970..c903af1 100644
--- a/Swift/QtUI/QtSwiftUtil.h
+++ b/Swift/QtUI/QtSwiftUtil.h
@@ -9,4 +9,6 @@
#define P2QSTRING(a) QString::fromUtf8(a.c_str())
#define Q2PSTRING(a) std::string(a.toUtf8())
+#include <boost/date_time/posix_time/posix_time.hpp>
+
#define B2QDATE(a) QDateTime::fromTime_t((a - boost::posix_time::from_time_t(0)).total_seconds())
diff --git a/Swift/QtUI/QtVCardWidget/QtCloseButton.cpp b/Swift/QtUI/QtVCardWidget/QtCloseButton.cpp
new file mode 100644
index 0000000..a6afe81
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtCloseButton.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtCloseButton.h"
+
+#include <QMouseEvent>
+#include <QPainter>
+#include <QStyle>
+#include <QStyleOption>
+
+namespace Swift {
+
+QtCloseButton::QtCloseButton(QWidget *parent) : QAbstractButton(parent) {
+ lightPixmap = QPixmap(12,12);
+ lightPixmap.fill(QColor(0,0,0,0));
+ QStyleOption opt;
+ opt.init(this);
+ opt.state = QStyle::State(0);
+ opt.state |= QStyle::State_MouseOver;
+ QPainter lightPixmapPainter(&lightPixmap);
+ style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &lightPixmapPainter);
+
+ darkPixmap = QPixmap(12,12);
+ darkPixmap.fill(QColor(0,0,0,0));
+ opt.init(this);
+ opt.state = QStyle::State(0);
+ QPainter darkPixmapPainter(&darkPixmap);
+ style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &darkPixmapPainter);
+}
+
+QSize QtCloseButton::sizeHint() const {
+ return QSize(width(), height());
+}
+
+bool QtCloseButton::event(QEvent *e) {
+ if (e->type() == QEvent::Enter || e->type() == QEvent::Leave) {
+ update();
+ }
+ return QAbstractButton::event(e);
+}
+
+void QtCloseButton::paintEvent(QPaintEvent *) {
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::HighQualityAntialiasing);
+ if (underMouse()) {
+ painter.drawPixmap(0, 0, height(), height(), darkPixmap);
+ } else {
+ painter.drawPixmap(0, 0, height(), height(), lightPixmap);
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtCloseButton.h b/Swift/QtUI/QtVCardWidget/QtCloseButton.h
new file mode 100644
index 0000000..6ce8d30
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtCloseButton.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QAbstractButton>
+
+namespace Swift {
+
+ class QtCloseButton : public QAbstractButton {
+ Q_OBJECT
+ public:
+ explicit QtCloseButton(QWidget *parent = 0);
+ virtual QSize sizeHint() const;
+
+ protected:
+ virtual bool event(QEvent *e);
+ virtual void paintEvent(QPaintEvent* );
+
+ private:
+ QPixmap lightPixmap;
+ QPixmap darkPixmap;
+ };
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.cpp b/Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.cpp
new file mode 100644
index 0000000..b586444
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtRemovableItemDelegate.h"
+
+#include <QEvent>
+#include <QPainter>
+
+namespace Swift {
+
+QtRemovableItemDelegate::QtRemovableItemDelegate(const QStyle* style) : style(style) {
+
+}
+
+void QtRemovableItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex&) const {
+ QStyleOption opt;
+ opt.state = QStyle::State(0);
+ opt.state |= QStyle::State_MouseOver;
+ painter->save();
+ painter->fillRect(option.rect, option.state & QStyle::State_Selected ? option.palette.highlight() : option.palette.base());
+ painter->translate(option.rect.x(), option.rect.y()+(option.rect.height() - 12)/2);
+ style->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, painter);
+ painter->restore();
+}
+
+QWidget* QtRemovableItemDelegate::createEditor(QWidget*, const QStyleOptionViewItem&, const QModelIndex&) const {
+ return NULL;
+}
+
+bool QtRemovableItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) {
+ if (event->type() == QEvent::MouseButtonRelease) {
+ model->removeRow(index.row());
+ return true;
+ } else {
+ return QItemDelegate::editorEvent(event, model, option, index);
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.h b/Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.h
new file mode 100644
index 0000000..3d99ad8
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QItemDelegate>
+
+namespace Swift {
+
+class QtRemovableItemDelegate : public QItemDelegate {
+ public:
+ QtRemovableItemDelegate(const QStyle* style);
+
+ virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex&) const;
+ virtual QWidget* createEditor(QWidget*, const QStyleOptionViewItem&, const QModelIndex&) const;
+
+ protected:
+ virtual bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index);
+
+ private:
+ const QStyle* style;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtResizableLineEdit.cpp b/Swift/QtUI/QtVCardWidget/QtResizableLineEdit.cpp
new file mode 100644
index 0000000..efe04dc
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtResizableLineEdit.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtResizableLineEdit.h"
+
+namespace Swift {
+
+QtResizableLineEdit::QtResizableLineEdit(QWidget* parent) :
+ QLineEdit(parent) {
+ connect(this, SIGNAL(textChanged(QString)), SLOT(textChanged(QString)));
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ int marginHeight = 6;
+ setMaximumHeight(fontMetrics().height() + marginHeight);
+}
+
+QtResizableLineEdit::~QtResizableLineEdit() {
+}
+
+bool QtResizableLineEdit::isEditable() const {
+ return editable;
+}
+void QtResizableLineEdit::setEditable(const bool editable) {
+ this->editable = editable;
+ if (editable) {
+ setReadOnly(false);
+ } else {
+ setReadOnly(true);
+ }
+}
+
+
+QSize QtResizableLineEdit::sizeHint() const {
+ int horizontalMargin = 10;
+#if QT_VERSION >= 0x040700
+ int w = fontMetrics().boundingRect(text().isEmpty() ? placeholderText() : text()).width() + horizontalMargin;
+#else
+ int w = fontMetrics().boundingRect(text().isEmpty() ? QString(" ") : text()).width() + horizontalMargin;
+#endif
+ return QSize(w, height());
+}
+
+void QtResizableLineEdit::textChanged(QString) {
+ updateGeometry();
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtResizableLineEdit.h b/Swift/QtUI/QtVCardWidget/QtResizableLineEdit.h
new file mode 100644
index 0000000..9022d38
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtResizableLineEdit.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QLineEdit>
+
+namespace Swift {
+
+ class QtResizableLineEdit : public QLineEdit {
+ Q_OBJECT
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable)
+
+ public:
+ explicit QtResizableLineEdit(QWidget* parent = 0);
+ ~QtResizableLineEdit();
+
+ bool isEditable() const;
+ void setEditable(const bool);
+
+ virtual QSize sizeHint() const;
+
+ private slots:
+ void textChanged(QString);
+
+ private:
+ bool editable;
+ };
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtTagComboBox.cpp b/Swift/QtUI/QtVCardWidget/QtTagComboBox.cpp
new file mode 100644
index 0000000..bade009
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtTagComboBox.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtTagComboBox.h"
+
+#include <QAbstractItemView>
+#include <QtGui>
+
+namespace Swift {
+
+QtTagComboBox::QtTagComboBox(QWidget* parent) : QComboBox(parent) {
+ setEditable(false);
+ displayModel = new QStandardItemModel();
+ displayItem = new QStandardItem();
+ displayItem->setText("");
+ displayModel->insertRow(0, displayItem);
+ editMenu = new QMenu();
+ this->setModel(displayModel);
+ editable = true;
+}
+
+QtTagComboBox::~QtTagComboBox() {
+
+}
+
+bool QtTagComboBox::isEditable() const {
+ return editable;
+}
+
+void QtTagComboBox::setEditable(const bool editable) {
+ this->editable = editable;
+}
+
+void QtTagComboBox::addTag(const QString &id, const QString &label) {
+ QAction* tagAction = new QAction(editMenu);
+ tagAction->setText(label);
+ tagAction->setCheckable(true);
+ tagAction->setData(QString(id));
+ editMenu->addAction(tagAction);
+}
+
+void QtTagComboBox::setTag(const QString &id, bool value) {
+ QList<QAction*> tagActions = editMenu->actions();
+ foreach(QAction* action, tagActions) {
+ if (action->data() == id) {
+ action->setChecked(value);
+ updateDisplayItem();
+ return;
+ }
+ }
+}
+
+bool QtTagComboBox::isTagSet(const QString &id) const {
+ QList<QAction*> tagActions = editMenu->actions();
+ foreach(QAction* action, tagActions) {
+ if (action->data() == id) {
+ return action->isChecked();
+ }
+ }
+ return false;
+}
+
+void QtTagComboBox::showPopup() {
+
+}
+
+void QtTagComboBox::hidePopup() {
+
+}
+
+bool QtTagComboBox::event(QEvent* event) {
+ if (event->type() == QEvent::MouseButtonPress ||
+ event->type() == QEvent::KeyRelease) {
+ if (!editable) return true;
+
+ QPoint p = mapToGlobal(QPoint(0,0));
+ p += QPoint(0, height());
+ editMenu->exec(p);
+ updateDisplayItem();
+ return true;
+ }
+ return QComboBox::event(event);
+}
+
+void QtTagComboBox::updateDisplayItem() {
+ QList<QAction*> tagActions = editMenu->actions();
+ QString text = "";
+ foreach(QAction* action, tagActions) {
+ if (action->isChecked()) {
+ if (text != "") {
+ text += ", ";
+ }
+ text += action->text();
+ }
+ }
+ setItemText(0, text);
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtTagComboBox.h b/Swift/QtUI/QtVCardWidget/QtTagComboBox.h
new file mode 100644
index 0000000..37a60af
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtTagComboBox.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QComboBox>
+#include <QMenu>
+#include <QStandardItem>
+#include <QStandardItemModel>
+
+namespace Swift {
+
+class QtTagComboBox : public QComboBox {
+ Q_OBJECT
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable)
+
+ public:
+ explicit QtTagComboBox(QWidget* parent = 0);
+ ~QtTagComboBox();
+
+ bool isEditable() const;
+ void setEditable(const bool);
+
+ void addTag(const QString& id, const QString& label);
+ void setTag(const QString& id, bool value);
+ bool isTagSet(const QString& id) const;
+
+ virtual void showPopup();
+ virtual void hidePopup();
+
+ virtual bool event(QEvent* event);
+
+ private:
+ void updateDisplayItem();
+
+ private:
+ bool editable;
+ QStandardItemModel* displayModel;
+ QStandardItem* displayItem;
+ QMenu* editMenu;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardAddressField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardAddressField.cpp
new file mode 100644
index 0000000..4d34e53
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardAddressField.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardAddressField.h"
+
+#include <QGridLayout>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardAddressField::QtVCardAddressField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("Address")) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardAddressField::~QtVCardAddressField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardAddressField::setupContentWidgets() {
+ textFieldGridLayout = new QGridLayout();
+
+ streetLineEdit = new QtResizableLineEdit(this);
+ textFieldGridLayout->addWidget(streetLineEdit, 0, 0, Qt::AlignVCenter);
+
+ poboxLineEdit = new QtResizableLineEdit(this);
+ textFieldGridLayout->addWidget(poboxLineEdit, 0, 1, Qt::AlignVCenter);
+
+ addressextLineEdit = new QtResizableLineEdit(this);
+ textFieldGridLayout->addWidget(addressextLineEdit, 1, 0, Qt::AlignVCenter);
+
+ cityLineEdit = new QtResizableLineEdit(this);
+ textFieldGridLayout->addWidget(cityLineEdit, 2, 0, Qt::AlignVCenter);
+
+ pocodeLineEdit = new QtResizableLineEdit(this);
+ textFieldGridLayout->addWidget(pocodeLineEdit, 2, 1, Qt::AlignVCenter);
+
+ regionLineEdit = new QtResizableLineEdit(this);
+ textFieldGridLayout->addWidget(regionLineEdit, 3, 0, Qt::AlignVCenter);
+
+ countryLineEdit = new QtResizableLineEdit(this);
+ textFieldGridLayout->addWidget(countryLineEdit, 4, 0, Qt::AlignVCenter);
+ textFieldGridLayout->setVerticalSpacing(2);
+ getGridLayout()->addLayout(textFieldGridLayout, getGridLayout()->rowCount()-1, 2, 5, 2, Qt::AlignVCenter);
+ textFieldGridLayoutItem = getGridLayout()->itemAtPosition(getGridLayout()->rowCount()-1, 2);
+
+#if QT_VERSION >= 0x040700
+ streetLineEdit->setPlaceholderText(tr("Street"));
+ poboxLineEdit->setPlaceholderText(tr("PO Box"));
+ addressextLineEdit->setPlaceholderText(tr("Address Extension"));
+ cityLineEdit->setPlaceholderText(tr("City"));
+ pocodeLineEdit->setPlaceholderText(tr("Postal Code"));
+ regionLineEdit->setPlaceholderText(tr("Region"));
+ countryLineEdit->setPlaceholderText(tr("Country"));
+#endif
+
+ deliveryTypeLabel = new QLabel(this);
+ deliveryTypeLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ getGridLayout()->addWidget(deliveryTypeLabel, getGridLayout()->rowCount()-3, 4, Qt::AlignVCenter);
+
+ domesticRadioButton = new QRadioButton(tr("Domestic Delivery"), this);
+ getGridLayout()->addWidget(domesticRadioButton, getGridLayout()->rowCount()-2, 4, Qt::AlignVCenter);
+
+ internationalRadioButton = new QRadioButton(tr("International Delivery"), this);
+ getGridLayout()->addWidget(internationalRadioButton, getGridLayout()->rowCount()-1, 4, Qt::AlignVCenter);
+
+ buttonGroup = new QButtonGroup(this);
+ buttonGroup->addButton(domesticRadioButton);
+ buttonGroup->addButton(internationalRadioButton);
+
+ setTabOrder(internationalRadioButton, getTagComboBox());
+ getTagComboBox()->addTag("postal", tr("Postal"));
+ getTagComboBox()->addTag("parcel", tr("Parcel"));
+
+ QtVCardHomeWork::setTagComboBox(getTagComboBox());
+
+ textFields << streetLineEdit << poboxLineEdit << addressextLineEdit << cityLineEdit << pocodeLineEdit << regionLineEdit << countryLineEdit;
+ childWidgets << deliveryTypeLabel << domesticRadioButton << internationalRadioButton;
+}
+
+void QtVCardAddressField::customCleanup() {
+ foreach(QWidget* widget, textFields) {
+ widget->hide();
+ textFieldGridLayout->removeWidget(widget);
+ }
+ getGridLayout()->removeItem(textFieldGridLayoutItem);
+}
+
+
+
+bool QtVCardAddressField::isEmpty() const {
+ return streetLineEdit->text().isEmpty() &&
+ poboxLineEdit->text().isEmpty() &&
+ addressextLineEdit->text().isEmpty() &&
+ cityLineEdit->text().isEmpty() &&
+ pocodeLineEdit->text().isEmpty() &&
+ regionLineEdit->text().isEmpty() &&
+ countryLineEdit->text().isEmpty();
+}
+
+void QtVCardAddressField::setAddress(const VCard::Address& address) {
+ setPreferred(address.isPreferred);
+ setHome(address.isHome);
+ setWork(address.isWork);
+ getTagComboBox()->setTag("postal", address.isPostal);
+ getTagComboBox()->setTag("parcel", address.isParcel);
+ domesticRadioButton->setChecked(address.deliveryType == VCard::DomesticDelivery);
+ internationalRadioButton->setChecked(address.deliveryType == VCard::InternationalDelivery);
+ streetLineEdit->setText(P2QSTRING(address.street));
+ poboxLineEdit->setText(P2QSTRING(address.poBox));
+ addressextLineEdit->setText(P2QSTRING(address.addressExtension));
+ cityLineEdit->setText(P2QSTRING(address.locality));
+ pocodeLineEdit->setText(P2QSTRING(address.postalCode));
+ regionLineEdit->setText(P2QSTRING(address.region));
+ countryLineEdit->setText(P2QSTRING(address.country));
+}
+
+VCard::Address QtVCardAddressField::getAddress() const {
+ VCard::Address address;
+ address.isPreferred = getPreferred();
+ address.isHome = getHome();
+ address.isWork = getWork();
+ address.deliveryType = domesticRadioButton->isChecked() ? VCard::DomesticDelivery : (internationalRadioButton->isChecked() ? VCard::InternationalDelivery : VCard::None);
+ address.isPostal = getTagComboBox()->isTagSet("postal");
+ address.isParcel = getTagComboBox()->isTagSet("parcel");
+ address.street = Q2PSTRING(streetLineEdit->text());
+ address.poBox = Q2PSTRING(poboxLineEdit->text());
+ address.addressExtension = Q2PSTRING(addressextLineEdit->text());
+ address.locality = Q2PSTRING(cityLineEdit->text());
+ address.postalCode = Q2PSTRING(pocodeLineEdit->text());
+ address.region = Q2PSTRING(regionLineEdit->text());
+ address.country = Q2PSTRING(countryLineEdit->text());
+ return address;
+}
+
+void QtVCardAddressField::handleEditibleChanged(bool isEditable) {
+ if (streetLineEdit) streetLineEdit->setEditable(isEditable);
+ if (poboxLineEdit) poboxLineEdit->setEditable(isEditable);
+ if (addressextLineEdit) addressextLineEdit->setEditable(isEditable);
+ if (cityLineEdit) cityLineEdit->setEditable(isEditable);
+ if (pocodeLineEdit) pocodeLineEdit->setEditable(isEditable);
+ if (regionLineEdit) regionLineEdit->setEditable(isEditable);
+ if (countryLineEdit) countryLineEdit->setEditable(isEditable);
+
+ if (deliveryTypeLabel) {
+ deliveryTypeLabel->setText(buttonGroup->checkedButton() == 0 ? "" : buttonGroup->checkedButton()->text());
+ deliveryTypeLabel->setVisible(!isEditable);
+ }
+ if (domesticRadioButton) domesticRadioButton->setVisible(isEditable);
+ if (internationalRadioButton) internationalRadioButton->setVisible(isEditable);
+
+ foreach (QWidget* widget, textFields) {
+ QtResizableLineEdit* lineEdit;
+ if ((lineEdit = dynamic_cast<QtResizableLineEdit*>(widget))) {
+ lineEdit->setShown(isEditable ? true : !lineEdit->text().isEmpty());
+ lineEdit->setStyleSheet(isEditable ? "" : "QLineEdit { border: none; background: transparent; }");
+ }
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardAddressField.h b/Swift/QtUI/QtVCardWidget/QtVCardAddressField.h
new file mode 100644
index 0000000..5a1256a
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardAddressField.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include <QButtonGroup>
+#include <QRadioButton>
+
+#include "QtResizableLineEdit.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+#include "QtVCardHomeWork.h"
+
+namespace Swift {
+
+class QtVCardAddressField : public QtVCardGeneralField, public QtVCardHomeWork {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("Address", UNLIMITED_INSTANCES, QtVCardAddressField)
+
+ QtVCardAddressField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardAddressField();
+
+ virtual bool isEmpty() const;
+
+ void setAddress(const VCard::Address& address);
+ VCard::Address getAddress() const;
+
+ protected:
+ virtual void setupContentWidgets();
+ virtual void customCleanup();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QList<QWidget*> textFields;
+ QtResizableLineEdit* streetLineEdit;
+ QtResizableLineEdit* poboxLineEdit;
+ QtResizableLineEdit* addressextLineEdit;
+ QtResizableLineEdit* cityLineEdit;
+ QtResizableLineEdit* pocodeLineEdit;
+ QtResizableLineEdit* regionLineEdit;
+ QtResizableLineEdit* countryLineEdit;
+ QGridLayout* textFieldGridLayout;
+ QLayoutItem* textFieldGridLayoutItem;
+
+ QLabel* deliveryTypeLabel;
+ QRadioButton* domesticRadioButton;
+ QRadioButton* internationalRadioButton;
+ QButtonGroup* buttonGroup;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardAddressLabelField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardAddressLabelField.cpp
new file mode 100644
index 0000000..20f48b9
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardAddressLabelField.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardAddressLabelField.h"
+
+#include <QGridLayout>
+#include <boost/algorithm/string.hpp>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardAddressLabelField::QtVCardAddressLabelField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("Address Label")) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardAddressLabelField::~QtVCardAddressLabelField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardAddressLabelField::setupContentWidgets() {
+ addressLabelPlainTextEdit = new QPlainTextEdit(this);
+ addressLabelPlainTextEdit->setTabChangesFocus(true);
+ getGridLayout()->addWidget(addressLabelPlainTextEdit, getGridLayout()->rowCount()-1, 2, 3, 2, Qt::AlignVCenter);
+
+ deliveryTypeLabel = new QLabel(this);
+ deliveryTypeLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ getGridLayout()->addWidget(deliveryTypeLabel, getGridLayout()->rowCount()-2, 4, Qt::AlignVCenter);
+
+ domesticRadioButton = new QRadioButton(tr("Domestic Delivery"), this);
+ getGridLayout()->addWidget(domesticRadioButton, getGridLayout()->rowCount()-2, 4, Qt::AlignVCenter);
+
+ internationalRadioButton = new QRadioButton(tr("International Delivery"), this);
+ getGridLayout()->addWidget(internationalRadioButton, getGridLayout()->rowCount()-1, 4, Qt::AlignVCenter);
+
+ buttonGroup = new QButtonGroup(this);
+ buttonGroup->addButton(domesticRadioButton);
+ buttonGroup->addButton(internationalRadioButton);
+
+ setTabOrder(internationalRadioButton, getTagComboBox());
+ getTagComboBox()->addTag("postal", tr("Postal"));
+ getTagComboBox()->addTag("parcel", tr("Parcel"));
+
+ QtVCardHomeWork::setTagComboBox(getTagComboBox());
+ deliveryTypeLabel->hide();
+ childWidgets << addressLabelPlainTextEdit << deliveryTypeLabel << domesticRadioButton << internationalRadioButton;
+}
+
+bool QtVCardAddressLabelField::isEmpty() const {
+ return addressLabelPlainTextEdit->toPlainText().isEmpty();
+}
+
+void QtVCardAddressLabelField::setAddressLabel(const VCard::AddressLabel& addressLabel) {
+ setPreferred(addressLabel.isPreferred);
+ setHome(addressLabel.isHome);
+ setWork(addressLabel.isWork);
+ getTagComboBox()->setTag("postal", addressLabel.isPostal);
+ getTagComboBox()->setTag("parcel", addressLabel.isParcel);
+ domesticRadioButton->setChecked(addressLabel.deliveryType == VCard::DomesticDelivery);
+ internationalRadioButton->setChecked(addressLabel.deliveryType == VCard::InternationalDelivery);
+ std::string joinedLines = boost::algorithm::join(addressLabel.lines, "\n");
+ addressLabelPlainTextEdit->setPlainText(P2QSTRING(joinedLines));
+}
+
+VCard::AddressLabel QtVCardAddressLabelField::getAddressLabel() const {
+ VCard::AddressLabel addressLabel;
+ addressLabel.isPreferred = getPreferred();
+ addressLabel.isHome = getHome();
+ addressLabel.isWork = getWork();
+ addressLabel.deliveryType = domesticRadioButton->isChecked() ? VCard::DomesticDelivery : (internationalRadioButton->isChecked() ? VCard::InternationalDelivery : VCard::None);
+ addressLabel.isPostal = getTagComboBox()->isTagSet("postal");
+ addressLabel.isParcel = getTagComboBox()->isTagSet("parcel");
+
+ std::string lines = Q2PSTRING(addressLabelPlainTextEdit->toPlainText());
+ boost::split(addressLabel.lines, lines, boost::is_any_of("\n"));
+ return addressLabel;
+}
+
+void QtVCardAddressLabelField::handleEditibleChanged(bool isEditable) {
+ if (addressLabelPlainTextEdit) {
+ addressLabelPlainTextEdit->setReadOnly(!isEditable);
+ addressLabelPlainTextEdit->setStyleSheet(isEditable ? "" : "QPlainTextEdit { background: transparent; }");
+ }
+
+ if (deliveryTypeLabel) {
+ deliveryTypeLabel->setText(buttonGroup->checkedButton() == 0 ? "" : buttonGroup->checkedButton()->text());
+ deliveryTypeLabel->setVisible(!isEditable);
+ }
+ if (domesticRadioButton) domesticRadioButton->setVisible(isEditable);
+ if (internationalRadioButton) internationalRadioButton->setVisible(isEditable);
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardAddressLabelField.h b/Swift/QtUI/QtVCardWidget/QtVCardAddressLabelField.h
new file mode 100644
index 0000000..0e097d9
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardAddressLabelField.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QButtonGroup>
+#include <QPlainTextEdit>
+#include <QRadioButton>
+#include <Swiften/Elements/VCard.h>
+
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+#include "QtVCardHomeWork.h"
+
+namespace Swift {
+
+class QtVCardAddressLabelField : public QtVCardGeneralField, public QtVCardHomeWork {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("AddressLabel", UNLIMITED_INSTANCES, QtVCardAddressLabelField)
+
+ QtVCardAddressLabelField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardAddressLabelField();
+
+ virtual bool isEmpty() const;
+
+ void setAddressLabel(const VCard::AddressLabel& addressLabel);
+ VCard::AddressLabel getAddressLabel() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QPlainTextEdit* addressLabelPlainTextEdit;
+
+ QLabel* deliveryTypeLabel;
+ QRadioButton* domesticRadioButton;
+ QRadioButton* internationalRadioButton;
+ QButtonGroup* buttonGroup;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardBirthdayField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardBirthdayField.cpp
new file mode 100644
index 0000000..2afc2f6
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardBirthdayField.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardBirthdayField.h"
+
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <boost/algorithm/string.hpp>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardBirthdayField::QtVCardBirthdayField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("Birthday"), false, false) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardBirthdayField::~QtVCardBirthdayField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardBirthdayField::setupContentWidgets() {
+ birthdayLabel = new QLabel(this);
+ birthdayLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ birthdayDateEdit = new QDateEdit(this);
+ birthdayDateEdit->setCalendarPopup(true);
+
+ QHBoxLayout* birthdayLayout = new QHBoxLayout();
+ birthdayLayout->addWidget(birthdayLabel);
+ birthdayLayout->addWidget(birthdayDateEdit);
+
+ getGridLayout()->addLayout(birthdayLayout, getGridLayout()->rowCount()-1, 2, Qt::AlignVCenter);
+
+ getTagComboBox()->hide();
+ birthdayLabel->hide();
+ childWidgets << birthdayLabel << birthdayDateEdit;
+}
+
+bool QtVCardBirthdayField::isEmpty() const {
+ return false;
+}
+
+void QtVCardBirthdayField::setBirthday(const boost::posix_time::ptime& birthday) {
+ birthdayDateEdit->setDate(B2QDATE(birthday).date());
+}
+
+boost::posix_time::ptime QtVCardBirthdayField::getBirthday() const {
+ return boost::posix_time::from_time_t(QDateTime(birthdayDateEdit->date()).toTime_t());
+}
+
+void QtVCardBirthdayField::handleEditibleChanged(bool isEditable) {
+ birthdayLabel->setText(birthdayDateEdit->date().toString(Qt::DefaultLocaleLongDate));
+ birthdayDateEdit->setVisible(isEditable);
+ birthdayLabel->setVisible(!isEditable);
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardBirthdayField.h b/Swift/QtUI/QtVCardWidget/QtVCardBirthdayField.h
new file mode 100644
index 0000000..4be6e27
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardBirthdayField.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QDateEdit>
+#include <Swiften/Elements/VCard.h>
+
+#include "QtCloseButton.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+
+namespace Swift {
+
+class QtVCardBirthdayField : public QtVCardGeneralField {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("Birthday", 1, QtVCardBirthdayField)
+
+ QtVCardBirthdayField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardBirthdayField();
+
+ virtual bool isEmpty() const;
+
+ void setBirthday(const boost::posix_time::ptime& addressLabel);
+ boost::posix_time::ptime getBirthday() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QLabel* birthdayLabel;
+ QDateEdit* birthdayDateEdit;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardDescriptionField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardDescriptionField.cpp
new file mode 100644
index 0000000..f907d78
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardDescriptionField.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardDescriptionField.h"
+
+#include <boost/algorithm/string.hpp>
+#include <QFontMetrics>
+#include <QGridLayout>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardDescriptionField::QtVCardDescriptionField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("Description"), false, false) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardDescriptionField::~QtVCardDescriptionField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardDescriptionField::setupContentWidgets() {
+ descriptionPlainTextEdit = new QPlainTextEdit(this);
+ descriptionPlainTextEdit->setMinimumHeight(70);
+ getGridLayout()->addWidget(descriptionPlainTextEdit, getGridLayout()->rowCount()-1, 2, 2, 2, Qt::AlignVCenter);
+ getTagComboBox()->hide();
+ childWidgets << descriptionPlainTextEdit;
+}
+
+bool QtVCardDescriptionField::isEmpty() const {
+ return descriptionPlainTextEdit->toPlainText().isEmpty();
+}
+
+void QtVCardDescriptionField::setDescription(const std::string& description) {
+ descriptionPlainTextEdit->setPlainText(P2QSTRING(description));
+}
+
+std::string QtVCardDescriptionField::getDescription() const {
+ return Q2PSTRING(descriptionPlainTextEdit->toPlainText());
+}
+
+void QtVCardDescriptionField::handleEditibleChanged(bool isEditable) {
+ if (descriptionPlainTextEdit) {
+ if (isEditable) {
+ descriptionPlainTextEdit->setMinimumHeight(70);
+ } else {
+ QFontMetrics inputMetrics(descriptionPlainTextEdit->document()->defaultFont());
+ QRect horizontalBounds = contentsRect().adjusted(0,0,0,9999);
+ QRect boundingRect = inputMetrics.boundingRect(horizontalBounds, Qt::TextWordWrap, descriptionPlainTextEdit->toPlainText() + "A");
+ int left, top, right, bottom;
+ getContentsMargins(&left, &top, &right, &bottom);
+ int height = boundingRect.height() + top + bottom + inputMetrics.height();
+ descriptionPlainTextEdit->setMinimumHeight(height > 70 ? 70 : height);
+ }
+ descriptionPlainTextEdit->setReadOnly(!isEditable);
+ descriptionPlainTextEdit->setStyleSheet(isEditable ? "" : "QPlainTextEdit { background: transparent; }");
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardDescriptionField.h b/Swift/QtUI/QtVCardWidget/QtVCardDescriptionField.h
new file mode 100644
index 0000000..3b1b3d9
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardDescriptionField.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include <QPlainTextEdit>
+
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+
+namespace Swift {
+
+class QtVCardDescriptionField : public QtVCardGeneralField {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("Description", 1, QtVCardDescriptionField)
+
+ QtVCardDescriptionField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardDescriptionField();
+
+ virtual bool isEmpty() const;
+
+ void setDescription(const std::string& description);
+ std::string getDescription() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QPlainTextEdit* descriptionPlainTextEdit;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h b/Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h
new file mode 100644
index 0000000..168c01b
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QGridLayout>
+#include <QObject>
+#include <QString>
+#include <typeinfo>
+
+#define GENERIC_QT_VCARD_FIELD_INFO(MENU_NAME, ALLOWED_INSTANCES, FIELD_CLASS) \
+ class FieldInfo : public QtVCardFieldInfo { \
+ public: \
+ virtual ~FieldInfo() { \
+ } \
+ \
+ virtual QString getMenuName() const { \
+ return QObject::tr(MENU_NAME); \
+ } \
+ \
+ virtual int getAllowedInstances() const { \
+ return ALLOWED_INSTANCES; \
+ } \
+ \
+ virtual QWidget* createFieldInstance(QWidget* parent, QGridLayout* layout, bool editable) const { \
+ return new FIELD_CLASS(parent, layout, editable); \
+ } \
+ \
+ virtual bool testInstance(QWidget* widget) const { \
+ return dynamic_cast<FIELD_CLASS*>(widget) != 0; \
+ } \
+ };
+
+class QWidget;
+
+namespace Swift {
+
+ class QtVCardFieldInfo {
+ public:
+ static const int UNLIMITED_INSTANCES = -1;
+
+ virtual ~QtVCardFieldInfo() {
+ }
+ virtual QString getMenuName() const = 0;
+ virtual int getAllowedInstances() const = 0;
+ virtual QWidget* createFieldInstance(QWidget* parent, QGridLayout* layout, bool editable) const = 0;
+ virtual bool testInstance(QWidget*) const = 0;
+ };
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardGeneralField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardGeneralField.cpp
new file mode 100644
index 0000000..5b3ef87
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardGeneralField.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardGeneralField.h"
+
+#include <QHBoxLayout>
+#include <Swiften/Base/Log.h>
+
+namespace Swift {
+
+QtVCardGeneralField::QtVCardGeneralField(QWidget* parent, QGridLayout* layout, bool editable, int row, QString label, bool preferrable, bool taggable) :
+ QWidget(parent), preferrable(preferrable), taggable(taggable), layout(layout), row(row), preferredCheckBox(0), label(0), labelText(label),
+ tagComboBox(0), closeButton(0) {
+ setEditable(editable);
+}
+
+QtVCardGeneralField::~QtVCardGeneralField() {
+
+}
+
+void QtVCardGeneralField::initialize() {
+ if (preferrable) {
+ preferredCheckBox = new QCheckBox(this);
+ preferredCheckBox->setStyleSheet(
+ "QCheckBox::indicator { width: 18px; height: 18px; }"
+ "QCheckBox::indicator:checked { image: url(:/icons/star-checked.png); }"
+ "QCheckBox::indicator:unchecked { image: url(:/icons/star-unchecked); }"
+ );
+ layout->addWidget(preferredCheckBox, row, 0, Qt::AlignVCenter);
+ childWidgets << preferredCheckBox;
+ }
+ label = new QLabel(this);
+ label->setText(labelText);
+ layout->addWidget(label, row, 1, Qt::AlignVCenter | Qt::AlignRight);
+
+ tagLabel = new QLabel(this);
+ tagLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+
+ tagComboBox = new QtTagComboBox(this);
+ closeButton = new QtCloseButton(this);
+ connect(closeButton, SIGNAL(clicked()), SLOT(handleCloseButtonClicked()));
+
+ QHBoxLayout* tagLayout = new QHBoxLayout();
+ tagLayout->addWidget(tagLabel);
+ tagLayout->addWidget(tagComboBox);
+
+ setupContentWidgets();
+ layout->addLayout(tagLayout, row, 4, Qt::AlignTop);
+ layout->addWidget(closeButton, row, 5, Qt::AlignCenter);
+ closeButton->resize(12, 12);
+ tagLabel->hide();
+
+ childWidgets << label << tagComboBox << tagLabel << closeButton;
+}
+
+bool QtVCardGeneralField::isEditable() const {
+ return editable;
+}
+
+void QtVCardGeneralField::setEditable(bool editable) {
+ this->editable = editable;
+ if (tagComboBox) {
+ if (taggable) {
+ tagLabel->setText(tagComboBox->itemText(0));
+ tagComboBox->setVisible(editable);
+ tagLabel->setVisible(!editable);
+ } else {
+ tagLabel->hide();
+ tagComboBox->hide();
+ }
+ }
+ if (closeButton) closeButton->setVisible(editable);
+ if (preferredCheckBox) {
+ if (editable) {
+ preferredCheckBox->show();
+ } else if (!preferredCheckBox->isChecked()) {
+ preferredCheckBox->hide();
+ }
+ preferredCheckBox->setEnabled(editable);
+ }
+ editableChanged(this->editable);
+}
+
+void QtVCardGeneralField::setPreferred(const bool preferred) {
+ if (preferredCheckBox) preferredCheckBox->setChecked(preferred);
+}
+
+bool QtVCardGeneralField::getPreferred() const {
+ return preferredCheckBox ? preferredCheckBox->isChecked() : false;
+}
+
+void QtVCardGeneralField::customCleanup() {
+}
+
+QtTagComboBox* QtVCardGeneralField::getTagComboBox() const {
+ return tagComboBox;
+}
+
+QGridLayout* QtVCardGeneralField::getGridLayout() const {
+ return layout;
+}
+
+void QtVCardGeneralField::handleCloseButtonClicked() {
+ customCleanup();
+ foreach(QWidget* widget, childWidgets) {
+ widget->hide();
+ layout->removeWidget(widget);
+ }
+ deleteField(this);
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardGeneralField.h b/Swift/QtUI/QtVCardWidget/QtVCardGeneralField.h
new file mode 100644
index 0000000..4afe692
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardGeneralField.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QCheckBox>
+#include <QGridLayout>
+#include <QLabel>
+#include <QWidget>
+
+#include "QtCloseButton.h"
+#include "QtTagComboBox.h"
+
+namespace Swift {
+
+/*
+ * covers features like:
+ * - preffered (star ceckbox)
+ * - combo check boxh
+ * - label
+ * - remove button
+ */
+class QtVCardGeneralField : public QWidget {
+ Q_OBJECT
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable NOTIFY editableChanged)
+ Q_PROPERTY(bool empty READ isEmpty)
+
+ public:
+ explicit QtVCardGeneralField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false, int row = 0, QString label = QString(),
+ bool preferrable = true, bool taggable = true);
+ virtual ~QtVCardGeneralField();
+
+ void initialize();
+
+ virtual bool isEditable() const;
+ virtual void setEditable(bool);
+
+ virtual bool isEmpty() const = 0;
+
+ void setPreferred(const bool preferred);
+ bool getPreferred() const;
+
+ protected:
+ virtual void setupContentWidgets() = 0;
+ virtual void customCleanup();
+
+ QtTagComboBox* getTagComboBox() const;
+ QGridLayout* getGridLayout() const;
+
+ signals:
+ void editableChanged(bool);
+ void deleteField(QtVCardGeneralField*);
+
+ public slots:
+ void handleCloseButtonClicked();
+
+ protected:
+ QList<QWidget*> childWidgets;
+
+ private:
+ bool editable;
+ bool preferrable;
+ bool taggable;
+ QGridLayout* layout;
+ int row;
+ QCheckBox* preferredCheckBox;
+ QLabel* label;
+ QString labelText;
+ QtTagComboBox* tagComboBox;
+ QLabel* tagLabel;
+ QtCloseButton* closeButton;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardHomeWork.cpp b/Swift/QtUI/QtVCardWidget/QtVCardHomeWork.cpp
new file mode 100644
index 0000000..3119a80
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardHomeWork.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardHomeWork.h"
+
+namespace Swift {
+
+QtVCardHomeWork::QtVCardHomeWork() : tagComboBox(0) {
+}
+
+QtVCardHomeWork::~QtVCardHomeWork() {
+}
+
+void QtVCardHomeWork::setTagComboBox(QtTagComboBox* tagBox) {
+ tagComboBox = tagBox;
+ tagComboBox->addTag("home", QObject::tr("Home"));
+ tagComboBox->addTag("work", QObject::tr("Work"));
+}
+
+void QtVCardHomeWork::setHome(const bool home) {
+ tagComboBox->setTag("home", home);
+}
+
+bool QtVCardHomeWork::getHome() const {
+ return tagComboBox->isTagSet("home");
+}
+
+void QtVCardHomeWork::setWork(const bool work) {
+ tagComboBox->setTag("work", work);
+}
+
+bool QtVCardHomeWork::getWork() const {
+ return tagComboBox->isTagSet("work");
+}
+
+}
+
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardHomeWork.h b/Swift/QtUI/QtVCardWidget/QtVCardHomeWork.h
new file mode 100644
index 0000000..768d984
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardHomeWork.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QObject>
+
+#include "QtTagComboBox.h"
+
+namespace Swift {
+
+class QtVCardHomeWork {
+ public:
+ QtVCardHomeWork();
+ virtual ~QtVCardHomeWork();
+
+ void setTagComboBox(QtTagComboBox* tagBox);
+
+ void setHome(const bool home);
+ bool getHome() const;
+ void setWork(const bool work);
+ bool getWork() const;
+
+ private:
+ QtTagComboBox* tagComboBox;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardInternetEMailField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardInternetEMailField.cpp
new file mode 100644
index 0000000..46f253f
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardInternetEMailField.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardInternetEMailField.h"
+
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QTextDocument>
+#include <Swiften/Base/Log.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardInternetEMailField::QtVCardInternetEMailField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("E-Mail")) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardInternetEMailField::~QtVCardInternetEMailField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardInternetEMailField::setupContentWidgets() {
+ emailLabel = new QLabel(this);
+ emailLabel->setOpenExternalLinks(true);
+ emailLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
+ emailLineEdit = new QtResizableLineEdit(this);
+#if QT_VERSION >= 0x040700
+ emailLineEdit->setPlaceholderText(tr("alice@wonderland.lit"));
+#endif
+ QHBoxLayout* emailLayout = new QHBoxLayout();
+ emailLayout->addWidget(emailLabel);
+ emailLayout->addWidget(emailLineEdit);
+ getGridLayout()->addLayout(emailLayout, getGridLayout()->rowCount()-1, 2, 1, 2, Qt::AlignVCenter);
+ setTabOrder(emailLineEdit, getTagComboBox());
+ QtVCardHomeWork::setTagComboBox(getTagComboBox());
+ emailLabel->hide();
+ childWidgets << emailLabel << emailLineEdit;
+}
+
+bool QtVCardInternetEMailField::isEmpty() const {
+ return emailLineEdit->text().isEmpty();
+}
+
+void QtVCardInternetEMailField::setInternetEMailAddress(const VCard::EMailAddress& address) {
+ assert(address.isInternet);
+ setPreferred(address.isPreferred);
+ setHome(address.isHome);
+ setWork(address.isWork);
+ emailLineEdit->setText(P2QSTRING(address.address));
+}
+
+VCard::EMailAddress QtVCardInternetEMailField::getInternetEMailAddress() const {
+ VCard::EMailAddress address;
+ address.isInternet = true;
+ address.isPreferred = getPreferred();
+ address.isHome = getHome();
+ address.isWork = getWork();
+ address.address = Q2PSTRING(emailLineEdit->text());
+ return address;
+}
+
+void QtVCardInternetEMailField::handleEditibleChanged(bool isEditable) {
+ if (isEditable) {
+ if (emailLineEdit) emailLineEdit->show();
+ if (emailLabel) emailLabel->hide();
+ } else {
+ if (emailLineEdit) emailLineEdit->hide();
+ if (emailLabel) {
+ emailLabel->setText(QString("<a href=\"mailto:%1\">%1</a>").arg(Qt::escape(emailLineEdit->text())));
+ emailLabel->show();
+ }
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardInternetEMailField.h b/Swift/QtUI/QtVCardWidget/QtVCardInternetEMailField.h
new file mode 100644
index 0000000..3f8a27f
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardInternetEMailField.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include "QtResizableLineEdit.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+#include "QtVCardHomeWork.h"
+
+namespace Swift {
+
+class QtVCardInternetEMailField : public QtVCardGeneralField, public QtVCardHomeWork {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("E-Mail", UNLIMITED_INSTANCES, QtVCardInternetEMailField)
+
+ QtVCardInternetEMailField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardInternetEMailField();
+
+ virtual bool isEmpty() const;
+
+ void setInternetEMailAddress(const VCard::EMailAddress& address);
+ VCard::EMailAddress getInternetEMailAddress() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QtResizableLineEdit* emailLineEdit;
+ QLabel* emailLabel;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardJIDField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardJIDField.cpp
new file mode 100644
index 0000000..dbb4b7c
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardJIDField.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardJIDField.h"
+
+#include <QGridLayout>
+#include <QTextDocument>
+#include <boost/algorithm/string.hpp>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardJIDField::QtVCardJIDField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("JID"), false, false) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardJIDField::~QtVCardJIDField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardJIDField::setupContentWidgets() {
+ jidLabel = new QLabel(this);
+ jidLabel->setOpenExternalLinks(true);
+ jidLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
+ jidLineEdit = new QtResizableLineEdit(this);
+#if QT_VERSION >= 0x040700
+ jidLineEdit->setPlaceholderText(tr("alice@wonderland.lit"));
+#endif
+ QHBoxLayout* jidLayout = new QHBoxLayout();
+ jidLayout->addWidget(jidLabel);
+ jidLayout->addWidget(jidLineEdit);
+ getGridLayout()->addLayout(jidLayout, getGridLayout()->rowCount()-1, 2, 1, 2, Qt::AlignVCenter);
+
+ jidLabel->hide();
+ getTagComboBox()->hide();
+
+ childWidgets << jidLabel << jidLineEdit;
+}
+
+bool QtVCardJIDField::isEmpty() const {
+ return jidLineEdit->text().isEmpty();
+}
+
+void QtVCardJIDField::setJID(const JID& jid) {
+ std::string jidStr = jid.toBare().toString();
+ jidLineEdit->setText(P2QSTRING(jidStr));
+}
+
+JID QtVCardJIDField::getJID() const {
+ return JID(Q2PSTRING(jidLineEdit->text()));
+}
+
+void QtVCardJIDField::handleEditibleChanged(bool isEditable) {
+ if (isEditable) {
+ if (jidLineEdit) jidLineEdit->show();
+ if (jidLabel) jidLabel->hide();
+ } else {
+ if (jidLineEdit) jidLineEdit->hide();
+ if (jidLabel) {
+ jidLabel->setText(QString("<a href=\"xmpp:%1\">%1</a>").arg(Qt::escape(jidLineEdit->text())));
+ jidLabel->show();
+ }
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardJIDField.h b/Swift/QtUI/QtVCardWidget/QtVCardJIDField.h
new file mode 100644
index 0000000..016bcf8
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardJIDField.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include "QtResizableLineEdit.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+
+namespace Swift {
+
+class QtVCardJIDField : public QtVCardGeneralField {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("JID", UNLIMITED_INSTANCES, QtVCardJIDField)
+
+ QtVCardJIDField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardJIDField();
+
+ virtual bool isEmpty() const;
+
+ void setJID(const JID& jid);
+ JID getJID() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QLabel* jidLabel;
+ QtResizableLineEdit* jidLineEdit;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardOrganizationField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardOrganizationField.cpp
new file mode 100644
index 0000000..5f231dc
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardOrganizationField.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardOrganizationField.h"
+
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <boost/algorithm/string.hpp>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardOrganizationField::QtVCardOrganizationField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("Organisation"), false, false) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardOrganizationField::~QtVCardOrganizationField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardOrganizationField::setupContentWidgets() {
+ organizationLabel = new QLabel(this);
+ organizationLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ organizationLineEdit = new QtResizableLineEdit(this);
+ QHBoxLayout* organizationLayout = new QHBoxLayout();
+ organizationLayout->addWidget(organizationLabel);
+ organizationLayout->addWidget(organizationLineEdit);
+
+ getGridLayout()->addLayout(organizationLayout, getGridLayout()->rowCount()-1, 2, 1, 2, Qt::AlignVCenter);
+
+ itemDelegate = new QtRemovableItemDelegate(style());
+
+ unitsTreeWidget = new QTreeWidget(this);
+ unitsTreeWidget->setColumnCount(2);
+ unitsTreeWidget->header()->setStretchLastSection(false);
+ int closeIconWidth = unitsTreeWidget->fontMetrics().height();
+ unitsTreeWidget->header()->resizeSection(1, closeIconWidth);
+ unitsTreeWidget->header()->setResizeMode(0, QHeaderView::Stretch);
+ unitsTreeWidget->setHeaderHidden(true);
+ unitsTreeWidget->setRootIsDecorated(false);
+ unitsTreeWidget->setEditTriggers(QAbstractItemView::DoubleClicked);
+ unitsTreeWidget->setItemDelegateForColumn(1, itemDelegate);
+ connect(unitsTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), SLOT(handleItemChanged(QTreeWidgetItem*,int)));
+ getGridLayout()->addWidget(unitsTreeWidget, getGridLayout()->rowCount()-1, 4, 2, 1);
+
+ QTreeWidgetItem* item = new QTreeWidgetItem(QStringList("") << "");
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ unitsTreeWidget->addTopLevelItem(item);
+
+ getTagComboBox()->hide();
+ organizationLabel->hide();
+ childWidgets << organizationLabel << organizationLineEdit << unitsTreeWidget;
+}
+
+bool QtVCardOrganizationField::isEmpty() const {
+ return organizationLineEdit->text().isEmpty() && unitsTreeWidget->model()->rowCount() != 0;
+}
+
+void QtVCardOrganizationField::setOrganization(const VCard::Organization& organization) {
+ organizationLineEdit->setText(P2QSTRING(organization.name));
+ unitsTreeWidget->clear();
+ foreach(std::string unit, organization.units) {
+ QTreeWidgetItem* item = new QTreeWidgetItem(QStringList(P2QSTRING(unit)) << "");
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ unitsTreeWidget->addTopLevelItem(item);
+ }
+}
+
+VCard::Organization QtVCardOrganizationField::getOrganization() const {
+ VCard::Organization organization;
+ organization.name = Q2PSTRING(organizationLineEdit->text());
+ for(int i=0; i < unitsTreeWidget->topLevelItemCount(); ++i) {
+ QTreeWidgetItem* row = unitsTreeWidget->topLevelItem(i);
+ if (!row->text(0).isEmpty()) {
+ organization.units.push_back(Q2PSTRING(row->text(0)));
+ }
+ }
+
+ QTreeWidgetItem* item = new QTreeWidgetItem(QStringList("") << "");
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ unitsTreeWidget->addTopLevelItem(item);
+
+ return organization;
+}
+
+void QtVCardOrganizationField::handleEditibleChanged(bool isEditable) {
+ if (organizationLineEdit) {
+ organizationLineEdit->setVisible(isEditable);
+ organizationLabel->setVisible(!isEditable);
+
+ if (!isEditable) {
+ QString label;
+ for(int i=0; i < unitsTreeWidget->topLevelItemCount(); ++i) {
+ QTreeWidgetItem* row = unitsTreeWidget->topLevelItem(i);
+ if (!row->text(0).isEmpty()) {
+ label += row->text(0) + ", ";
+ }
+ }
+ label += organizationLineEdit->text();
+ organizationLabel->setText(label);
+ }
+ }
+ if (unitsTreeWidget) unitsTreeWidget->setVisible(isEditable);
+}
+
+void QtVCardOrganizationField::handleItemChanged(QTreeWidgetItem *, int) {
+ bool hasEmptyRow = false;
+ QList<QTreeWidgetItem*> rows = unitsTreeWidget->findItems("", Qt::MatchFixedString);
+ foreach(QTreeWidgetItem* row, rows) {
+ if (row->text(0).isEmpty()) {
+ hasEmptyRow = true;
+ }
+ }
+
+ if (!hasEmptyRow) {
+ QTreeWidgetItem* item = new QTreeWidgetItem(QStringList("") << "");
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ unitsTreeWidget->addTopLevelItem(item);
+ }
+ getTagComboBox()->hide();
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardOrganizationField.h b/Swift/QtUI/QtVCardWidget/QtVCardOrganizationField.h
new file mode 100644
index 0000000..917e22a
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardOrganizationField.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include <QTreeWidget>
+
+#include "QtRemovableItemDelegate.h"
+#include "QtResizableLineEdit.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+
+namespace Swift {
+
+class QtVCardOrganizationField : public QtVCardGeneralField {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("Organization", UNLIMITED_INSTANCES, QtVCardOrganizationField)
+
+ QtVCardOrganizationField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardOrganizationField();
+
+ virtual bool isEmpty() const;
+
+ void setOrganization(const VCard::Organization& organization);
+ VCard::Organization getOrganization() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private slots:
+ void handleItemChanged(QTreeWidgetItem*, int);
+
+ private:
+ QLabel* organizationLabel;
+ QtResizableLineEdit* organizationLineEdit;
+ QTreeWidget* unitsTreeWidget;
+ QtRemovableItemDelegate* itemDelegate;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.cpp b/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.cpp
new file mode 100644
index 0000000..3ddc86b
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardPhotoAndNameFields.h"
+#include "ui_QtVCardPhotoAndNameFields.h"
+
+#include <QMenu>
+
+namespace Swift {
+
+QtVCardPhotoAndNameFields::QtVCardPhotoAndNameFields(QWidget* parent) :
+ QWidget(parent),
+ ui(new Ui::QtVCardPhotoAndNameFields) {
+ ui->setupUi(this);
+ ui->lineEditPREFIX->hide();
+ ui->lineEditMIDDLE->hide();
+ ui->lineEditSUFFIX->hide();
+ ui->lineEditFN->hide();
+ ui->lineEditNICKNAME->hide();
+ ui->labelFULLNAME->hide();
+
+#if QT_VERSION >= 0x040700
+ ui->lineEditFN->setPlaceholderText(tr("Formatted Name"));
+ ui->lineEditNICKNAME->setPlaceholderText(tr("Nickname"));
+ ui->lineEditPREFIX->setPlaceholderText(tr("Prefix"));
+ ui->lineEditGIVEN->setPlaceholderText(tr("Given Name"));
+ ui->lineEditMIDDLE->setPlaceholderText(tr("Middle Name"));
+ ui->lineEditFAMILY->setPlaceholderText(tr("Last Name"));
+ ui->lineEditSUFFIX->setPlaceholderText(tr("Suffix"));
+#endif
+
+ addFieldMenu = new QMenu("Name", this);
+
+ actionSignalMapper = new QSignalMapper(this);
+
+ connect(actionSignalMapper, SIGNAL(mapped(const QString &)), this, SLOT(showField(const QString &)));
+ prepareAddFieldMenu();
+}
+
+QtVCardPhotoAndNameFields::~QtVCardPhotoAndNameFields() {
+ delete ui;
+ delete actionSignalMapper;
+}
+
+bool QtVCardPhotoAndNameFields::isEditable() const {
+ return editable;
+}
+
+void QtVCardPhotoAndNameFields::setEditable(bool editable) {
+ this->editable = editable;
+
+ ui->avatarWidget->setEditable(editable);
+ ui->lineEditFN->setVisible(editable ? true : !ui->lineEditFN->text().isEmpty());
+ ui->lineEditFN->setEditable(editable);
+ ui->lineEditFN->setStyleSheet(editable ? "" : "QLineEdit {border: none; background-color: transparent;}");
+
+ ui->lineEditNICKNAME->setVisible(editable ? true : !ui->lineEditNICKNAME->text().isEmpty());
+ ui->lineEditNICKNAME->setEditable(editable);
+ ui->lineEditNICKNAME->setStyleSheet(editable ? "" : "QLineEdit {border: none; background-color: transparent;}");
+
+ // prefix given middle last suffix
+ ui->lineEditPREFIX->setVisible(editable);
+ ui->lineEditGIVEN->setVisible(editable);
+ ui->lineEditMIDDLE->setVisible(editable);
+ ui->lineEditFAMILY->setVisible(editable);
+ ui->lineEditSUFFIX->setVisible(editable);
+ ui->labelFULLNAME->setVisible(!editable);
+ ui->labelFULLNAME->setText( ui->lineEditPREFIX->text() + " " + ui->lineEditGIVEN->text() + " " +
+ ui->lineEditMIDDLE->text() + " " + ui->lineEditFAMILY->text() + " " + ui->lineEditSUFFIX->text());
+
+ prepareAddFieldMenu();
+}
+
+QMenu* QtVCardPhotoAndNameFields::getAddFieldMenu() const {
+ return addFieldMenu;
+}
+
+void QtVCardPhotoAndNameFields::setAvatar(const ByteArray &data, const std::string &type) {
+ ui->avatarWidget->setAvatar(data, type);
+}
+
+ByteArray QtVCardPhotoAndNameFields::getAvatarData() const {
+ return ui->avatarWidget->getAvatarData();
+}
+
+std::string QtVCardPhotoAndNameFields::getAvatarType() const {
+ return ui->avatarWidget->getAvatarType();
+}
+
+void QtVCardPhotoAndNameFields::setFormattedName(const QString formattedName) {
+ ui->lineEditFN->setText(formattedName);
+}
+
+QString QtVCardPhotoAndNameFields::getFormattedName() const {
+ return ui->lineEditFN->text();
+}
+
+void QtVCardPhotoAndNameFields::setNickname(const QString nickname) {
+ ui->lineEditNICKNAME->setText(nickname);
+}
+
+QString QtVCardPhotoAndNameFields::getNickname() const {
+ return ui->lineEditNICKNAME->text();
+}
+
+void QtVCardPhotoAndNameFields::setPrefix(const QString prefix) {
+ ui->lineEditPREFIX->setText(prefix);
+}
+
+QString QtVCardPhotoAndNameFields::getPrefix() const {
+ return ui->lineEditPREFIX->text();
+}
+
+void QtVCardPhotoAndNameFields::setGivenName(const QString givenName) {
+ ui->lineEditGIVEN->setText(givenName);
+}
+
+QString QtVCardPhotoAndNameFields::getGivenName() const {
+ return ui->lineEditGIVEN->text();
+}
+
+void QtVCardPhotoAndNameFields::setMiddleName(const QString middleName) {
+ ui->lineEditMIDDLE->setText(middleName);
+}
+
+QString QtVCardPhotoAndNameFields::getMiddleName() const {
+ return ui->lineEditMIDDLE->text();
+}
+
+void QtVCardPhotoAndNameFields::setFamilyName(const QString familyName) {
+ ui->lineEditFAMILY->setText(familyName);
+}
+
+QString QtVCardPhotoAndNameFields::getFamilyName() const {
+ return ui->lineEditFAMILY->text();
+}
+
+void QtVCardPhotoAndNameFields::setSuffix(const QString suffix) {
+ ui->lineEditSUFFIX->setText(suffix);
+}
+
+QString QtVCardPhotoAndNameFields::getSuffix() const {
+ return ui->lineEditSUFFIX->text();
+}
+
+void QtVCardPhotoAndNameFields::prepareAddFieldMenu() {
+ foreach(QAction* action, addFieldMenu->actions()) {
+ actionSignalMapper->removeMappings(action);
+ }
+
+ addFieldMenu->clear();
+ foreach(QObject* obj, children()) {
+ QLineEdit* lineEdit = 0;
+ if (!(lineEdit = dynamic_cast<QLineEdit*>(obj))) continue;
+ if (lineEdit->isHidden()) {
+#if QT_VERSION >= 0x040700
+ QAction* action = addFieldMenu->addAction(QString("Add ") + lineEdit->placeholderText(), actionSignalMapper, SLOT(map()));
+#else
+ QAction* action = addFieldMenu->addAction(QString("Add ") + lineEdit->toolTip(), actionSignalMapper, SLOT(map()));
+#endif
+ actionSignalMapper->setMapping(action, lineEdit->objectName());
+ }
+ }
+}
+
+void QtVCardPhotoAndNameFields::showField(const QString& widgetName) {
+ QLineEdit* lineEditToShow = findChild<QLineEdit*>(widgetName);
+ if (lineEditToShow) lineEditToShow->show();
+
+ prepareAddFieldMenu();
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.h b/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.h
new file mode 100644
index 0000000..f279701
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QMenu>
+#include <QSignalMapper>
+#include <QWidget>
+#include <Swiften/Base/ByteArray.h>
+
+namespace Ui {
+ class QtVCardPhotoAndNameFields;
+}
+
+
+namespace Swift {
+
+ class QtVCardPhotoAndNameFields : public QWidget {
+ Q_OBJECT
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable)
+
+ public:
+ explicit QtVCardPhotoAndNameFields(QWidget* parent = 0);
+ ~QtVCardPhotoAndNameFields();
+
+ bool isEditable() const;
+ void setEditable(bool);
+
+ QMenu* getAddFieldMenu() const;
+
+ void setAvatar(const ByteArray& data, const std::string& type);
+ ByteArray getAvatarData() const;
+ std::string getAvatarType() const;
+
+ void setFormattedName(const QString formattedName);
+ QString getFormattedName() const;
+
+ void setNickname(const QString nickname);
+ QString getNickname() const;
+
+ void setPrefix(const QString prefix);
+ QString getPrefix() const;
+
+ void setGivenName(const QString givenName);
+ QString getGivenName() const;
+
+ void setMiddleName(const QString middleName);
+ QString getMiddleName() const;
+
+ void setFamilyName(const QString familyName);
+ QString getFamilyName() const;
+
+ void setSuffix(const QString suffix);
+ QString getSuffix() const;
+
+ public slots:
+ void showField(const QString& widgetName);
+
+ private:
+ void prepareAddFieldMenu();
+
+ private:
+ Ui::QtVCardPhotoAndNameFields* ui;
+ bool editable;
+
+ QMenu* addFieldMenu;
+ QSignalMapper* actionSignalMapper;
+ };
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.ui b/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.ui
new file mode 100644
index 0000000..04da2bc
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardPhotoAndNameFields.ui
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtVCardPhotoAndNameFields</class>
+ <widget class="QWidget" name="QtVCardPhotoAndNameFields">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>522</width>
+ <height>81</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0" rowminimumheight="0,0,0,0,0">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>5</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0" rowspan="5">
+ <widget class="Swift::QtAvatarWidget" name="avatarWidget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" stdset="0">
+ <string/>
+ </property>
+ <property name="flat" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="Swift::QtResizableLineEdit" name="lineEditFN">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>Formatted Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="Swift::QtResizableLineEdit" name="lineEditNICKNAME">
+ <property name="toolTip">
+ <string>Nickname</string>
+ </property>
+ <property name="frame">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="labelFULLNAME">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Swift::QtResizableLineEdit" name="lineEditPREFIX">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Prefix</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Swift::QtResizableLineEdit" name="lineEditGIVEN">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Given Name</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Swift::QtResizableLineEdit" name="lineEditMIDDLE">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Middle Name</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="frame">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Swift::QtResizableLineEdit" name="lineEditFAMILY">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Last Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Swift::QtResizableLineEdit" name="lineEditSUFFIX">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Suffix</string>
+ </property>
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Swift::QtResizableLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>QtResizableLineEdit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>Swift::QtAvatarWidget</class>
+ <extends>QWidget</extends>
+ <header>Swift/QtUI/QtAvatarWidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardRoleField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardRoleField.cpp
new file mode 100644
index 0000000..8af4e64
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardRoleField.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardRoleField.h"
+
+#include <QGridLayout>
+#include <boost/algorithm/string.hpp>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardRoleField::QtVCardRoleField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("Role"), false, false) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardRoleField::~QtVCardRoleField() {
+}
+
+void QtVCardRoleField::setupContentWidgets() {
+ roleLineEdit = new QtResizableLineEdit(this);
+ getGridLayout()->addWidget(roleLineEdit, getGridLayout()->rowCount()-1, 2, 1, 2, Qt::AlignVCenter);
+ getTagComboBox()->hide();
+ childWidgets << roleLineEdit;
+}
+
+bool QtVCardRoleField::isEmpty() const {
+ return roleLineEdit->text().isEmpty();
+}
+
+void QtVCardRoleField::setRole(const std::string& role) {
+ roleLineEdit->setText(P2QSTRING(role));
+}
+
+std::string QtVCardRoleField::getRole() const {
+ return Q2PSTRING(roleLineEdit->text());
+}
+
+void QtVCardRoleField::handleEditibleChanged(bool isEditable) {
+ if (roleLineEdit) {
+ roleLineEdit->setEditable(isEditable);
+ roleLineEdit->setStyleSheet(isEditable ? "" : "QLineEdit { border: none; background: transparent; }");
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardRoleField.h b/Swift/QtUI/QtVCardWidget/QtVCardRoleField.h
new file mode 100644
index 0000000..3c819ed
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardRoleField.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include "QtResizableLineEdit.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+
+namespace Swift {
+
+class QtVCardRoleField : public QtVCardGeneralField {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("Role", UNLIMITED_INSTANCES, QtVCardRoleField)
+
+ QtVCardRoleField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardRoleField();
+
+ virtual bool isEmpty() const;
+
+ void setRole(const std::string& role);
+ std::string getRole() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QtResizableLineEdit* roleLineEdit;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardTelephoneField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardTelephoneField.cpp
new file mode 100644
index 0000000..ee93c01
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardTelephoneField.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardTelephoneField.h"
+
+#include <QGridLayout>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardTelephoneField::QtVCardTelephoneField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("Telephone")) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardTelephoneField::~QtVCardTelephoneField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardTelephoneField::setupContentWidgets() {
+ telephoneLineEdit = new QtResizableLineEdit(this);
+#if QT_VERSION >= 0x040700
+ telephoneLineEdit->setPlaceholderText(tr("0118 999 881 999 119 7253"));
+#endif
+ getGridLayout()->addWidget(telephoneLineEdit, getGridLayout()->rowCount()-1, 2, 1, 2, Qt::AlignVCenter);
+ setTabOrder(telephoneLineEdit, getTagComboBox());
+ QtVCardHomeWork::setTagComboBox(getTagComboBox());
+
+ getTagComboBox()->addTag("voice", QObject::tr("Voice"));
+ getTagComboBox()->addTag("fax", QObject::tr("Fax"));
+ getTagComboBox()->addTag("pager", QObject::tr("Pager"));
+ getTagComboBox()->addTag("msg", QObject::tr("Voice Messaging"));
+ getTagComboBox()->addTag("cell", QObject::tr("Cell"));
+ getTagComboBox()->addTag("video", QObject::tr("Video"));
+ getTagComboBox()->addTag("bbs", QObject::tr("Bulletin Board System"));
+ getTagComboBox()->addTag("modem", QObject::tr("Modem"));
+ getTagComboBox()->addTag("isdn", QObject::tr("ISDN"));
+ getTagComboBox()->addTag("pcs", QObject::tr("Personal Communication Services"));
+
+ childWidgets << telephoneLineEdit;
+}
+
+bool QtVCardTelephoneField::isEmpty() const {
+ return telephoneLineEdit->text().isEmpty();
+}
+
+void QtVCardTelephoneField::setTelephone(const VCard::Telephone& telephone) {
+ setPreferred(telephone.isPreferred);
+ setHome(telephone.isHome);
+ setWork(telephone.isWork);
+
+ telephoneLineEdit->setText(P2QSTRING(telephone.number));
+
+ getTagComboBox()->setTag("voice", telephone.isVoice);
+ getTagComboBox()->setTag("fax", telephone.isFax);
+ getTagComboBox()->setTag("pager", telephone.isPager);
+ getTagComboBox()->setTag("msg", telephone.isMSG);
+ getTagComboBox()->setTag("cell", telephone.isCell);
+ getTagComboBox()->setTag("video", telephone.isVideo);
+ getTagComboBox()->setTag("bbs", telephone.isBBS);
+ getTagComboBox()->setTag("modem", telephone.isModem);
+ getTagComboBox()->setTag("isdn", telephone.isISDN);
+ getTagComboBox()->setTag("pcs", telephone.isPCS);
+}
+
+VCard::Telephone QtVCardTelephoneField::getTelephone() const {
+ VCard::Telephone telephone;
+
+ telephone.number = Q2PSTRING(telephoneLineEdit->text());
+
+ telephone.isPreferred = getPreferred();
+ telephone.isHome = getHome();
+ telephone.isWork = getWork();
+
+ telephone.isVoice = getTagComboBox()->isTagSet("voice");
+ telephone.isFax = getTagComboBox()->isTagSet("fax");
+ telephone.isPager = getTagComboBox()->isTagSet("pager");
+ telephone.isMSG = getTagComboBox()->isTagSet("msg");
+ telephone.isCell = getTagComboBox()->isTagSet("cell");
+ telephone.isVideo = getTagComboBox()->isTagSet("video");
+ telephone.isBBS = getTagComboBox()->isTagSet("bbs");
+ telephone.isModem = getTagComboBox()->isTagSet("modem");
+ telephone.isISDN = getTagComboBox()->isTagSet("isdn");
+ telephone.isPCS = getTagComboBox()->isTagSet("pcs");
+
+ return telephone;
+}
+
+void QtVCardTelephoneField::handleEditibleChanged(bool isEditable) {
+ if (telephoneLineEdit) {
+ telephoneLineEdit->setEditable(isEditable);
+ telephoneLineEdit->setStyleSheet(isEditable ? "" : "QLineEdit { border: none; background: transparent; }");
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardTelephoneField.h b/Swift/QtUI/QtVCardWidget/QtVCardTelephoneField.h
new file mode 100644
index 0000000..b433e3c
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardTelephoneField.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include "QtResizableLineEdit.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+#include "QtVCardHomeWork.h"
+
+namespace Swift {
+
+class QtVCardTelephoneField : public QtVCardGeneralField, public QtVCardHomeWork {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("Telephone", UNLIMITED_INSTANCES, QtVCardTelephoneField)
+
+ QtVCardTelephoneField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardTelephoneField();
+
+ virtual bool isEmpty() const;
+
+ void setTelephone(const VCard::Telephone& telephone);
+ VCard::Telephone getTelephone() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QtResizableLineEdit* telephoneLineEdit;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardTitleField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardTitleField.cpp
new file mode 100644
index 0000000..aac4e31
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardTitleField.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardTitleField.h"
+
+#include <QGridLayout>
+#include <boost/algorithm/string.hpp>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardTitleField::QtVCardTitleField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("Title"), false, false) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardTitleField::~QtVCardTitleField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardTitleField::setupContentWidgets() {
+ titleLineEdit = new QtResizableLineEdit(this);
+ getGridLayout()->addWidget(titleLineEdit, getGridLayout()->rowCount()-1, 2, 1, 2, Qt::AlignVCenter);
+ getTagComboBox()->hide();
+ childWidgets << titleLineEdit;
+}
+
+bool QtVCardTitleField::isEmpty() const {
+ return titleLineEdit->text().isEmpty();
+}
+
+void QtVCardTitleField::setTitle(const std::string& title) {
+ titleLineEdit->setText(P2QSTRING(title));
+}
+
+std::string QtVCardTitleField::getTitle() const {
+ return Q2PSTRING(titleLineEdit->text());
+}
+
+void QtVCardTitleField::handleEditibleChanged(bool isEditable) {
+ if (titleLineEdit) {
+ titleLineEdit->setEditable(isEditable);
+ titleLineEdit->setStyleSheet(isEditable ? "" : "QLineEdit { border: none; background: transparent; }");
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardTitleField.h b/Swift/QtUI/QtVCardWidget/QtVCardTitleField.h
new file mode 100644
index 0000000..28dc603
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardTitleField.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include "QtResizableLineEdit.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+
+namespace Swift {
+
+class QtVCardTitleField : public QtVCardGeneralField {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("Title", UNLIMITED_INSTANCES, QtVCardTitleField)
+
+ QtVCardTitleField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardTitleField();
+
+ virtual bool isEmpty() const;
+
+ void setTitle(const std::string& title);
+ std::string getTitle() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QtResizableLineEdit* titleLineEdit;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardURLField.cpp b/Swift/QtUI/QtVCardWidget/QtVCardURLField.cpp
new file mode 100644
index 0000000..0b6f0c1
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardURLField.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardURLField.h"
+
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QTextDocument>
+#include <boost/algorithm/string.hpp>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtVCardURLField::QtVCardURLField(QWidget* parent, QGridLayout *layout, bool editable) :
+ QtVCardGeneralField(parent, layout, editable, layout->rowCount(), tr("URL"), false, false) {
+ connect(this, SIGNAL(editableChanged(bool)), SLOT(handleEditibleChanged(bool)));
+}
+
+QtVCardURLField::~QtVCardURLField() {
+ disconnect(this, SLOT(handleEditibleChanged(bool)));
+}
+
+void QtVCardURLField::setupContentWidgets() {
+ urlLabel = new QLabel(this);
+ urlLabel->setOpenExternalLinks(true);
+ urlLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
+ urlLineEdit = new QtResizableLineEdit(this);
+
+ QHBoxLayout* urlLayout = new QHBoxLayout();
+ urlLayout->addWidget(urlLabel);
+ urlLayout->addWidget(urlLineEdit);
+
+ getGridLayout()->addLayout(urlLayout, getGridLayout()->rowCount()-1, 2, 1, 2, Qt::AlignVCenter);
+ getTagComboBox()->hide();
+ urlLabel->hide();
+ childWidgets << urlLabel << urlLineEdit;
+}
+
+bool QtVCardURLField::isEmpty() const {
+ return urlLineEdit->text().isEmpty();
+}
+
+void QtVCardURLField::setURL(const std::string& url) {
+ urlLineEdit->setText(P2QSTRING(url));
+}
+
+std::string QtVCardURLField::getURL() const {
+ return Q2PSTRING(urlLineEdit->text());
+}
+
+void QtVCardURLField::handleEditibleChanged(bool isEditable) {
+ if (isEditable) {
+ if (urlLineEdit) urlLineEdit->show();
+ if (urlLabel) urlLabel->hide();
+ } else {
+ if (urlLineEdit) urlLineEdit->hide();
+ if (urlLabel) {
+ urlLabel->setText(QString("<a href=\"%1\">%1</a>").arg(Qt::escape(urlLineEdit->text())));
+ urlLabel->show();
+ }
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardURLField.h b/Swift/QtUI/QtVCardWidget/QtVCardURLField.h
new file mode 100644
index 0000000..2c011d8
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardURLField.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Elements/VCard.h>
+
+#include "QtResizableLineEdit.h"
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+
+namespace Swift {
+
+class QtVCardURLField : public QtVCardGeneralField {
+ Q_OBJECT
+
+ public:
+ GENERIC_QT_VCARD_FIELD_INFO("URL", UNLIMITED_INSTANCES, QtVCardURLField)
+
+ QtVCardURLField(QWidget* parent = 0, QGridLayout* layout = 0, bool editable = false);
+ virtual ~QtVCardURLField();
+
+ virtual bool isEmpty() const;
+
+ void setURL(const std::string& url);
+ std::string getURL() const;
+
+ protected:
+ virtual void setupContentWidgets();
+
+ public slots:
+ void handleEditibleChanged(bool isEditable);
+
+ private:
+ QLabel* urlLabel;
+ QtResizableLineEdit* urlLineEdit;
+};
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp b/Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp
new file mode 100644
index 0000000..1c80fa4
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "QtVCardWidget.h"
+#include "ui_QtVCardWidget.h"
+
+#include <QDebug>
+#include <QLineEdit>
+#include <QMenu>
+
+#include "QtVCardAddressField.h"
+#include "QtVCardAddressLabelField.h"
+#include "QtVCardBirthdayField.h"
+#include "QtVCardDescriptionField.h"
+#include "QtVCardGeneralField.h"
+#include "QtVCardInternetEMailField.h"
+#include "QtVCardJIDField.h"
+#include "QtVCardOrganizationField.h"
+#include "QtVCardRoleField.h"
+#include "QtVCardTelephoneField.h"
+#include "QtVCardTitleField.h"
+#include "QtVCardURLField.h"
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+#include <Swiften/Base/Log.h>
+
+namespace Swift {
+
+QtVCardWidget::QtVCardWidget(QWidget* parent) :
+ QWidget(parent),
+ ui(new ::Ui::QtVCardWidget) {
+ ui->setupUi(this);
+
+ ui->cardFields->setColumnStretch(0,0);
+ ui->cardFields->setColumnStretch(1,0);
+ ui->cardFields->setColumnStretch(2,2);
+ ui->cardFields->setColumnStretch(3,1);
+ ui->cardFields->setColumnStretch(4,2);
+ menu = new QMenu(this);
+
+ menu->addMenu(ui->photoAndName->getAddFieldMenu());
+ ui->toolButton->setMenu(menu);
+
+ addFieldType(menu, boost::make_shared<QtVCardInternetEMailField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardTelephoneField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardAddressField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardAddressLabelField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardBirthdayField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardJIDField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardDescriptionField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardRoleField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardTitleField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardOrganizationField::FieldInfo>());
+ addFieldType(menu, boost::make_shared<QtVCardURLField::FieldInfo>());
+
+ setEditable(false);
+}
+
+QtVCardWidget::~QtVCardWidget() {
+ delete ui;
+}
+
+bool QtVCardWidget::isEditable() const {
+ return editable;
+}
+
+void QtVCardWidget::setEditable(bool editable) {
+ this->editable = editable;
+
+ ui->photoAndName->setProperty("editable", QVariant(editable));
+
+ foreach(QtVCardGeneralField* field, fields) {
+ field->setEditable(editable);
+ }
+
+ if (editable) {
+ ui->toolButton->show();
+ //if ((findChild<QtVCardBirthdayField*>() == 0)) {
+ //}
+ } else {
+ ui->toolButton->hide();
+ }
+
+ editableChanged(editable);
+}
+
+void QtVCardWidget::setVCard(VCard::ref vcard) {
+ SWIFT_LOG(debug) << std::endl;
+ clearFields();
+ this->vcard = vcard;
+ ui->photoAndName->setFormattedName(P2QSTRING(vcard->getFullName()));
+ ui->photoAndName->setNickname(P2QSTRING(vcard->getNickname()));
+ ui->photoAndName->setPrefix(P2QSTRING(vcard->getPrefix()));
+ ui->photoAndName->setGivenName(P2QSTRING(vcard->getGivenName()));
+ ui->photoAndName->setMiddleName(P2QSTRING(vcard->getMiddleName()));
+ ui->photoAndName->setFamilyName(P2QSTRING(vcard->getFamilyName()));
+ ui->photoAndName->setSuffix(P2QSTRING(vcard->getSuffix()));
+ ui->photoAndName->setAvatar(vcard->getPhoto(), vcard->getPhotoType());
+
+ foreach (const VCard::EMailAddress& address, vcard->getEMailAddresses()) {
+ if (address.isInternet) {
+ QtVCardInternetEMailField* internetEmailField = new QtVCardInternetEMailField(this, ui->cardFields);
+ internetEmailField->initialize();
+ internetEmailField->setInternetEMailAddress(address);
+ appendField(internetEmailField);
+ }
+ }
+
+ foreach (const VCard::Telephone& telephone, vcard->getTelephones()) {
+ QtVCardTelephoneField* telField = new QtVCardTelephoneField(this, ui->cardFields);
+ telField->initialize();
+ telField->setTelephone(telephone);
+ appendField(telField);
+ }
+
+ foreach (const VCard::Address& address, vcard->getAddresses()) {
+ QtVCardAddressField* addressField = new QtVCardAddressField(this, ui->cardFields);
+ addressField->initialize();
+ addressField->setAddress(address);
+ appendField(addressField);
+ }
+
+ foreach (const VCard::AddressLabel& label, vcard->getAddressLabels()) {
+ QtVCardAddressLabelField* addressLabelField = new QtVCardAddressLabelField(this, ui->cardFields);
+ addressLabelField->initialize();
+ addressLabelField->setAddressLabel(label);
+ appendField(addressLabelField);
+ }
+
+ if (!vcard->getBirthday().is_not_a_date_time()) {
+ QtVCardBirthdayField* bdayField = new QtVCardBirthdayField(this, ui->cardFields);
+ bdayField->initialize();
+ bdayField->setBirthday(vcard->getBirthday());
+ appendField(bdayField);
+ }
+
+ foreach (const JID& jid, vcard->getJIDs()) {
+ QtVCardJIDField* jidField = new QtVCardJIDField(this, ui->cardFields);
+ jidField->initialize();
+ jidField->setJID(jid);
+ appendField(jidField);
+ }
+
+ if (!vcard->getDescription().empty()) {
+ QtVCardDescriptionField* descField = new QtVCardDescriptionField(this, ui->cardFields);
+ descField->initialize();
+ descField->setDescription(vcard->getDescription());
+ appendField(descField);
+ }
+
+ foreach (const VCard::Organization& org, vcard->getOrganizations()) {
+ QtVCardOrganizationField* orgField = new QtVCardOrganizationField(this, ui->cardFields);
+ orgField->initialize();
+ orgField->setOrganization(org);
+ appendField(orgField);
+ }
+
+ foreach (const std::string& role, vcard->getRoles()) {
+ QtVCardRoleField* roleField = new QtVCardRoleField(this, ui->cardFields);
+ roleField->initialize();
+ roleField->setRole(role);
+ appendField(roleField);
+ }
+
+ foreach (const std::string& title, vcard->getTitles()) {
+ QtVCardTitleField* titleField = new QtVCardTitleField(this, ui->cardFields);
+ titleField->initialize();
+ titleField->setTitle(title);
+ appendField(titleField);
+ }
+
+ foreach (const std::string& url, vcard->getURLs()) {
+ QtVCardURLField* urlField = new QtVCardURLField(this, ui->cardFields);
+ urlField->initialize();
+ urlField->setURL(url);
+ appendField(urlField);
+ }
+
+ setEditable(editable);
+}
+
+VCard::ref QtVCardWidget::getVCard() {
+ SWIFT_LOG(debug) << std::endl;
+ clearEmptyFields();
+ vcard->setFullName(Q2PSTRING(ui->photoAndName->getFormattedName()));
+ vcard->setNickname(Q2PSTRING(ui->photoAndName->getNickname()));
+ vcard->setPrefix(Q2PSTRING(ui->photoAndName->getPrefix()));
+ vcard->setGivenName(Q2PSTRING(ui->photoAndName->getGivenName()));
+ vcard->setMiddleName(Q2PSTRING(ui->photoAndName->getMiddleName()));
+ vcard->setFamilyName(Q2PSTRING(ui->photoAndName->getFamilyName()));
+ vcard->setSuffix(Q2PSTRING(ui->photoAndName->getSuffix()));
+ vcard->setPhoto(ui->photoAndName->getAvatarData());
+ vcard->setPhotoType(ui->photoAndName->getAvatarType());
+
+ vcard->clearEMailAddresses();
+ vcard->clearJIDs();
+ vcard->clearURLs();
+ vcard->clearTelephones();
+ vcard->clearRoles();
+ vcard->clearTitles();
+ vcard->clearOrganizations();
+ vcard->clearAddresses();
+ vcard->clearAddressLabels();
+
+
+ QtVCardBirthdayField* bdayField = NULL;
+ QtVCardDescriptionField* descriptionField = NULL;
+
+ foreach(QtVCardGeneralField* field, fields) {
+ QtVCardInternetEMailField* emailField;
+ if ((emailField = dynamic_cast<QtVCardInternetEMailField*>(field))) {
+ vcard->addEMailAddress(emailField->getInternetEMailAddress());
+ continue;
+ }
+
+ QtVCardTelephoneField* telephoneField;
+ if ((telephoneField = dynamic_cast<QtVCardTelephoneField*>(field))) {
+ vcard->addTelephone(telephoneField->getTelephone());
+ continue;
+ }
+
+ QtVCardAddressField* addressField;
+ if ((addressField = dynamic_cast<QtVCardAddressField*>(field))) {
+ vcard->addAddress(addressField->getAddress());
+ continue;
+ }
+
+ QtVCardAddressLabelField* addressLabelField;
+ if ((addressLabelField = dynamic_cast<QtVCardAddressLabelField*>(field))) {
+ vcard->addAddressLabel(addressLabelField->getAddressLabel());
+ continue;
+ }
+
+ if ((bdayField = dynamic_cast<QtVCardBirthdayField*>(field))) {
+ continue;
+ }
+
+ QtVCardJIDField* jidField;
+ if ((jidField = dynamic_cast<QtVCardJIDField*>(field))) {
+ vcard->addJID(jidField->getJID());
+ continue;
+ }
+
+ if ((descriptionField = dynamic_cast<QtVCardDescriptionField*>(field))) {
+ continue;
+ }
+
+ QtVCardOrganizationField* orgField;
+ if ((orgField = dynamic_cast<QtVCardOrganizationField*>(field))) {
+ vcard->addOrganization(orgField->getOrganization());
+ continue;
+ }
+
+ QtVCardRoleField* roleField;
+ if ((roleField = dynamic_cast<QtVCardRoleField*>(field))) {
+ vcard->addRole(roleField->getRole());
+ continue;
+ }
+
+ QtVCardTitleField* titleField;
+ if ((titleField = dynamic_cast<QtVCardTitleField*>(field))) {
+ vcard->addTitle(titleField->getTitle());
+ continue;
+ }
+
+ QtVCardURLField* urlField;
+ if ((urlField = dynamic_cast<QtVCardURLField*>(field))) {
+ vcard->addURL(urlField->getURL());
+ continue;
+ }
+ }
+
+ if (bdayField) {
+ vcard->setBirthday(bdayField->getBirthday());
+ } else {
+ vcard->setBirthday(boost::posix_time::ptime());
+ }
+
+ if (descriptionField) {
+ vcard->setDescription(descriptionField->getDescription());
+ } else {
+ vcard->setDescription("");
+ }
+
+ return vcard;
+}
+
+void QtVCardWidget::addField() {
+ QAction* action = NULL;
+ if ((action = dynamic_cast<QAction*>(sender()))) {
+ boost::shared_ptr<QtVCardFieldInfo> fieldInfo = actionFieldInfo[action];
+ QWidget* newField = fieldInfo->createFieldInstance(this, ui->cardFields, true);
+ QtVCardGeneralField* newGeneralField = dynamic_cast<QtVCardGeneralField*>(newField);
+ if (newGeneralField) {
+ newGeneralField->initialize();
+ }
+ appendField(newGeneralField);
+ }
+}
+
+void QtVCardWidget::removeField(QtVCardGeneralField *field) {
+ fields.remove(field);
+ delete field;
+}
+
+void QtVCardWidget::addFieldType(QMenu* menu, boost::shared_ptr<QtVCardFieldInfo> fieldType) {
+ QAction* action = new QAction(tr("Add ") + fieldType->getMenuName(), this);
+ actionFieldInfo[action] = fieldType;
+ connect(action, SIGNAL(triggered()), this, SLOT(addField()));
+ menu->addAction(action);
+}
+
+int QtVCardWidget::fieldTypeInstances(boost::shared_ptr<QtVCardFieldInfo> fieldType) {
+ int instances = 0;
+ for (int n = 0; n < ui->cardFields->count(); n++) {
+ if (fieldType->testInstance(ui->cardFields->itemAt(n)->widget())) instances++;
+ }
+ return instances;
+}
+
+void layoutDeleteChildren(QLayout *layout) {
+ while(layout->count() > 0) {
+ QLayoutItem* child;
+ if ((child = layout->takeAt(0)) != 0) {
+ if (child->layout()) {
+ layoutDeleteChildren(child->layout());
+ }
+ delete child->widget();
+ delete child;
+ }
+ }
+}
+
+void QtVCardWidget::clearFields() {
+ foreach(QtVCardGeneralField* field, fields) {
+ delete field;
+ }
+ fields.clear();
+
+ assert(ui->cardFields->count() >= 0);
+ layoutDeleteChildren(ui->cardFields);
+}
+
+void QtVCardWidget::clearEmptyFields() {
+ std::vector<QtVCardGeneralField*> items_to_remove;
+ foreach (QtVCardGeneralField* field, fields) {
+ if (field->property("empty").isValid() && field->property("empty").toBool()) {
+ ui->cardFields->removeWidget(field);
+ items_to_remove.push_back(field);
+ delete field;
+ }
+ }
+
+ foreach(QtVCardGeneralField* field, items_to_remove) {
+ fields.remove(field);
+ }
+}
+
+void QtVCardWidget::appendField(QtVCardGeneralField *field) {
+ connect(field, SIGNAL(deleteField(QtVCardGeneralField*)), SLOT(removeField(QtVCardGeneralField*)));
+ fields.push_back(field);
+}
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardWidget.h b/Swift/QtUI/QtVCardWidget/QtVCardWidget.h
new file mode 100644
index 0000000..07f528d
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardWidget.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+#include <Swiften/Elements/VCard.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include "QtVCardFieldInfo.h"
+#include "QtVCardGeneralField.h"
+#include "QtVCardPhotoAndNameFields.h"
+
+namespace Ui {
+ class QtVCardWidget;
+}
+
+namespace Swift {
+
+ class QtVCardWidget : public QWidget {
+ Q_OBJECT
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable)
+
+ public :
+ explicit QtVCardWidget(QWidget* parent = 0);
+ ~QtVCardWidget();
+
+ bool isEditable() const;
+ void setEditable(bool);
+
+ void setVCard(VCard::ref vcard);
+ VCard::ref getVCard();
+
+ signals:
+ void editableChanged(bool editable);
+
+ private slots:
+ void addField();
+ void removeField(QtVCardGeneralField* field);
+
+ private:
+ void addFieldType(QMenu*, boost::shared_ptr<QtVCardFieldInfo>);
+ int fieldTypeInstances(boost::shared_ptr<QtVCardFieldInfo>);
+ void clearFields();
+ void clearEmptyFields();
+ void appendField(QtVCardGeneralField* field);
+
+ private:
+ VCard::ref vcard;
+ Ui::QtVCardWidget* ui;
+ bool editable;
+ QMenu* menu;
+ std::list<QtVCardGeneralField*> fields;
+ std::map<QAction*, boost::shared_ptr<QtVCardFieldInfo> > actionFieldInfo;
+ };
+
+}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardWidget.ui b/Swift/QtUI/QtVCardWidget/QtVCardWidget.ui
new file mode 100644
index 0000000..eae1006
--- /dev/null
+++ b/Swift/QtUI/QtVCardWidget/QtVCardWidget.ui
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtVCardWidget</class>
+ <widget class="QWidget" name="QtVCardWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>535</width>
+ <height>126</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" rowstretch="1,0" columnstretch="1,0">
+ <property name="margin">
+ <number>5</number>
+ </property>
+ <item row="0" column="0" colspan="2">
+ <layout class="QVBoxLayout" name="card" stretch="0,0,1">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item>
+ <widget class="Swift::QtVCardPhotoAndNameFields" name="photoAndName" native="true"/>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>523</width>
+ <height>76</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinAndMaxSize</enum>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="cardFields">
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Preferred</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>1000</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <widget class="QToolButton" name="toolButton">
+ <property name="text">
+ <string>Add Field</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::NoArrow</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Swift::QtVCardPhotoAndNameFields</class>
+ <extends>QWidget</extends>
+ <header>QtVCardPhotoAndNameFields.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
index 5d26c46..12dc1e4 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
@@ -58,6 +58,7 @@ void QtOccupantListWidget::contextMenuEvent(QContextMenuEvent* event) {
case ChatWindow::MakeParticipant: text = tr("Make participant"); break;
case ChatWindow::MakeVisitor: text = tr("Remove voice"); break;
case ChatWindow::AddContact: text = tr("Add to contacts"); break;
+ case ChatWindow::ShowProfile: text = tr("Show profile"); break;
}
QAction* action = contextMenu.addAction(text);
actions[action] = availableAction;
diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp
index 1cf073b..b783ff6 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.cpp
+++ b/Swift/QtUI/Roster/QtRosterWidget.cpp
@@ -16,6 +16,7 @@
#include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h"
#include "Swift/Controllers/UIEvents/SendFileUIEvent.h"
#include "Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h"
+#include "Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h"
#include "QtContactEditWindow.h"
#include "Swift/Controllers/Roster/ContactRosterItem.h"
#include "Swift/Controllers/Roster/GroupRosterItem.h"
@@ -57,6 +58,7 @@ void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) {
if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) {
QAction* editContact = contextMenu.addAction(tr("Edit…"));
QAction* removeContact = contextMenu.addAction(tr("Remove"));
+ QAction* showProfileForContact = contextMenu.addAction(tr("Show Profile"));
#ifdef SWIFT_EXPERIMENTAL_FT
QAction* sendFile = NULL;
if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) {
@@ -78,6 +80,9 @@ void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) {
eventStream_->send(boost::make_shared<RemoveRosterItemUIEvent>(contact->getJID()));
}
}
+ else if (result == showProfileForContact) {
+ eventStream_->send(boost::make_shared<ShowProfileForRosterItemUIEvent>(contact->getJID()));
+ }
#ifdef SWIFT_EXPERIMENTAL_FT
else if (sendFile && result == sendFile) {
QString fileName = QFileDialog::getOpenFileName(this, tr("Send File"), "", tr("All Files (*);;"));
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index cd0ed57..4ab6792 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -24,7 +24,7 @@ myenv = env.Clone()
# Disable warnings that affect Qt
myenv["CXXFLAGS"] = filter(lambda x : x != "-Wfloat-equal", myenv["CXXFLAGS"])
if "clang" in env["CC"] :
- myenv.Append(CXXFLAGS = ["-Wno-float-equal", "-Wno-shorten-64-to-32", "-Wno-missing-prototypes", "-Wno-unreachable-code", "-Wno-disabled-macro-expansion", "-Wno-unused-private-field", "-Wno-extra-semi", "-Wno-duplicate-enum", "-Wno-missing-variable-declarations"])
+ myenv.Append(CXXFLAGS = ["-Wno-float-equal", "-Wno-shorten-64-to-32", "-Wno-missing-prototypes", "-Wno-unreachable-code", "-Wno-disabled-macro-expansion", "-Wno-unused-private-field", "-Wno-extra-semi", "-Wno-duplicate-enum", "-Wno-missing-variable-declarations", "-Wno-conversion"])
myenv.UseFlags(env["SWIFT_CONTROLLERS_FLAGS"])
myenv.UseFlags(env["SWIFTOOLS_FLAGS"])
@@ -175,6 +175,34 @@ sources = [
"QtURLValidator.cpp"
]
+# QtVCardWidget
+sources.extend([
+ "QtVCardWidget/QtCloseButton.cpp",
+ "QtVCardWidget/QtRemovableItemDelegate.cpp",
+ "QtVCardWidget/QtResizableLineEdit.cpp",
+ "QtVCardWidget/QtTagComboBox.cpp",
+ "QtVCardWidget/QtVCardHomeWork.cpp",
+ "QtVCardWidget/QtVCardAddressField.cpp",
+ "QtVCardWidget/QtVCardAddressLabelField.cpp",
+ "QtVCardWidget/QtVCardBirthdayField.cpp",
+ "QtVCardWidget/QtVCardDescriptionField.cpp",
+ "QtVCardWidget/QtVCardInternetEMailField.cpp",
+ "QtVCardWidget/QtVCardJIDField.cpp",
+ "QtVCardWidget/QtVCardOrganizationField.cpp",
+ "QtVCardWidget/QtVCardPhotoAndNameFields.cpp",
+ "QtVCardWidget/QtVCardRoleField.cpp",
+ "QtVCardWidget/QtVCardTelephoneField.cpp",
+ "QtVCardWidget/QtVCardTitleField.cpp",
+ "QtVCardWidget/QtVCardURLField.cpp",
+ "QtVCardWidget/QtVCardGeneralField.cpp",
+ "QtVCardWidget/QtVCardWidget.cpp"
+])
+
+myenv.Uic4("QtVCardWidget/QtVCardPhotoAndNameFields.ui")
+myenv.Uic4("QtVCardWidget/QtVCardWidget.ui")
+myenv.Uic4("QtProfileWindow.ui")
+
+
# Determine the version
myenv["SWIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift")
if env["PLATFORM"] == "win32" :
diff --git a/Swift/QtUI/Swift.qrc b/Swift/QtUI/Swift.qrc
index 39201da..934bd80 100644
--- a/Swift/QtUI/Swift.qrc
+++ b/Swift/QtUI/Swift.qrc
@@ -38,5 +38,7 @@
<file alias="emoticons/tongue.png">../resources/emoticons/tongue.png</file>
<file alias="emoticons/unhappy.png">../resources/emoticons/unhappy.png</file>
<file alias="emoticons/wink.png">../resources/emoticons/wink.png</file>
+ <file alias="icons/star-checked.png">../resources/icons/star-checked2.png</file>
+ <file alias="icons/star-unchecked.png">../resources/icons/star-unchecked2.png</file>
</qresource>
</RCC>
diff --git a/Swift/resources/icons/star-checked2.png b/Swift/resources/icons/star-checked2.png
new file mode 100644
index 0000000..2908534
--- /dev/null
+++ b/Swift/resources/icons/star-checked2.png
Binary files differ
diff --git a/Swift/resources/icons/star-checked2.svg b/Swift/resources/icons/star-checked2.svg
new file mode 100644
index 0000000..ea4d1da
--- /dev/null
+++ b/Swift/resources/icons/star-checked2.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="89.89167"
+ height="85.751091"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="star-checked2.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="7.9195959"
+ inkscape:cx="27.108144"
+ inkscape:cy="28.243526"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ showguides="false"
+ inkscape:snap-global="false"
+ fit-margin-top="0.6"
+ fit-margin-left="0.6"
+ fit-margin-right="0.6"
+ fit-margin-bottom="0.6"
+ inkscape:window-width="1440"
+ inkscape:window-height="852"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2987"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-114.63435,-344.09596)">
+ <path
+ sodipodi:type="star"
+ style="fill:#ffd700;fill-opacity:1;stroke:#444444;stroke-width:4;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2989"
+ sodipodi:sides="5"
+ sodipodi:cx="150"
+ sodipodi:cy="393.07648"
+ sodipodi:r1="44.498337"
+ sodipodi:r2="24.474085"
+ sodipodi:arg1="-0.32682665"
+ sodipodi:arg2="0.30149188"
+ inkscape:flatsided="false"
+ inkscape:rounded="0.05"
+ inkscape:randomized="0"
+ d="m 192.14286,378.79076 c 0.4588,1.35347 -18.34832,20.18852 -18.77269,21.55318 -0.42437,1.36466 4.38466,27.54365 3.23921,28.39825 -1.14545,0.85459 -24.87036,-11.21169 -26.29937,-11.19359 -1.429,0.0181 -24.84064,12.68151 -26.00737,11.85621 -1.16672,-0.8253 2.97759,-27.11772 2.51879,-28.47119 -0.4588,-1.35347 -19.73702,-19.70605 -19.31265,-21.07071 0.42437,-1.36466 26.71061,-5.54798 27.85606,-6.40257 1.14545,-0.8546 12.64249,-24.86053 14.0715,-24.87863 1.429,-0.0181 13.53048,23.68888 14.69721,24.51418 1.16672,0.82531 27.5505,4.3414 28.00931,5.69487 z"
+ inkscape:transform-center-x="0.015620988"
+ inkscape:transform-center-y="-4.2343566"
+ transform="matrix(0.99993351,0.01153134,-0.01153134,0.99993351,14.139118,-3.5976011)" />
+ </g>
+</svg>
diff --git a/Swift/resources/icons/star-unchecked2.png b/Swift/resources/icons/star-unchecked2.png
new file mode 100644
index 0000000..ee85d69
--- /dev/null
+++ b/Swift/resources/icons/star-unchecked2.png
Binary files differ
diff --git a/Swift/resources/icons/star-unchecked2.svg b/Swift/resources/icons/star-unchecked2.svg
new file mode 100644
index 0000000..4186d0e
--- /dev/null
+++ b/Swift/resources/icons/star-unchecked2.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="89.89167"
+ height="85.751091"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="star-unchecked2.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="7.9195959"
+ inkscape:cx="27.108141"
+ inkscape:cy="28.243523"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ showguides="false"
+ inkscape:snap-global="false"
+ fit-margin-top="0.6"
+ fit-margin-left="0.6"
+ fit-margin-right="0.6"
+ fit-margin-bottom="0.6"
+ inkscape:window-width="1440"
+ inkscape:window-height="852"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2987"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-114.63435,-344.09596)">
+ <path
+ sodipodi:type="star"
+ style="fill:#ffffff;fill-opacity:1;stroke:#444444;stroke-width:4;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2989"
+ sodipodi:sides="5"
+ sodipodi:cx="150"
+ sodipodi:cy="393.07648"
+ sodipodi:r1="44.498337"
+ sodipodi:r2="24.474085"
+ sodipodi:arg1="-0.32682665"
+ sodipodi:arg2="0.30149188"
+ inkscape:flatsided="false"
+ inkscape:rounded="0.05"
+ inkscape:randomized="0"
+ d="m 192.14286,378.79076 c 0.4588,1.35347 -18.34832,20.18852 -18.77269,21.55318 -0.42437,1.36466 4.38466,27.54365 3.23921,28.39825 -1.14545,0.85459 -24.87036,-11.21169 -26.29937,-11.19359 -1.429,0.0181 -24.84064,12.68151 -26.00737,11.85621 -1.16672,-0.8253 2.97759,-27.11772 2.51879,-28.47119 -0.4588,-1.35347 -19.73702,-19.70605 -19.31265,-21.07071 0.42437,-1.36466 26.71061,-5.54798 27.85606,-6.40257 1.14545,-0.8546 12.64249,-24.86053 14.0715,-24.87863 1.429,-0.0181 13.53048,23.68888 14.69721,24.51418 1.16672,0.82531 27.5505,4.3414 28.00931,5.69487 z"
+ inkscape:transform-center-x="0.015620988"
+ inkscape:transform-center-y="-4.2343566"
+ transform="matrix(0.99993351,0.01153134,-0.01153134,0.99993351,14.139118,-3.5976011)" />
+ </g>
+</svg>
diff --git a/Swiften/Elements/VCard.h b/Swiften/Elements/VCard.h
index f9822c9..84b6cfe 100644
--- a/Swiften/Elements/VCard.h
+++ b/Swiften/Elements/VCard.h
@@ -7,8 +7,10 @@
#pragma once
#include <boost/shared_ptr.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
#include <string>
+#include <Swiften/JID/JID.h>
#include <Swiften/Base/ByteArray.h>
#include <Swiften/Elements/Payload.h>
@@ -29,6 +31,71 @@ namespace Swift {
std::string address;
};
+ struct Telephone {
+ Telephone() : isHome(false), isWork(false), isVoice(false), isFax(false), isPager(false), isMSG(false), isCell(false),
+ isVideo(false), isBBS(false), isModem(false), isISDN(false), isPCS(false), isPreferred(false) {
+ }
+
+ bool isHome;
+ bool isWork;
+ bool isVoice;
+ bool isFax;
+ bool isPager;
+ bool isMSG;
+ bool isCell;
+ bool isVideo;
+ bool isBBS;
+ bool isModem;
+ bool isISDN;
+ bool isPCS;
+ bool isPreferred;
+ std::string number;
+ };
+
+ enum DeliveryType {
+ DomesticDelivery,
+ InternationalDelivery,
+ None
+ };
+
+ struct Address {
+ Address() : isHome(false), isWork(false), isPostal(false), isParcel(false), deliveryType(None), isPreferred(false) {
+ }
+
+ bool isHome;
+ bool isWork;
+ bool isPostal;
+ bool isParcel;
+ DeliveryType deliveryType;
+ bool isPreferred;
+
+ std::string poBox;
+ std::string addressExtension;
+ std::string street;
+ std::string locality;
+ std::string region;
+ std::string postalCode;
+ std::string country;
+ };
+
+ struct AddressLabel {
+ AddressLabel() : isHome(false), isWork(false), isPostal(false), isParcel(false), deliveryType(None), isPreferred(false) {
+ }
+
+ bool isHome;
+ bool isWork;
+ bool isPostal;
+ bool isParcel;
+ DeliveryType deliveryType;
+ bool isPreferred;
+ std::vector<std::string> lines;
+ };
+
+ struct Organization {
+ std::string name;
+ std::vector<std::string> units;
+ };
+
VCard() {}
void setVersion(const std::string& version) { version_ = version; }
@@ -78,8 +145,124 @@ namespace Swift {
emailAddresses_.push_back(email);
}
+ void clearEMailAddresses() {
+ emailAddresses_.clear();
+ }
+
EMailAddress getPreferredEMailAddress() const;
+ void setBirthday(const boost::posix_time::ptime& birthday) {
+ birthday_ = birthday;
+ }
+
+ const boost::posix_time::ptime& getBirthday() const {
+ return birthday_;
+ }
+
+ const std::vector<Telephone>& getTelephones() const {
+ return telephones_;
+ }
+
+ void addTelephone(const Telephone& phone) {
+ telephones_.push_back(phone);
+ }
+
+ void clearTelephones() {
+ telephones_.clear();
+ }
+
+ const std::vector<Address>& getAddresses() const {
+ return addresses_;
+ }
+
+ void addAddress(const Address& address) {
+ addresses_.push_back(address);
+ }
+
+ void clearAddresses() {
+ addresses_.clear();
+ }
+
+ const std::vector<AddressLabel>& getAddressLabels() const {
+ return addressLabels_;
+ }
+
+ void addAddressLabel(const AddressLabel& addressLabel) {
+ addressLabels_.push_back(addressLabel);
+ }
+
+ void clearAddressLabels() {
+ addressLabels_.clear();
+ }
+
+ const std::vector<JID>& getJIDs() const {
+ return jids_;
+ }
+
+ void addJID(const JID& jid) {
+ jids_.push_back(jid);
+ }
+
+ void clearJIDs() {
+ jids_.clear();
+ }
+
+ const std::string& getDescription() const {
+ return description_;
+ }
+
+ void setDescription(const std::string& description) {
+ this->description_ = description;
+ }
+
+ const std::vector<Organization>& getOrganizations() const {
+ return organizations_;
+ }
+
+ void addOrganization(const Organization& organization) {
+ organizations_.push_back(organization);
+ }
+
+ void clearOrganizations() {
+ organizations_.clear();
+ }
+
+ const std::vector<std::string>& getTitles() const {
+ return titles_;
+ }
+
+ void addTitle(const std::string& title) {
+ titles_.push_back(title);
+ }
+
+ void clearTitles() {
+ titles_.clear();
+ }
+
+ const std::vector<std::string>& getRoles() const {
+ return roles_;
+ }
+
+ void addRole(const std::string& role) {
+ roles_.push_back(role);
+ }
+
+ void clearRoles() {
+ roles_.clear();
+ }
+
+ const std::vector<std::string>& getURLs() const {
+ return urls_;
+ }
+
+ void addURL(const std::string& url) {
+ urls_.push_back(url);
+ }
+
+ void clearURLs() {
+ urls_.clear();
+ }
+
private:
std::string version_;
std::string fullName_;
@@ -92,7 +275,17 @@ namespace Swift {
ByteArray photo_;
std::string photoType_;
std::string nick_;
+ boost::posix_time::ptime birthday_;
std::string unknownContent_;
std::vector<EMailAddress> emailAddresses_;
+ std::vector<Telephone> telephones_;
+ std::vector<Address> addresses_;
+ std::vector<AddressLabel> addressLabels_;
+ std::vector<JID> jids_;
+ std::string description_;
+ std::vector<Organization> organizations_;
+ std::vector<std::string> titles_;
+ std::vector<std::string> roles_;
+ std::vector<std::string> urls_;
};
}
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp
index f1e6635..eda2547 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp
@@ -7,6 +7,8 @@
#include <Swiften/Base/ByteArray.h>
#include <QA/Checker/IO.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
@@ -48,8 +50,36 @@ class VCardParserTest : public CppUnit::TestFixture {
"<WORK/>"
"<X400/>"
"</EMAIL>"
+ "<TEL>"
+ "<NUMBER>555-6273</NUMBER>"
+ "<HOME/>"
+ "<VOICE/>"
+ "</TEL>"
+ "<ADR>"
+ "<LOCALITY>Any Town</LOCALITY>"
+ "<STREET>Fake Street 123</STREET>"
+ "<PCODE>12345</PCODE>"
+ "<CTRY>USA</CTRY>"
+ "<HOME/>"
+ "</ADR>"
+ "<LABEL>"
+ "<LINE>Fake Street 123</LINE>"
+ "<LINE>12345 Any Town</LINE>"
+ "<LINE>USA</LINE>"
+ "<HOME/>"
+ "</LABEL>"
"<NICKNAME>DreamGirl</NICKNAME>"
- "<BDAY>1234</BDAY>"
+ "<BDAY>1865-05-04</BDAY>"
+ "<JID>alice@teaparty.lit</JID>"
+ "<JID>alice@wonderland.lit</JID>"
+ "<DESC>I once fell down a rabbit hole.</DESC>"
+ "<ORG>"
+ "<ORGNAME>Alice In Wonderland Inc.</ORGNAME>"
+ "</ORG>"
+ "<TITLE>Some Title</TITLE>"
+ "<ROLE>Main Character</ROLE>"
+ "<URL>http://wonderland.lit/~alice</URL>"
+ "<URL>http://teaparty.lit/~alice2</URL>"
"<MAILER>mutt</MAILER>"
"</vCard>"));
@@ -62,7 +92,7 @@ class VCardParserTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(std::string("Mrs"), payload->getPrefix());
CPPUNIT_ASSERT_EQUAL(std::string("PhD"), payload->getSuffix());
CPPUNIT_ASSERT_EQUAL(std::string("DreamGirl"), payload->getNickname());
- CPPUNIT_ASSERT_EQUAL(std::string("<BDAY xmlns=\"vcard-temp\">1234</BDAY><MAILER xmlns=\"vcard-temp\">mutt</MAILER>"), payload->getUnknownContent());
+ CPPUNIT_ASSERT_EQUAL(boost::posix_time::ptime(boost::gregorian::date(1865, 5, 4)), payload->getBirthday());
CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getEMailAddresses().size()));
CPPUNIT_ASSERT_EQUAL(std::string("alice@wonderland.lit"), payload->getEMailAddresses()[0].address);
CPPUNIT_ASSERT(payload->getEMailAddresses()[0].isHome);
@@ -76,6 +106,45 @@ class VCardParserTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(!payload->getEMailAddresses()[1].isPreferred);
CPPUNIT_ASSERT(payload->getEMailAddresses()[1].isWork);
CPPUNIT_ASSERT(payload->getEMailAddresses()[1].isX400);
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getTelephones().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("555-6273"), payload->getTelephones()[0].number);
+ CPPUNIT_ASSERT(payload->getTelephones()[0].isHome);
+ CPPUNIT_ASSERT(payload->getTelephones()[0].isVoice);
+ CPPUNIT_ASSERT(!payload->getTelephones()[0].isPreferred);
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getAddresses().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("Any Town"), payload->getAddresses()[0].locality);
+ CPPUNIT_ASSERT_EQUAL(std::string("Fake Street 123"), payload->getAddresses()[0].street);
+ CPPUNIT_ASSERT_EQUAL(std::string("12345"), payload->getAddresses()[0].postalCode);
+ CPPUNIT_ASSERT_EQUAL(std::string("USA"), payload->getAddresses()[0].country);
+ CPPUNIT_ASSERT(payload->getAddresses()[0].isHome);
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getAddressLabels().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("Fake Street 123"), payload->getAddressLabels()[0].lines[0]);
+ CPPUNIT_ASSERT_EQUAL(std::string("12345 Any Town"), payload->getAddressLabels()[0].lines[1]);
+ CPPUNIT_ASSERT_EQUAL(std::string("USA"), payload->getAddressLabels()[0].lines[2]);
+ CPPUNIT_ASSERT(payload->getAddressLabels()[0].isHome);
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getJIDs().size()));
+ CPPUNIT_ASSERT_EQUAL(JID("alice@teaparty.lit"), payload->getJIDs()[0]);
+ CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit"), payload->getJIDs()[1]);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("I once fell down a rabbit hole."), payload->getDescription());
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getOrganizations().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("Alice In Wonderland Inc."), payload->getOrganizations()[0].name);
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(payload->getOrganizations()[0].units.size()));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getTitles().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("Some Title"), payload->getTitles()[0]);
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getRoles().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("Main Character"), payload->getRoles()[0]);
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getURLs().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("http://wonderland.lit/~alice"), payload->getURLs()[0]);
+ CPPUNIT_ASSERT_EQUAL(std::string("http://teaparty.lit/~alice2"), payload->getURLs()[1]);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("<MAILER xmlns=\"vcard-temp\">mutt</MAILER>"), payload->getUnknownContent());
}
void testParse_Photo() {
diff --git a/Swiften/Parser/PayloadParsers/VCardParser.cpp b/Swiften/Parser/PayloadParsers/VCardParser.cpp
index 553d26a..620a307 100644
--- a/Swiften/Parser/PayloadParsers/VCardParser.cpp
+++ b/Swiften/Parser/PayloadParsers/VCardParser.cpp
@@ -6,6 +6,7 @@
#include <Swiften/Parser/PayloadParsers/VCardParser.h>
#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/DateTime.h>
#include <Swiften/StringCodecs/Base64.h>
#include <Swiften/Parser/SerializingParser.h>
@@ -20,6 +21,18 @@ void VCardParser::handleStartElement(const std::string& element, const std::stri
if (elementHierarchy == "/vCard/EMAIL") {
currentEMailAddress_ = VCard::EMailAddress();
}
+ if (elementHierarchy == "/vCard/TEL") {
+ currentTelephone_ = VCard::Telephone();
+ }
+ if (elementHierarchy == "/vCard/ADR") {
+ currentAddress_ = VCard::Address();
+ }
+ if (elementHierarchy == "/vCard/LABEL") {
+ currentAddressLabel_ = VCard::AddressLabel();
+ }
+ if (elementHierarchy == "/vCard/ORG") {
+ currentOrganization_ = VCard::Organization();
+ }
if (elementStack_.size() == 2) {
assert(!unknownContentParser_);
unknownContentParser_ = new SerializingParser();
@@ -90,9 +103,160 @@ void VCardParser::handleEndElement(const std::string& element, const std::string
else if (elementHierarchy == "/vCard/EMAIL/PREF") {
currentEMailAddress_.isPreferred = true;
}
- else if (elementHierarchy == "/vCard/EMAIL") {
+ else if (elementHierarchy == "/vCard/EMAIL" && !currentEMailAddress_.address.empty()) {
getPayloadInternal()->addEMailAddress(currentEMailAddress_);
}
+ else if (elementHierarchy == "/vCard/BDAY" && !currentText_.empty()) {
+ getPayloadInternal()->setBirthday(stringToDateTime(currentText_));
+ }
+ else if (elementHierarchy == "/vCard/TEL/NUMBER") {
+ currentTelephone_.number = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/TEL/HOME") {
+ currentTelephone_.isHome = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/WORK") {
+ currentTelephone_.isWork = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/VOICE") {
+ currentTelephone_.isVoice = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/FAX") {
+ currentTelephone_.isFax = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/PAGER") {
+ currentTelephone_.isPager = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/MSG") {
+ currentTelephone_.isMSG = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/CELL") {
+ currentTelephone_.isCell = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/VIDEO") {
+ currentTelephone_.isVideo = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/BBS") {
+ currentTelephone_.isBBS = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/MODEM") {
+ currentTelephone_.isModem = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/ISDN") {
+ currentTelephone_.isISDN = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/PCS") {
+ currentTelephone_.isPCS = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL/PREF") {
+ currentTelephone_.isPreferred = true;
+ }
+ else if (elementHierarchy == "/vCard/TEL" && !currentTelephone_.number.empty()) {
+ getPayloadInternal()->addTelephone(currentTelephone_);
+ }
+ else if (elementHierarchy == "/vCard/ADR/HOME") {
+ currentAddress_.isHome = true;
+ }
+ else if (elementHierarchy == "/vCard/ADR/WORK") {
+ currentAddress_.isWork = true;
+ }
+ else if (elementHierarchy == "/vCard/ADR/POSTAL") {
+ currentAddress_.isPostal = true;
+ }
+ else if (elementHierarchy == "/vCard/ADR/PARCEL") {
+ currentAddress_.isParcel = true;
+ }
+ else if (elementHierarchy == "/vCard/ADR/DOM") {
+ currentAddress_.deliveryType = VCard::DomesticDelivery;
+ }
+ else if (elementHierarchy == "/vCard/ADR/INTL") {
+ currentAddress_.deliveryType = VCard::InternationalDelivery;
+ }
+ else if (elementHierarchy == "/vCard/ADR/PREF") {
+ currentAddress_.isPreferred = true;
+ }
+ else if (elementHierarchy == "/vCard/ADR/POBOX") {
+ currentAddress_.poBox = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/ADR/EXTADD") {
+ currentAddress_.addressExtension = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/ADR/STREET") {
+ currentAddress_.street = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/ADR/LOCALITY") {
+ currentAddress_.locality = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/ADR/REGION") {
+ currentAddress_.region = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/ADR/PCODE") {
+ currentAddress_.postalCode = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/ADR/CTRY") {
+ currentAddress_.country = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/ADR") {
+ if (!currentAddress_.poBox.empty() || !currentAddress_.addressExtension.empty() ||
+ !currentAddress_.street.empty() || !currentAddress_.locality.empty() ||
+ !currentAddress_.region.empty() || !currentAddress_.region.empty() ||
+ !currentAddress_.postalCode.empty() || !currentAddress_.country.empty()) {
+ getPayloadInternal()->addAddress(currentAddress_);
+ }
+ }
+ else if (elementHierarchy == "/vCard/LABEL/HOME") {
+ currentAddressLabel_.isHome = true;
+ }
+ else if (elementHierarchy == "/vCard/LABEL/WORK") {
+ currentAddressLabel_.isWork = true;
+ }
+ else if (elementHierarchy == "/vCard/LABEL/POSTAL") {
+ currentAddressLabel_.isPostal = true;
+ }
+ else if (elementHierarchy == "/vCard/LABEL/PARCEL") {
+ currentAddressLabel_.isParcel = true;
+ }
+ else if (elementHierarchy == "/vCard/LABEL/DOM") {
+ currentAddressLabel_.deliveryType = VCard::DomesticDelivery;
+ }
+ else if (elementHierarchy == "/vCard/LABEL/INTL") {
+ currentAddressLabel_.deliveryType = VCard::InternationalDelivery;
+ }
+ else if (elementHierarchy == "/vCard/LABEL/PREF") {
+ currentAddressLabel_.isPreferred = true;
+ }
+ else if (elementHierarchy == "/vCard/LABEL/LINE") {
+ currentAddressLabel_.lines.push_back(currentText_);
+ }
+ else if (elementHierarchy == "/vCard/LABEL") {
+ getPayloadInternal()->addAddressLabel(currentAddressLabel_);
+ }
+ else if (elementHierarchy == "/vCard/JID" && !currentText_.empty()) {
+ getPayloadInternal()->addJID(JID(currentText_));
+ }
+ else if (elementHierarchy == "/vCard/DESC") {
+ getPayloadInternal()->setDescription(currentText_);
+ }
+ else if (elementHierarchy == "/vCard/ORG/ORGNAME") {
+ currentOrganization_.name = currentText_;
+ }
+ else if (elementHierarchy == "/vCard/ORG/ORGUNIT" && !currentText_.empty()) {
+ currentOrganization_.units.push_back(currentText_);
+ }
+ else if (elementHierarchy == "/vCard/ORG") {
+ if (!currentOrganization_.name.empty() || !currentOrganization_.units.empty()) {
+ getPayloadInternal()->addOrganization(currentOrganization_);
+ }
+ }
+ else if (elementHierarchy == "/vCard/TITLE" && !currentText_.empty()) {
+ getPayloadInternal()->addTitle(currentText_);
+ }
+ else if (elementHierarchy == "/vCard/ROLE" && !currentText_.empty()) {
+ getPayloadInternal()->addRole(currentText_);
+ }
+ else if (elementHierarchy == "/vCard/URL" && !currentText_.empty()) {
+ getPayloadInternal()->addURL(currentText_);
+ }
else if (elementStack_.size() == 2 && unknownContentParser_) {
getPayloadInternal()->addUnknownContent(unknownContentParser_->getResult());
}
diff --git a/Swiften/Parser/PayloadParsers/VCardParser.h b/Swiften/Parser/PayloadParsers/VCardParser.h
index b1c47a3..f10d639 100644
--- a/Swiften/Parser/PayloadParsers/VCardParser.h
+++ b/Swiften/Parser/PayloadParsers/VCardParser.h
@@ -28,6 +28,10 @@ namespace Swift {
private:
std::vector<std::string> elementStack_;
VCard::EMailAddress currentEMailAddress_;
+ VCard::Telephone currentTelephone_;
+ VCard::Address currentAddress_;
+ VCard::AddressLabel currentAddressLabel_;
+ VCard::Organization currentOrganization_;
SerializingParser* unknownContentParser_;
std::string currentText_;
};
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp
index 3ac1d77..01c8e77 100644
--- a/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp
@@ -31,14 +31,15 @@ class VCardSerializerTest : public CppUnit::TestFixture
vcard->setNickname("DreamGirl");
vcard->setPhoto(createByteArray("abcdef"));
vcard->setPhotoType("image/png");
- vcard->addUnknownContent("<BDAY>1234</BDAY><MAILER>mutt</MAILER>");
+ vcard->setBirthday(boost::posix_time::ptime(boost::gregorian::date(1865, 5, 4)));
+ vcard->addUnknownContent("<MAILER>mutt</MAILER>");
- VCard::EMailAddress address1;
- address1.address = "alice@wonderland.lit";
- address1.isHome = true;
- address1.isPreferred = true;
- address1.isInternet = true;
- vcard->addEMailAddress(address1);
+ VCard::EMailAddress emailAddress1;
+ emailAddress1.address = "alice@wonderland.lit";
+ emailAddress1.isHome = true;
+ emailAddress1.isPreferred = true;
+ emailAddress1.isInternet = true;
+ vcard->addEMailAddress(emailAddress1);
VCard::EMailAddress address2;
address2.address = "alice@teaparty.lit";
@@ -46,6 +47,41 @@ class VCardSerializerTest : public CppUnit::TestFixture
address2.isX400 = true;
vcard->addEMailAddress(address2);
+ VCard::Telephone telephone1;
+ telephone1.number = "555-6273";
+ telephone1.isHome = true;
+ telephone1.isVoice = true;
+ vcard->addTelephone(telephone1);
+
+ VCard::Address address1;
+ address1.locality = "Any Town";
+ address1.street = "Fake Street 123";
+ address1.postalCode = "12345";
+ address1.country = "USA";
+ address1.isHome = true;
+ vcard->addAddress(address1);
+
+ VCard::AddressLabel label1;
+ label1.lines.push_back("Fake Street 123");
+ label1.lines.push_back("12345 Any Town");
+ label1.lines.push_back("USA");
+ label1.isHome = true;
+ vcard->addAddressLabel(label1);
+
+ vcard->addJID(JID("alice@teaparty.lit"));
+ vcard->addJID(JID("alice@wonderland.lit"));
+
+ vcard->setDescription("I once fell down a rabbit hole.");
+
+ VCard::Organization org1;
+ org1.name = "Alice In Wonderland Inc.";
+ vcard->addOrganization(org1);
+
+ vcard->addTitle("Some Title");
+ vcard->addRole("Main Character");
+ vcard->addURL("http://wonderland.lit/~alice");
+ vcard->addURL("http://teaparty.lit/~alice2");
+
std::string expectedResult =
"<vCard xmlns=\"vcard-temp\">"
"<VERSION>2.0</VERSION>"
@@ -73,7 +109,35 @@ class VCardSerializerTest : public CppUnit::TestFixture
"<TYPE>image/png</TYPE>"
"<BINVAL>YWJjZGVm</BINVAL>"
"</PHOTO>"
- "<BDAY>1234</BDAY>"
+ "<BDAY>1865-05-04T00:00:00Z</BDAY>"
+ "<TEL>"
+ "<NUMBER>555-6273</NUMBER>"
+ "<HOME/>"
+ "<VOICE/>"
+ "</TEL>"
+ "<ADR>"
+ "<STREET>Fake Street 123</STREET>"
+ "<LOCALITY>Any Town</LOCALITY>"
+ "<PCODE>12345</PCODE>"
+ "<CTRY>USA</CTRY>"
+ "<HOME/>"
+ "</ADR>"
+ "<LABEL>"
+ "<LINE>Fake Street 123</LINE>"
+ "<LINE>12345 Any Town</LINE>"
+ "<LINE>USA</LINE>"
+ "<HOME/>"
+ "</LABEL>"
+ "<JID>alice@teaparty.lit</JID>"
+ "<JID>alice@wonderland.lit</JID>"
+ "<DESC>I once fell down a rabbit hole.</DESC>"
+ "<ORG>"
+ "<ORGNAME>Alice In Wonderland Inc.</ORGNAME>"
+ "</ORG>"
+ "<TITLE>Some Title</TITLE>"
+ "<ROLE>Main Character</ROLE>"
+ "<URL>http://wonderland.lit/~alice</URL>"
+ "<URL>http://teaparty.lit/~alice2</URL>"
"<MAILER>mutt</MAILER>"
"</vCard>";
diff --git a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp
index 1512c6c..22d59b4 100644
--- a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp
+++ b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp
@@ -13,6 +13,7 @@
#include <Swiften/Serializer/XML/XMLTextNode.h>
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
#include <Swiften/StringCodecs/Base64.h>
+#include <Swiften/Base/DateTime.h>
#include <Swiften/Base/foreach.h>
namespace Swift {
@@ -23,49 +24,33 @@ VCardSerializer::VCardSerializer() : GenericPayloadSerializer<VCard>() {
std::string VCardSerializer::serializePayload(boost::shared_ptr<VCard> vcard) const {
XMLElement queryElement("vCard", "vcard-temp");
if (!vcard->getVersion().empty()) {
- boost::shared_ptr<XMLElement> versionElement(new XMLElement("VERSION"));
- versionElement->addNode(boost::make_shared<XMLTextNode>(vcard->getVersion()));
- queryElement.addNode(versionElement);
+ queryElement.addNode(boost::make_shared<XMLElement>("VERSION", "", vcard->getVersion()));
}
if (!vcard->getFullName().empty()) {
- boost::shared_ptr<XMLElement> fullNameElement(new XMLElement("FN"));
- fullNameElement->addNode(boost::make_shared<XMLTextNode>(vcard->getFullName()));
- queryElement.addNode(fullNameElement);
+ queryElement.addNode(boost::make_shared<XMLElement>("FN", "", vcard->getFullName()));
}
if (!vcard->getGivenName().empty() || !vcard->getFamilyName().empty() || !vcard->getMiddleName().empty() || !vcard->getPrefix().empty() || !vcard->getSuffix().empty()) {
boost::shared_ptr<XMLElement> nameElement(new XMLElement("N"));
if (!vcard->getFamilyName().empty()) {
- boost::shared_ptr<XMLElement> familyNameElement(new XMLElement("FAMILY"));
- familyNameElement->addNode(boost::make_shared<XMLTextNode>(vcard->getFamilyName()));
- nameElement->addNode(familyNameElement);
+ nameElement->addNode(boost::make_shared<XMLElement>("FAMILY", "", vcard->getFamilyName()));
}
if (!vcard->getGivenName().empty()) {
- boost::shared_ptr<XMLElement> givenNameElement(new XMLElement("GIVEN"));
- givenNameElement->addNode(boost::make_shared<XMLTextNode>(vcard->getGivenName()));
- nameElement->addNode(givenNameElement);
+ nameElement->addNode(boost::make_shared<XMLElement>("GIVEN", "", vcard->getGivenName()));
}
if (!vcard->getMiddleName().empty()) {
- boost::shared_ptr<XMLElement> middleNameElement(new XMLElement("MIDDLE"));
- middleNameElement->addNode(boost::make_shared<XMLTextNode>(vcard->getMiddleName()));
- nameElement->addNode(middleNameElement);
+ nameElement->addNode(boost::make_shared<XMLElement>("MIDDLE", "", vcard->getMiddleName()));
}
if (!vcard->getPrefix().empty()) {
- boost::shared_ptr<XMLElement> prefixElement(new XMLElement("PREFIX"));
- prefixElement->addNode(boost::make_shared<XMLTextNode>(vcard->getPrefix()));
- nameElement->addNode(prefixElement);
+ nameElement->addNode(boost::make_shared<XMLElement>("PREFIX", "", vcard->getPrefix()));
}
if (!vcard->getSuffix().empty()) {
- boost::shared_ptr<XMLElement> suffixElement(new XMLElement("SUFFIX"));
- suffixElement->addNode(boost::make_shared<XMLTextNode>(vcard->getSuffix()));
- nameElement->addNode(suffixElement);
+ nameElement->addNode(boost::make_shared<XMLElement>("SUFFIX", "", vcard->getSuffix()));
}
queryElement.addNode(nameElement);
}
foreach(const VCard::EMailAddress& emailAddress, vcard->getEMailAddresses()) {
boost::shared_ptr<XMLElement> emailElement(new XMLElement("EMAIL"));
- boost::shared_ptr<XMLElement> userIDElement(new XMLElement("USERID"));
- userIDElement->addNode(boost::make_shared<XMLTextNode>(emailAddress.address));
- emailElement->addNode(userIDElement);
+ emailElement->addNode(boost::make_shared<XMLElement>("USERID", "", emailAddress.address));
if (emailAddress.isHome) {
emailElement->addNode(boost::make_shared<XMLElement>("HOME"));
}
@@ -84,24 +69,179 @@ std::string VCardSerializer::serializePayload(boost::shared_ptr<VCard> vcard) c
queryElement.addNode(emailElement);
}
if (!vcard->getNickname().empty()) {
- boost::shared_ptr<XMLElement> nickElement(new XMLElement("NICKNAME"));
- nickElement->addNode(boost::make_shared<XMLTextNode>(vcard->getNickname()));
- queryElement.addNode(nickElement);
+ queryElement.addNode(boost::make_shared<XMLElement>("NICKNAME", "", vcard->getNickname()));
}
if (!vcard->getPhoto().empty() || !vcard->getPhotoType().empty()) {
XMLElement::ref photoElement(new XMLElement("PHOTO"));
if (!vcard->getPhotoType().empty()) {
- XMLElement::ref typeElement(new XMLElement("TYPE"));
- typeElement->addNode(XMLTextNode::ref(new XMLTextNode(vcard->getPhotoType())));
- photoElement->addNode(typeElement);
+ photoElement->addNode(boost::make_shared<XMLElement>("TYPE", "", vcard->getPhotoType()));
}
if (!vcard->getPhoto().empty()) {
- XMLElement::ref binvalElement(new XMLElement("BINVAL"));
- binvalElement->addNode(XMLTextNode::ref(new XMLTextNode(Base64::encode(vcard->getPhoto()))));
- photoElement->addNode(binvalElement);
+ photoElement->addNode(boost::make_shared<XMLElement>("BINVAL", "", Base64::encode(vcard->getPhoto())));
}
queryElement.addNode(photoElement);
}
+ if (!vcard->getBirthday().is_not_a_date_time()) {
+ queryElement.addNode(boost::make_shared<XMLElement>("BDAY", "", dateTimeToString(vcard->getBirthday())));
+ }
+
+ foreach(const VCard::Telephone& telephone, vcard->getTelephones()) {
+ boost::shared_ptr<XMLElement> telElement(new XMLElement("TEL"));
+ telElement->addNode(boost::make_shared<XMLElement>("NUMBER", "", telephone.number));
+ if (telephone.isHome) {
+ telElement->addNode(boost::make_shared<XMLElement>("HOME"));
+ }
+ if (telephone.isWork) {
+ telElement->addNode(boost::make_shared<XMLElement>("WORK"));
+ }
+ if (telephone.isVoice) {
+ telElement->addNode(boost::make_shared<XMLElement>("VOICE"));
+ }
+ if (telephone.isFax) {
+ telElement->addNode(boost::make_shared<XMLElement>("FAX"));
+ }
+ if (telephone.isPager) {
+ telElement->addNode(boost::make_shared<XMLElement>("PAGER"));
+ }
+ if (telephone.isMSG) {
+ telElement->addNode(boost::make_shared<XMLElement>("MSG"));
+ }
+ if (telephone.isCell) {
+ telElement->addNode(boost::make_shared<XMLElement>("CELL"));
+ }
+ if (telephone.isVideo) {
+ telElement->addNode(boost::make_shared<XMLElement>("VIDEO"));
+ }
+ if (telephone.isBBS) {
+ telElement->addNode(boost::make_shared<XMLElement>("BBS"));
+ }
+ if (telephone.isModem) {
+ telElement->addNode(boost::make_shared<XMLElement>("MODEM"));
+ }
+ if (telephone.isISDN) {
+ telElement->addNode(boost::make_shared<XMLElement>("ISDN"));
+ }
+ if (telephone.isPCS) {
+ telElement->addNode(boost::make_shared<XMLElement>("PCS"));
+ }
+ if (telephone.isPreferred) {
+ telElement->addNode(boost::make_shared<XMLElement>("PREF"));
+ }
+ queryElement.addNode(telElement);
+ }
+
+ foreach(const VCard::Address& address, vcard->getAddresses()) {
+ boost::shared_ptr<XMLElement> adrElement = boost::make_shared<XMLElement>("ADR");
+ if (!address.poBox.empty()) {
+ adrElement->addNode(boost::make_shared<XMLElement>("POBOX", "", address.poBox));
+ }
+ if (!address.addressExtension.empty()) {
+ adrElement->addNode(boost::make_shared<XMLElement>("EXTADD", "", address.addressExtension));
+ }
+ if (!address.street.empty()) {
+ adrElement->addNode(boost::make_shared<XMLElement>("STREET", "", address.street));
+ }
+ if (!address.locality.empty()) {
+ adrElement->addNode(boost::make_shared<XMLElement>("LOCALITY", "", address.locality));
+ }
+ if (!address.region.empty()) {
+ adrElement->addNode(boost::make_shared<XMLElement>("REGION", "", address.region));
+ }
+ if (!address.postalCode.empty()) {
+ adrElement->addNode(boost::make_shared<XMLElement>("PCODE", "", address.postalCode));
+ }
+ if (!address.country.empty()) {
+ adrElement->addNode(boost::make_shared<XMLElement>("CTRY", "", address.country));
+ }
+
+ if (address.isHome) {
+ adrElement->addNode(boost::make_shared<XMLElement>("HOME"));
+ }
+ if (address.isWork) {
+ adrElement->addNode(boost::make_shared<XMLElement>("WORK"));
+ }
+ if (address.isPostal) {
+ adrElement->addNode(boost::make_shared<XMLElement>("POSTAL"));
+ }
+ if (address.isParcel) {
+ adrElement->addNode(boost::make_shared<XMLElement>("PARCEL"));
+ }
+ if (address.deliveryType == VCard::DomesticDelivery) {
+ adrElement->addNode(boost::make_shared<XMLElement>("DOM"));
+ }
+ if (address.deliveryType == VCard::InternationalDelivery) {
+ adrElement->addNode(boost::make_shared<XMLElement>("INTL"));
+ }
+ if (address.isPreferred) {
+ adrElement->addNode(boost::make_shared<XMLElement>("PREF"));
+ }
+ queryElement.addNode(adrElement);
+ }
+
+ foreach(const VCard::AddressLabel& addressLabel, vcard->getAddressLabels()) {
+ boost::shared_ptr<XMLElement> labelElement = boost::make_shared<XMLElement>("LABEL");
+
+ foreach(const std::string& line, addressLabel.lines) {
+ labelElement->addNode(boost::make_shared<XMLElement>("LINE", "", line));
+ }
+
+ if (addressLabel.isHome) {
+ labelElement->addNode(boost::make_shared<XMLElement>("HOME"));
+ }
+ if (addressLabel.isWork) {
+ labelElement->addNode(boost::make_shared<XMLElement>("WORK"));
+ }
+ if (addressLabel.isPostal) {
+ labelElement->addNode(boost::make_shared<XMLElement>("POSTAL"));
+ }
+ if (addressLabel.isParcel) {
+ labelElement->addNode(boost::make_shared<XMLElement>("PARCEL"));
+ }
+ if (addressLabel.deliveryType == VCard::DomesticDelivery) {
+ labelElement->addNode(boost::make_shared<XMLElement>("DOM"));
+ }
+ if (addressLabel.deliveryType == VCard::InternationalDelivery) {
+ labelElement->addNode(boost::make_shared<XMLElement>("INTL"));
+ }
+ if (addressLabel.isPreferred) {
+ labelElement->addNode(boost::make_shared<XMLElement>("PREF"));
+ }
+ queryElement.addNode(labelElement);
+ }
+
+ foreach(const JID& jid, vcard->getJIDs()) {
+ queryElement.addNode(boost::make_shared<XMLElement>("JID", "", jid.toString()));
+ }
+
+ if (!vcard->getDescription().empty()) {
+ queryElement.addNode(boost::make_shared<XMLElement>("DESC", "", vcard->getDescription()));
+ }
+
+ foreach(const VCard::Organization& org, vcard->getOrganizations()) {
+ boost::shared_ptr<XMLElement> orgElement = boost::make_shared<XMLElement>("ORG");
+ if (!org.name.empty()) {
+ orgElement->addNode(boost::make_shared<XMLElement>("ORGNAME", "", org.name));
+ }
+ if (!org.units.empty()) {
+ foreach(const std::string& unit, org.units) {
+ orgElement->addNode(boost::make_shared<XMLElement>("ORGUNIT", "", unit));
+ }
+ }
+ queryElement.addNode(orgElement);
+ }
+
+ foreach(const std::string& title, vcard->getTitles()) {
+ queryElement.addNode(boost::make_shared<XMLElement>("TITLE", "", title));
+ }
+
+ foreach(const std::string& role, vcard->getRoles()) {
+ queryElement.addNode(boost::make_shared<XMLElement>("ROLE", "", role));
+ }
+
+ foreach(const std::string& url, vcard->getURLs()) {
+ queryElement.addNode(boost::make_shared<XMLElement>("URL", "", url));
+ }
+
if (!vcard->getUnknownContent().empty()) {
queryElement.addNode(boost::make_shared<XMLRawTextNode>(vcard->getUnknownContent()));
}