contact: implement add to contact feature

- Add right click on history item
	- Copy number to clipboard
	- Add to new Contact
	- Add to existing contact


Issue: #77711
Issue: #77862
Issue: #77859

Change-Id: Ia249707e51c5208abbd67eeb3b04e6ca835bcd75
diff --git a/RingWinClient.pro b/RingWinClient.pro
index e5f5c63..42ef5bc 100644
--- a/RingWinClient.pro
+++ b/RingWinClient.pro
@@ -6,7 +6,7 @@
 
 QT       += core gui
 
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets svg
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets svg xml
 
 VERSION = 0.3.0
 GIT_VERSION = $$system(git --git-dir $$PWD/.git --work-tree $$PWD describe --always --tags)
@@ -47,7 +47,9 @@
     accountstatedelegate.cpp \
     videoview.cpp \
     videooverlay.cpp \
-    imdelegate.cpp
+    imdelegate.cpp \
+    contactdialog.cpp \
+    contactpicker.cpp
 
 HEADERS  += mainwindow.h \
     callwidget.h \
@@ -70,7 +72,9 @@
     accountstatedelegate.h \
     videoview.h \
     videooverlay.h \
-    imdelegate.h
+    imdelegate.h \
+    contactdialog.h \
+    contactpicker.h
 
 FORMS    += mainwindow.ui \
     callwidget.ui \
@@ -83,7 +87,9 @@
     wizarddialog.ui \
     instantmessagingwidget.ui \
     videoview.ui \
-    videooverlay.ui
+    videooverlay.ui \
+    contactdialog.ui \
+    contactpicker.ui
 
 win32: LIBS += -lole32 -luuid -lshlwapi
 
@@ -118,7 +124,8 @@
     RUNTIME.path = $$OUT_PWD/release
 
     QTRUNTIME.files = $$RUNTIMEDIR/Qt5Core.dll $$RUNTIMEDIR/Qt5Widgets.dll \
-                            $$RUNTIMEDIR/Qt5Gui.dll $$RUNTIMEDIR/Qt5Svg.dll
+                            $$RUNTIMEDIR/Qt5Gui.dll $$RUNTIMEDIR/Qt5Svg.dll \
+                            $$RUNTIMEDIR/Qt5Xml.dll
     QTRUNTIME.path = $$OUT_PWD/release
 
     QTDEPSRUNTIME.files = $$RUNTIMEDIR/zlib1.dll $$RUNTIMEDIR/iconv.dll \
diff --git a/callwidget.cpp b/callwidget.cpp
index fa5eceb..670e632 100644
--- a/callwidget.cpp
+++ b/callwidget.cpp
@@ -19,10 +19,17 @@
 #include "callwidget.h"
 #include "ui_callwidget.h"
 
+#include <QClipboard>
+
 #include <memory>
 
+//ERROR is defined in windows.h
+#include "utils.h"
+#undef ERROR
+
 #include "audio/settings.h"
 #include "personmodel.h"
+#include "person.h"
 #include "fallbackpersoncollection.h"
 #include "categorizedcontactmodel.h"
 #include "localhistorycollection.h"
@@ -32,6 +39,8 @@
 
 #include "wizarddialog.h"
 #include "windowscontactbackend.h"
+#include "contactdialog.h"
+#include "contactpicker.h"
 
 CallWidget::CallWidget(QWidget *parent) :
     NavWidget(Main ,parent),
@@ -78,15 +87,18 @@
         ui->callList->setModel(callModel_);
         ui->callList->setSelectionModel(callModel_->selectionModel());
 
+        auto personCollection = PersonModel::instance()->
+                addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
+
+        CategorizedContactModel::instance()->setSortAlphabetical(false);
+        CategorizedContactModel::instance()->setUnreachableHidden(true);
+        ui->contactView->setModel(CategorizedContactModel::instance());
+        contactDelegate_ = new ContactDelegate();
+        ui->contactView->setItemDelegate(contactDelegate_);
+
         CategorizedHistoryModel::instance()->
                 addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
 
-        PersonModel::instance()->
-                addCollection<FallbackPersonCollection>(LoadOptions::FORCE_ENABLED);
-
-        PersonModel::instance()->
-                addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
-
         ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
         CategorizedHistoryModel::SortedProxy::instance()->model()->sort(0, Qt::DescendingOrder);
         ui->historyList->setHeaderHidden(true);
@@ -99,14 +111,63 @@
                 ui->historyList->setExpanded(idx, true);
         });
 
+        ui->historyList->setContextMenuPolicy(Qt::CustomContextMenu);
+        connect(ui->historyList, &QListView::customContextMenuRequested, [=](const QPoint& pos){
+            if (ui->historyList->currentIndex().parent().isValid()) {
+                QPoint globalPos = ui->historyList->mapToGlobal(pos);
+                QMenu menu;
+
+                ContactMethod* contactMethod = ui->historyList->currentIndex()
+                        .data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
+
+                auto copyAction = new QAction("Copy number", this);
+                menu.addAction(copyAction);
+                connect(copyAction, &QAction::triggered, [=]() {
+                    QApplication::clipboard()->setText(contactMethod->uri());
+                });
+
+                if (not contactMethod->contact()) {
+                    auto addNew = new QAction("Add to new contact", this);
+                    menu.addAction(addNew);
+                    connect(addNew, &QAction::triggered, [=]() {
+                        ContactDialog dialog(contactMethod->uri());
+                        auto ret = dialog.exec();
+                        if (!ret || dialog.getName().isEmpty())
+                            return;
+                        auto *newPerson = new Person();
+                        newPerson->setFormattedName(dialog.getName());
+                        Person::ContactMethods cM;
+                        cM.append(contactMethod);
+                        newPerson->setContactMethods(cM);
+                        newPerson->setUid(Utils::GenGUID().toLocal8Bit());
+                        PersonModel::instance()->addNewPerson(newPerson, personCollection);
+                    });
+                    auto addExisting = new QAction("Add to existing contact", this);
+                    menu.addAction(addExisting);
+                    connect(addExisting, &QAction::triggered, [=]() {
+                        /* Force LRC to update contact model as adding a number
+                        to a contact without one didn't render him reachable */
+                        CategorizedContactModel::instance()->setUnreachableHidden(false);
+
+                        ContactPicker contactPicker;
+                        contactPicker.move(globalPos.x(), globalPos.y() - (contactPicker.height()/2));
+                        auto ret = contactPicker.exec();
+                        if (!ret)
+                            return;
+                        auto p = contactPicker.getPersonSelected();
+                        Person::ContactMethods cM (p->phoneNumbers());
+                        cM.append(contactMethod);
+                        p->setContactMethods(cM);
+                        p->save();
+                        CategorizedContactModel::instance()->setUnreachableHidden(true);
+                    });
+                }
+                menu.exec(globalPos);
+            }
+        });
 
         ui->sortComboBox->setModel(CategorizedHistoryModel::SortedProxy::instance()->categoryModel());
 
-        CategorizedContactModel::instance()->setSortAlphabetical(false);
-        ui->contactView->setModel(CategorizedContactModel::instance());
-        contactDelegate_ = new ContactDelegate();
-        ui->contactView->setItemDelegate(contactDelegate_);
-
         findRingAccount();
 
     } catch (...) {
@@ -250,7 +311,8 @@
 }
 
 void
-CallWidget::addedCall(Call* call, Call* parent) {
+CallWidget::addedCall(Call* call, Call* parent)
+{
     Q_UNUSED(parent);
     if (call->direction() == Call::Direction::OUTGOING) {
         displaySpinner(true);
@@ -300,28 +362,32 @@
 }
 
 void
-CallWidget::atExit() {
+CallWidget::atExit()
+{
 
 }
 
 void
 CallWidget::on_contactView_doubleClicked(const QModelIndex &index)
 {
-    QString uri;
+    if (not index.isValid())
+        return;
+
+    ContactMethod* uri;
 
     auto var = index.child(0,0).data(
                 static_cast<int>(Person::Role::Object));
     if (var.isValid()) {
         Person* person = var.value<Person*>();
         if (person->phoneNumbers().size() > 0) {
-            uri = person->phoneNumbers().at(0)->uri();
+            uri = person->phoneNumbers().at(0); // FIXME: A person can have multiple contact method
+            if (uri) {
+                auto outCall = CallModel::instance()->dialingCall(person->formattedName());
+                outCall->setDialNumber(uri);
+                outCall->performAction(Call::Action::ACCEPT);
+            }
         }
     }
-    if (not uri.isEmpty()) {
-        auto outCall = CallModel::instance()->dialingCall(uri);
-        outCall->setDialNumber(uri);
-        outCall->performAction(Call::Action::ACCEPT);
-    }
 }
 
 void
@@ -330,9 +396,9 @@
     if (not index.isValid())
         return;
 
-    QString number = index.model()->data(index, static_cast<int>(Call::Role::Number)).toString();
-    if (not number.isEmpty()) {
-        auto outCall = CallModel::instance()->dialingCall(number);
+    auto number = index.data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
+    if (number) {
+        auto outCall = CallModel::instance()->dialingCall();
         outCall->setDialNumber(number);
         outCall->performAction(Call::Action::ACCEPT);
     }
diff --git a/contactdelegate.cpp b/contactdelegate.cpp
index e95b4fd..79c806f 100644
--- a/contactdelegate.cpp
+++ b/contactdelegate.cpp
@@ -35,7 +35,6 @@
     initStyleOption(&opt, index);
 
     if (index.column() == 0) {
-        QString name = index.model()->data(index, Qt::DisplayRole).toString();
         opt.text = "";
         QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
         style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
@@ -46,14 +45,13 @@
             cg = QPalette::Inactive;
         painter->setPen(opt.palette.color(cg, QPalette::Text));
         painter->setOpacity(1.0);
-        painter->drawText(QRect(rect.left()+sizeImage_+5, rect.top(),
-                                rect.width(), rect.height()/2),
-                                opt.displayAlignment, name);
-
         QVariant var_c = index.child(0,0).data(
                     static_cast<int>(Person::Role::Object));
         if (var_c.isValid()) {
             Person *c = var_c.value<Person *>();
+            painter->drawText(QRect(rect.left()+sizeImage_+5, rect.top(),
+                                    rect.width(), rect.height()/2),
+                                    opt.displayAlignment, c->formattedName());
             QVariant var_p = c->photo();
             painter->drawRect(QRect(rect.left(), rect.top(),
                                     sizeImage_+1, sizeImage_+1));
diff --git a/contactdialog.cpp b/contactdialog.cpp
new file mode 100644
index 0000000..fd96c24
--- /dev/null
+++ b/contactdialog.cpp
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Savoir-faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#include "contactdialog.h"
+#include "ui_contactdialog.h"
+
+ContactDialog::ContactDialog(const QString &number, QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::ContactDialog)
+{
+    ui->setupUi(this);
+    ui->numberLineEdit->setText(number);
+}
+
+ContactDialog::~ContactDialog()
+{
+    delete ui;
+}
+
+const QString&
+ContactDialog::getName()
+{
+    return contactName_;
+}
+
+void
+ContactDialog::on_nameLineEdit_textChanged(const QString &arg1)
+{
+    contactName_ = arg1;
+}
diff --git a/contactdialog.h b/contactdialog.h
new file mode 100644
index 0000000..b97cdb2
--- /dev/null
+++ b/contactdialog.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Savoir-faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#ifndef CONTACTDIALOG_H
+#define CONTACTDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class ContactDialog;
+}
+
+class ContactDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit ContactDialog(const QString& number, QWidget *parent = 0);
+    ~ContactDialog();
+
+    const QString &getName();
+
+private slots:
+    void on_nameLineEdit_textChanged(const QString &arg1);
+
+private:
+    Ui::ContactDialog *ui;
+    QString contactName_;
+};
+
+#endif // CONTACTDIALOG_H
diff --git a/contactdialog.ui b/contactdialog.ui
new file mode 100644
index 0000000..4d4e80f
--- /dev/null
+++ b/contactdialog.ui
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ContactDialog</class>
+ <widget class="QDialog" name="ContactDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>398</width>
+    <height>154</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="font">
+      <font>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="text">
+      <string>New Contact</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLineEdit" name="nameLineEdit">
+     <property name="placeholderText">
+      <string>Enter a name...</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLineEdit" name="numberLineEdit">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>ContactDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>ContactDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/contactpicker.cpp b/contactpicker.cpp
new file mode 100644
index 0000000..417d30c
--- /dev/null
+++ b/contactpicker.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Savoir-faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#include "contactpicker.h"
+#include "ui_contactpicker.h"
+
+#include "categorizedcontactmodel.h"
+
+ContactPicker::ContactPicker(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::ContactPicker),
+    personSelected_(nullptr)
+{
+    ui->setupUi(this);
+
+    this->setWindowFlags(Qt::CustomizeWindowHint);
+    this->setWindowFlags(Qt::FramelessWindowHint);
+
+    auto personModel = PersonModel::instance();
+    ui->contactView->setModel(personModel);
+}
+
+ContactPicker::~ContactPicker()
+{
+    delete ui;
+}
+
+void
+ContactPicker::on_contactView_doubleClicked(const QModelIndex &index)
+{
+    personSelected_ =  index.data(static_cast<int>(Person::Role::Object)).value<Person*>();
+    this->accept();
+}
+
+Person*
+ContactPicker::getPersonSelected()
+{
+    return personSelected_;
+}
+
+void
+ContactPicker::on_cancelButton_clicked()
+{
+    this->reject();
+}
diff --git a/contactpicker.h b/contactpicker.h
new file mode 100644
index 0000000..168d843
--- /dev/null
+++ b/contactpicker.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Savoir-faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#ifndef CONTACTPICKER_H
+#define CONTACTPICKER_H
+
+#include <QDialog>
+
+#include "personmodel.h"
+
+namespace Ui {
+class ContactPicker;
+}
+
+class ContactPicker : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit ContactPicker(QWidget *parent = 0);
+    ~ContactPicker();
+
+     Person *getPersonSelected();
+
+//UI SLOTS
+private slots:
+    void on_contactView_doubleClicked(const QModelIndex &index);
+    void on_cancelButton_clicked();
+
+private:
+    Ui::ContactPicker *ui;
+    Person *personSelected_;
+};
+
+#endif // CONTACTPICKER_H
diff --git a/contactpicker.ui b/contactpicker.ui
new file mode 100644
index 0000000..b1cb6e3
--- /dev/null
+++ b/contactpicker.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ContactPicker</class>
+ <widget class="QDialog" name="ContactPicker">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>249</width>
+    <height>438</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QListView" name="contactView"/>
+   </item>
+   <item>
+    <widget class="QPushButton" name="cancelButton">
+     <property name="text">
+      <string>Cancel</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/utils.cpp b/utils.cpp
index 7e8a25b..18515cb 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -117,3 +117,33 @@
 #endif
 }
 
+QString
+Utils::GenGUID() {
+#ifdef Q_OS_WIN32
+    GUID gidReference;
+    wchar_t *str;
+    HRESULT hCreateGuid = CoCreateGuid(&gidReference);
+    if (hCreateGuid == S_OK) {
+        StringFromCLSID(gidReference, &str);
+        auto gStr = QString::fromWCharArray(str);
+        return gStr.remove("{").remove("}").toLower();
+    }
+    else
+        return QString("");
+#else
+    return QString("");
+#endif
+}
+
+QString
+Utils::GetISODate() {
+#ifdef Q_OS_WIN32
+    SYSTEMTIME lt;
+    GetSystemTime(&lt);
+    return QString("%1-%2-%3T%4:%5:%6Z").arg(lt.wYear).arg(lt.wMonth,2,10,QChar('0')).arg(lt.wDay,2,10,QChar('0'))
+            .arg(lt.wHour,2,10,QChar('0')).arg(lt.wMinute,2,10,QChar('0')).arg(lt.wSecond,2,10,QChar('0'));
+#else
+    return QString("");
+#endif
+}
+
diff --git a/utils.h b/utils.h
index 46cf54f..519a46e 100644
--- a/utils.h
+++ b/utils.h
@@ -39,6 +39,8 @@
     static bool CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszPathLink);
     static bool CheckStartupLink();
     static QString GetRingtonePath();
+    static QString GenGUID();
+    static QString GetISODate();
 };
 
 
diff --git a/windowscontactbackend.cpp b/windowscontactbackend.cpp
index f8adb26..f246e94 100644
--- a/windowscontactbackend.cpp
+++ b/windowscontactbackend.cpp
@@ -18,6 +18,13 @@
 
 #include "windowscontactbackend.h"
 
+#include <QtXml>
+
+#include "personmodel.h"
+#include "categorizedcontactmodel.h"
+
+#include "utils.h"
+
 WindowsContactEditor::WindowsContactEditor(CollectionMediator<Person> *m
                                            , WindowsContactBackend *parent)
     : CollectionEditor<Person>(m),collection_(parent)
@@ -33,15 +40,65 @@
 bool
 WindowsContactEditor::save(const Person *item)
 {
-    Q_UNUSED(item)
-    return false;
+    QFile file(QStandardPaths::writableLocation
+               (QStandardPaths::HomeLocation) + "/Contacts/"
+               + item->formattedName() + ".contact");
+    if (!file.open(QIODevice::ReadWrite)) {
+        file.close();
+        qDebug() << "Cannot open contact file";
+        return false;
+    }
+
+    QDomDocument doc;
+    doc.setContent(&file);
+
+    auto root = doc.elementsByTagName("c:contact").at(0);
+    auto nodes = doc.elementsByTagName("c:PhoneNumberCollection");
+
+    //if PhoneNumberCollection already exists
+    QVector<QString> nodeNumberVector;
+    if (nodes.length()) {
+        auto phoneNumberCollection = nodes.at(0);
+        auto phoneNumbers = doc.elementsByTagName("c:Number");
+        auto virtualPhoneNumber = item->phoneNumbers();
+        for (int i = 0; i < phoneNumbers.length(); i++) {
+            auto node = phoneNumbers.at(i).toElement();
+            nodeNumberVector.append(node.text());
+        }
+        for (auto elem : virtualPhoneNumber) {
+            if (not nodeNumberVector.contains(elem->uri())) {
+                auto phoneNumber = doc.createElement("c:PhoneNumber");
+                phoneNumberCollection.appendChild(phoneNumber);
+                phoneNumber.setAttribute("c:ElementID", Utils::GenGUID());
+                auto numberNode = doc.createElement("c:Number");
+                phoneNumber.appendChild(numberNode);
+                auto numberValue = doc.createTextNode(elem->uri());
+                numberNode.appendChild(numberValue);
+            }
+        }
+    } else {
+        auto phoneNumberCollection = doc.createElement("c:PhoneNumberCollection");
+        root.appendChild(phoneNumberCollection);
+        auto phoneNumber = doc.createElement("c:PhoneNumber");
+        phoneNumberCollection.appendChild(phoneNumber);
+        phoneNumber.setAttribute("c:ElementID", Utils::GenGUID());
+        auto numberNode = doc.createElement("c:Number");
+        phoneNumber.appendChild(numberNode);
+        auto numberValue = doc.createTextNode(item->phoneNumbers().at(0)->uri());
+        numberNode.appendChild(numberValue);
+    }
+    file.resize(0);
+    file.write(doc.toByteArray());
+    file.close();
+    return true;
 }
 
 bool
 WindowsContactEditor::remove(const Person *item)
 {
-    Q_UNUSED(item)
-    return false;
+    items_.removeOne(const_cast<Person*>(item));
+    mediator()->removeItem(item);
+    return true;
 }
 
 bool
@@ -54,8 +111,82 @@
 bool
 WindowsContactEditor::addNew(const Person *item)
 {
-    Q_UNUSED(item)
-    return false;
+    QDomDocument doc;
+    QFile file(QStandardPaths::writableLocation
+               (QStandardPaths::HomeLocation) + "/Contacts/"
+               + item->formattedName()+".contact");
+    if (file.exists())
+        return false;
+    if (!file.open(QIODevice::ReadWrite)) {
+        file.close();
+        qDebug() << "Cannot create contact file";
+        return false;
+    }
+    doc.appendChild(
+                doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""));
+
+    //Create root
+    auto root = doc.createElement("c:contact");
+    root.setAttribute("c:Version", "1");
+    root.setAttribute("xmlns:c", "http://schemas.microsoft.com/Contact");
+    root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
+    root.setAttribute("xmlns:MSP2P","http://schemas.microsoft.com/Contact/Extended/MSP2P");
+    doc.appendChild(root);
+
+    auto date = Utils::GetISODate();
+
+    //Create creation date
+    auto creationDateNode = doc.createElement("c:CreationDate");
+    auto creationDateValue = doc.createTextNode(date);
+    creationDateNode.appendChild(creationDateValue);
+    root.appendChild(creationDateNode);
+
+    //Create extended node
+    auto extendedNode = doc.createElement("c:Extended");
+    extendedNode.setAttribute("xsi:nil", "true");
+    root.appendChild(extendedNode);
+
+    //Create contactID collection
+    auto contactIDCol = doc.createElement("c:ContactIDCollection");
+    root.appendChild(contactIDCol);
+    auto contactID = doc.createElement("c:ContactID");
+    contactID.setAttribute("c:ElementID", Utils::GenGUID());
+    auto contactValue = doc.createElement("c:Value");
+    auto value = doc.createTextNode(item->uid());
+    contactValue.appendChild(value);
+    contactID.appendChild(contactValue);
+    contactIDCol.appendChild(contactID);
+
+    //Create NameCollection
+    auto nameCollection = doc.createElement("c:NameCollection");
+    root.appendChild(nameCollection);
+    auto name = doc.createElement("c:Name");
+    nameCollection.appendChild(name);
+    name.setAttribute("c:ElementID", Utils::GenGUID());
+    auto formattedName = doc.createElement("c:FormattedName");
+    name.appendChild(formattedName);
+    auto formattedNameValue = doc.createTextNode(item->formattedName());
+    formattedName.appendChild(formattedNameValue);
+
+    //Create PhoneNumberCollection
+    auto phoneNumberCollection = doc.createElement("c:PhoneNumberCollection");
+    root.appendChild(phoneNumberCollection);
+    auto phoneNumber = doc.createElement("c:PhoneNumber");
+    phoneNumberCollection.appendChild(phoneNumber);
+    phoneNumber.setAttribute("c:ElementID", Utils::GenGUID());
+    auto numberNode = doc.createElement("c:Number");
+    phoneNumber.appendChild(numberNode);
+    auto numberValue = doc.createTextNode(item->phoneNumbers().at(0)->uri());
+    numberNode.appendChild(numberValue);
+
+    //Write to file
+    file.write(doc.toByteArray());
+    file.close();
+
+    //Add it to the collection
+    addExisting(item);
+
+    return true;
 }
 
 bool
@@ -75,7 +206,7 @@
 WindowsContactBackend::WindowsContactBackend(CollectionMediator<Person>* mediator,
                                              CollectionInterface* parent)
     : CollectionInterface(new WindowsContactEditor(mediator,this), parent)
-    , mediator_(mediator)
+    , mediator_(mediator), watcher_(new QFileSystemWatcher())
 {
 
 }
@@ -89,6 +220,12 @@
 WindowsContactBackend::load()
 {
     QtConcurrent::run(this, &WindowsContactBackend::loadRun);
+    watcher_->addPath(QStandardPaths::writableLocation
+                      (QStandardPaths::HomeLocation) + "/Contacts");
+    QObject::connect(watcher_, &QFileSystemWatcher::directoryChanged, [=](QString path) {
+        Q_UNUSED(path)
+        QtConcurrent::run(this, &WindowsContactBackend::loadRun);
+    });
     return true;
 }
 
@@ -98,84 +235,115 @@
     QDir contactDir(QStandardPaths::writableLocation
                     (QStandardPaths::HomeLocation) + "/Contacts");
     QStringList filesList = contactDir.entryList(QStringList("*.contact"));
-
+    auto ret = true;
     for(auto contactFileName : filesList) {
-        QString contactFilePath
-                (contactDir.absolutePath() + "/" +  contactFileName);
-        QFile contactFile(contactFilePath);
-        if (contactFile.open(QIODevice::ReadOnly)) {
-            QXmlStreamReader reader;
-            Person *p = new Person();
-            QVector<ContactMethod*> contactMethod;
-            reader.setDevice(&contactFile);
-            while (!reader.atEnd()) {
-                reader.readNext();
-                if (reader.isStartElement()) {
-                    QString name = reader.name().toString();
-                    if (name == "FormattedName")
-                        p->setFormattedName(reader.readElementText());
-                    else if (name == "NickName")
-                        p->setNickName(reader.readElementText());
-                    else if (name == "GivenName")
-                        p->setFirstName(reader.readElementText());
-                    else if (name == "FamilyName")
-                        p->setFamilyName(reader.readElementText());
-                    else if (name == "Company")
-                        p->setOrganization(reader.readElementText());
-                    else if (name == "Department")
-                        p->setDepartment(reader.readElementText());
-                    else if (name == "Number") {
-                        QString number = reader.readElementText();
-                        if (not number.isEmpty()) {
-                            ContactMethod *contact = PhoneDirectoryModel::instance()->getNumber(number);
-                            contactMethod.append(contact);
-                        }
+        if (not getPersonFromContactFile(contactDir, contactFileName))
+            ret = false;
+    }
+    return ret;
+}
+
+bool
+WindowsContactBackend::getPersonFromContactFile(const QDir& contactDir,
+                                                const QString &contactFileName)
+{
+    QString contactFilePath
+            (contactDir.absolutePath() + "/" +  contactFileName);
+    QFile contactFile(contactFilePath);
+    if (contactFile.open(QIODevice::ReadOnly)) {
+        QXmlStreamReader reader;
+        Person *p = new Person(this);
+        QVector<ContactMethod*> contactMethod;
+        reader.setDevice(&contactFile);
+        while (!reader.atEnd()) {
+            reader.readNext();
+            if (reader.isStartElement()) {
+                QString name = reader.name().toString();
+                if (name == "FormattedName")
+                    p->setFormattedName(reader.readElementText());
+                else if (name == "NickName")
+                    p->setNickName(reader.readElementText());
+                else if (name == "GivenName")
+                    p->setFirstName(reader.readElementText());
+                else if (name == "FamilyName")
+                    p->setFamilyName(reader.readElementText());
+                else if (name == "Company")
+                    p->setOrganization(reader.readElementText());
+                else if (name == "Department")
+                    p->setDepartment(reader.readElementText());
+                else if (name == "Number") {
+                    QString number = reader.readElementText();
+                    if (not number.isEmpty()) {
+                        ContactMethod *contact =
+                                PhoneDirectoryModel::instance()->getNumber(number,p);
+                        contactMethod.append(contact);
                     }
-                    else if (name == "Photo") {
-                        //FIXME: It seems to be possible to have multiple photo...
+                } else if (name == "ContactID") {
+                    while (reader.name().toString() != "Value")
                         reader.readNext();
-                        if (reader.name().toString() == "Url") {
-                            QString photoValue = reader.readElementText();
-                            QImage photo;
-                            photo.load(photoValue);
-                            p->setPhoto(photo.scaled(sizePhoto_,sizePhoto_, Qt::KeepAspectRatio,
-                                                     Qt::SmoothTransformation));
-                        }
-                    }
-                    else if (name == "EmailAddress") {
-                        QString address;
-                        bool isPreferred = false;
-                        reader.readNext();
-                        while (reader.name().toString() != "EmailAddress"
-                               && !reader.atEnd()) {
-                            if (reader.isStartElement()) {
-                                QString tag = reader.name().toString();
-                                if (tag == "Address")
-                                    address = reader.readElementText();
-                                else if (tag == "Label")
-                                    if (reader.readElementText() == "Preferred")
-                                        isPreferred = true;
-                            }
-                            reader.readNext();
-                        }
-                        if (isPreferred)
-                            p->setPreferredEmail(address);
+                    p->setUid(reader.readElementText().toUtf8());
+                }
+                else if (name == "Photo") {
+                    //FIXME: It seems to be possible to have multiple photo...
+                    reader.readNext();
+                    if (reader.name().toString() == "Url") {
+                        QString photoValue = reader.readElementText();
+                        QImage photo;
+                        photo.load(photoValue);
+                        p->setPhoto(photo.scaled(sizePhoto_,sizePhoto_, Qt::KeepAspectRatio,
+                                                 Qt::SmoothTransformation));
                     }
                 }
+                else if (name == "EmailAddress") {
+                    QString address;
+                    bool isPreferred = false;
+                    reader.readNext();
+                    while (reader.name().toString() != "EmailAddress"
+                           && !reader.atEnd()) {
+                        if (reader.isStartElement()) {
+                            QString tag = reader.name().toString();
+                            if (tag == "Address")
+                                address = reader.readElementText();
+                            else if (tag == "Label")
+                                if (reader.readElementText() == "Preferred")
+                                    isPreferred = true;
+                        }
+                        reader.readNext();
+                    }
+                    if (isPreferred)
+                        p->setPreferredEmail(address);
+                }
             }
-            if (reader.hasError()) {
-                qDebug() << reader.errorString();
-            } else {
+        }
+        if (reader.hasError()) {
+            qDebug() << reader.errorString();
+            contactFile.close();
+            return false;
+        } else {
+            Person* existing = PersonModel::instance()->getPersonByUid(p->uid());
+            if (existing) {
                 if (contactMethod.size() > 0)
-                    p->setContactMethods(contactMethod);
+                    existing->setContactMethods ( contactMethod   );
+                existing->setNickName       ( p->nickName()       );
+                existing->setFirstName      ( p->firstName()      );
+                existing->setFamilyName     ( p->secondName()     );
+                existing->setFormattedName  ( p->formattedName()  );
+                existing->setOrganization   ( p->organization()   );
+                existing->setPreferredEmail ( p->preferredEmail() );
+                existing->setGroup          ( p->group()          );
+                existing->setDepartment     ( p->department()     );
+                existing->setPhoto          ( p->photo()          );
+                delete p;
+            } else {
+                p->setContactMethods(contactMethod);
                 editor<Person>()->addExisting(p);
             }
-        } else {
-            qDebug() << "Error Opening contact file : " << contactFileName;
+            return true;
         }
+    } else {
+        qDebug() << "Error Opening contact file : " << contactFileName;
+        return false;
     }
-
-    return false;
 }
 
 bool
@@ -218,6 +386,9 @@
 {
     return (
                 CollectionInterface::SupportedFeatures::NONE |
-                CollectionInterface::SupportedFeatures::LOAD);
+                CollectionInterface::SupportedFeatures::LOAD |
+                CollectionInterface::SupportedFeatures::SAVE |
+                CollectionInterface::SupportedFeatures::REMOVE |
+                CollectionInterface::SupportedFeatures::ADD);
 }
 
diff --git a/windowscontactbackend.h b/windowscontactbackend.h
index c804a06..160b2ac 100644
--- a/windowscontactbackend.h
+++ b/windowscontactbackend.h
@@ -25,6 +25,7 @@
 #include <QXmlStreamReader>
 #include <QtConcurrent/QtConcurrent>
 #include <QImage>
+#include <QFileSystemWatcher>
 
 #include "person.h"
 #include "collectioninterface.h"
@@ -51,6 +52,10 @@
 private:
     CollectionMediator<Person>*  mediator_;
     constexpr static int sizePhoto_ = 50;
+    QFileSystemWatcher* watcher_;
+
+private:
+    bool getPersonFromContactFile(const QDir &contactDir, const QString& contactFileName);
 };
 
 class WindowsContactEditor : public CollectionEditor<Person>