TizenRefApp-5705 Implement Import controller 91/60091/6
authorNataliia Sydorchuk <n.sydorchuk@samsung.com>
Thu, 25 Feb 2016 08:43:52 +0000 (10:43 +0200)
committerNataliia Sydorchuk <n.sydorchuk@samsung.com>
Thu, 25 Feb 2016 08:44:11 +0000 (10:44 +0200)
Change-Id: I3c1806029cb802ba811bea53d71600ac4e83117d
Signed-off-by: Nataliia Sydorchuk <n.sydorchuk@samsung.com>
lib-apps-common/inc/Ui/ProgressController.h
lib-apps-common/src/Ui/ProgressController.cpp
lib-contact/inc/Contacts/Settings/ExportController.h
lib-contact/inc/Contacts/Settings/ExportItem.h
lib-contact/inc/Contacts/Settings/ImportController.h [new file with mode: 0644]
lib-contact/src/Contacts/Settings/ExportController.cpp
lib-contact/src/Contacts/Settings/ExportItem.cpp
lib-contact/src/Contacts/Settings/ImportController.cpp [new file with mode: 0644]

index c241f1b..c375e5b 100644 (file)
@@ -19,6 +19,7 @@
 #define PROGRESS_CONTROLLER_H
 
 #include <Elementary.h>
+#include <condition_variable>
 #include <functional>
 #include <tizen.h>
 
@@ -33,11 +34,6 @@ namespace Ui
        {
        public:
                /**
-                * @brief Finish progress callback.
-                */
-               typedef std::function<void(const ProgressController &)> FinishCallback;
-
-               /**
                 * @brief Create controller for ProgressPopup.
                 * @param[in]   parent      Parent object
                 * @param[in]   title       Progress popup title
@@ -54,15 +50,10 @@ namespace Ui
                 */
                void run();
 
-               /**
-                * @brief Set finish function which is called when the progress is over.
-                * @param[in]   callback    Finish function
-                */
-               void setFinishCallback(FinishCallback callback);
-
        protected:
-               virtual void onStart(Ecore_Thread *thread) = 0;
-               virtual void onCanceled() = 0;
+               virtual void onStart() = 0;
+               virtual void onFinish() { }
+               virtual void onCanceled() { }
                virtual bool onCancel();
 
                void cancel();
@@ -77,8 +68,9 @@ namespace Ui
                static void onCanceled(void *data, Ecore_Thread *thread);
 
        private:
-               bool m_IsCanceled;
-               FinishCallback m_OnFinish;
+               std::condition_variable m_ContinueCondition;
+               bool m_IsPopupUpdating;
+               Ecore_Thread *m_MainThread;
                ProgressPopup *m_ProgressPopup;
                Ecore_Thread *m_Thread;
        };
index e4f85c6..a5b90fd 100644 (file)
@@ -23,7 +23,7 @@
 using namespace Ui;
 
 ProgressController::ProgressController(Evas_Object *parent, const char *title, int maxValue)
-       : m_IsCanceled(false), m_ProgressPopup(nullptr), m_Thread(nullptr)
+       : m_MainThread(nullptr), m_ProgressPopup(nullptr), m_Thread(nullptr)
 {
        createProgressPopup(parent, title, maxValue);
 }
@@ -35,12 +35,7 @@ ProgressController::~ProgressController()
 
 void ProgressController::run()
 {
-       m_Thread = ecore_thread_feedback_run(onStart, onNotify, onFinish, onCanceled, this, EINA_FALSE);
-}
-
-void ProgressController::setFinishCallback(FinishCallback callback)
-{
-       m_OnFinish = std::move(callback);
+       m_MainThread = ecore_thread_feedback_run(onStart, onNotify, onFinish, onCanceled, this, EINA_FALSE);
 }
 
 bool ProgressController::onCancel()
@@ -50,20 +45,27 @@ bool ProgressController::onCancel()
 
 void ProgressController::cancel()
 {
-       m_IsCanceled = true;
+       ecore_thread_cancel(m_MainThread);
 }
 
 bool ProgressController::onProgress(size_t value)
 {
        ecore_thread_feedback(m_Thread, (void *)value);
+       m_IsPopupUpdating = true;
 
-       return !m_IsCanceled;
+       std::mutex condVariableMutex;
+       std::unique_lock<std::mutex> locker(condVariableMutex);
+       m_ContinueCondition.wait(locker, [this]{
+               return !m_IsPopupUpdating;
+       });
+
+       return !ecore_thread_check(m_Thread);
 }
 
 void ProgressController::createProgressPopup(Evas_Object *parent, const char *title, int maxValue)
 {
        m_ProgressPopup = new Ui::ProgressPopup(maxValue);
-       RETM_IF_ERR(!m_ProgressPopup, "m_ProgressPopup is NULL");
+       RETM_IF(!m_ProgressPopup, "m_ProgressPopup is NULL");
 
        m_ProgressPopup->create(parent);
        m_ProgressPopup->setTitle(title);
@@ -82,31 +84,36 @@ void ProgressController::createProgressPopup(Evas_Object *parent, const char *ti
 
 void ProgressController::onStart(void *data, Ecore_Thread *thread)
 {
-       RETM_IF_ERR(!data, "invalid data");
+       RETM_IF(!data, "invalid data");
+
        ProgressController *controller = (ProgressController *)data;
-       controller->onStart(thread);
+       controller->m_Thread = thread;
+       controller->onStart();
 }
 
 void ProgressController::onNotify(void *data, Ecore_Thread *thread, void *msgData)
 {
-       RETM_IF_ERR(!data || !msgData, "invalid data");
+       RETM_IF(!data || !msgData, "invalid data");
        ProgressController *controller = (ProgressController *)data;
 
        controller->m_ProgressPopup->setProgress((size_t)msgData);
+
+       controller->m_IsPopupUpdating = false;
+       controller->m_ContinueCondition.notify_one();
 }
 
 void ProgressController::onFinish(void *data, Ecore_Thread *thread)
 {
-       RETM_IF_ERR(!data, "invalid data");
+       RETM_IF(!data, "invalid data");
        ProgressController *controller = (ProgressController *)data;
-       controller->m_OnFinish(*controller);
+       controller->onFinish();
 
        delete controller;
 }
 
 void ProgressController::onCanceled(void *data, Ecore_Thread *thread)
 {
-       RETM_IF_ERR(!data, "invalid data");
+       RETM_IF(!data, "invalid data");
        ProgressController *controller = (ProgressController *)data;
        controller->onCanceled();
 
index 09fa05c..5d7b0d8 100644 (file)
@@ -55,29 +55,22 @@ namespace Contacts
                                        std::vector<int> personIdList, StorageType vcardStorage);
 
                        /**
-                        * @return Vcard path relative to the storage root directory.
-                        */
-                       const char *getVcardRelativePath() const;
-
-                       /**
                         * @return Vcard path.
                         */
                        const std::string &getVcardPath() const;
 
-                       /**
-                        * @return Total count of exported contacts.
-                        */
-                       size_t getTotalCount() const;
-
                private:
                        void createDirectory(const std::string &directoryPath);
                        std::string getVcardDirectoryPath();
+                       const char *getVcardRelativePath() const;
                        std::string getVcardFilePath();
 
-                       virtual void onStart(Ecore_Thread *thread) override;
+                       virtual void onStart() override;
+                       virtual void onFinish() override;
                        virtual void onCanceled() override;
 
                private:
+                       Evas_Object *m_Parent;
                        std::vector<int> m_PersonIdList;
                        std::string m_VcardPath;
                        StorageType m_VcardStorage;
index 668b106..1c42343 100644 (file)
@@ -43,8 +43,6 @@ namespace Contacts
 
                        void onPickResult(app_control_h request, app_control_h reply,
                                        app_control_result_e result);
-                       void onImportFinish(const Ui::ProgressController &controller);
-                       void createFinishPopup(const char *text);
 
                private:
                        App::AppControl m_AppControl;
diff --git a/lib-contact/inc/Contacts/Settings/ImportController.h b/lib-contact/inc/Contacts/Settings/ImportController.h
new file mode 100644 (file)
index 0000000..0546f69
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef CONTACTS_SETTINGS_IMPORT_CONTROLLER_H
+#define CONTACTS_SETTINGS_IMPORT_CONTROLLER_H
+
+#include <contacts.h>
+#include <string>
+#include <vector>
+
+#include "Ui/ProgressController.h"
+
+namespace Ui
+{
+       class Popup;
+}
+
+namespace Contacts
+{
+       namespace Settings
+       {
+               /**
+                * @brief Controller for Import ProgressPopup
+                */
+               class ImportController : public Ui::ProgressController
+               {
+               public:
+                       /**
+                        * @brief Create controller for Import ProgressPopup.
+                        * @param[in]   parent          Parent object.
+                        * @param[in]   title           Progress popup title.
+                        * @param[in]   totalCount      Total count of contacts that will be imported.
+                        * @param[in]   vcards          Vcards which will be imported.
+                        */
+                       ImportController(Evas_Object *parent, const char *title,
+                                       size_t totalCount, std::vector<std::string> vcards);
+
+               private:
+                       /**
+                        * @brief Private destructor. Only parent class ProgressController should call it.
+                        */
+                       virtual ~ImportController() override;
+
+                       void createCancelPopup(Evas_Object *parent);
+                       bool onPopupContinue();
+                       bool onPopupCancel();
+
+                       virtual void onStart() override;
+                       virtual void onFinish() override;
+                       virtual void onCanceled() override;
+                       virtual bool onCancel() override;
+
+                       static bool onVcardParse(contacts_record_h record, void *data);
+
+               private:
+                       Ui::Popup *m_CancelPopup;
+                       std::condition_variable m_ContinueCondition;
+                       std::string m_CurrentVcard;
+                       std::vector<int> m_ImportedContacts;
+                       bool m_IsPaused;
+                       std::vector<std::string> m_Vcards;
+               };
+       }
+}
+
+#endif /* CONTACTS_SETTINGS_IMPORT_CONTROLLER_H */
index 605eada..0adba39 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "Contacts/Common/Utils.h"
 #include "Contacts/Settings/ExportController.h"
+#include "Ui/Popup.h"
 #include "Utils/Logger.h"
 
 #include <contacts.h>
@@ -43,7 +44,7 @@ namespace
 
 ExportController::ExportController(Evas_Object *parent, const char *title,
                std::vector<int> personIdList, StorageType vcardStorage)
-       : ProgressController(parent, title, personIdList.size()),
+       : ProgressController(parent, title, personIdList.size()), m_Parent(parent),
          m_PersonIdList(std::move(personIdList)), m_VcardStorage(vcardStorage)
 {
        m_VcardPath = getVcardFilePath();
@@ -66,11 +67,6 @@ const std::string &ExportController::getVcardPath() const
        return m_VcardPath;
 }
 
-size_t ExportController::getTotalCount() const
-{
-       return m_PersonIdList.size();
-}
-
 void ExportController::createDirectory(const std::string &directoryPath)
 {
        std::string command("mkdir -p ");
@@ -119,32 +115,45 @@ std::string ExportController::getVcardFilePath()
        return std::string();
 }
 
-void ExportController::onStart(Ecore_Thread *thread)
+void ExportController::onStart()
 {
        FILE *file = fopen(m_VcardPath.c_str(), "a");
        RETM_IF(!file, "fopen failed: %s", strerror(errno));
+       contacts_connect_on_thread();
        size_t currentCount = 0;
 
        for (auto &&personId : m_PersonIdList) {
                contacts_record_h personRecord = nullptr;
                int err = contacts_db_get_record(_contacts_person._uri, personId, &personRecord);
-               LOG_IF_ERR(err, continue, "contacts_db_get_record failed: ");
+               LOG_IF_ERR(err, continue, "contacts_db_get_record() failed.");
 
                char *vcardStream = nullptr;
                err = contacts_vcard_make_from_person(personRecord, &vcardStream);
                contacts_record_destroy(personRecord, true);
-               LOG_IF_ERR(err, continue, "contacts_vcard_make_from_person failed: ");
+               LOG_IF_ERR(err, continue, "contacts_vcard_make_from_person() failed.");
 
                fputs(vcardStream, file);
                free(vcardStream);
 
-               ++currentCount;
-               if (!onProgress(currentCount)) {
-                       ecore_thread_cancel(thread);
+               if (!onProgress(++currentCount)) {
                        break;
                }
        }
        fclose(file);
+       contacts_disconnect_on_thread();
+}
+
+void ExportController::onFinish()
+{
+       char text[BUFFER_SIZE] = { 0, };
+       snprintf(text, sizeof(text), _("IDS_PB_POP_P1SD_CONTACTS_HAVE_BEEN_EXPORTED_TO_P2SS"),
+                       m_PersonIdList.size(), getVcardRelativePath());
+
+       Ui::Popup *finishPopup = new Ui::Popup();
+       finishPopup->create(m_Parent);
+       finishPopup->setTitle("IDS_PB_HEADER_CONTACTS_EXPORTED_ABB");
+       finishPopup->setText(text);
+       finishPopup->addButton("IDS_PB_BUTTON_OK_ABB2");
 }
 
 void ExportController::onCanceled()
index 1e98568..61e5ae2 100644 (file)
@@ -53,26 +53,5 @@ void ExportItem::onPickResult(app_control_h request, app_control_h reply,
        ExportController *exporter = new ExportController(
                        getParent()->getEvasObject(), "IDS_PB_HEADER_EXPORT_CONTACTS_ABB",
                        std::move(personIdList), StorageDevice);
-       exporter->setFinishCallback(std::bind(&ExportItem::onImportFinish, this, std::placeholders::_1));
        exporter->run();
 }
-
-void ExportItem::onImportFinish(const ProgressController &controller)
-{
-       const ExportController &exporter = static_cast<const ExportController &>(controller);
-
-       char text[BUFFER_SIZE] = { 0, };
-       snprintf(text, sizeof(text), _("IDS_PB_POP_P1SD_CONTACTS_HAVE_BEEN_EXPORTED_TO_P2SS"),
-                       exporter.getTotalCount(), exporter.getVcardRelativePath());
-
-       createFinishPopup(text);
-}
-
-void ExportItem::createFinishPopup(const char *text)
-{
-       Ui::Popup *finishPopup = new Ui::Popup();
-       finishPopup->create(getParent()->getEvasObject());
-       finishPopup->setTitle("IDS_PB_HEADER_CONTACTS_EXPORTED_ABB");
-       finishPopup->setText(text);
-       finishPopup->addButton("IDS_PB_BUTTON_OK_ABB2");
-}
diff --git a/lib-contact/src/Contacts/Settings/ImportController.cpp b/lib-contact/src/Contacts/Settings/ImportController.cpp
new file mode 100644 (file)
index 0000000..35e09e9
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Contacts/Settings/ImportController.h"
+#include "Contacts/Utils.h"
+#include "Ui/Popup.h"
+#include "Utils/Logger.h"
+
+#include <notification.h>
+
+using namespace Contacts::Settings;
+
+#define BUFFER_SIZE        1024
+
+ImportController::ImportController(Evas_Object *parent, const char *title,
+                       size_t totalCount, std::vector<std::string> vcards)
+       : ProgressController(parent, title, totalCount), m_IsPaused(false),
+         m_Vcards(std::move(vcards))
+{
+       createCancelPopup(parent);
+}
+
+ImportController::~ImportController()
+{
+       delete m_CancelPopup;
+}
+
+void ImportController::createCancelPopup(Evas_Object *parent)
+{
+       m_CancelPopup = new Ui::Popup();
+       m_CancelPopup->create(parent);
+       m_CancelPopup->setTitle("IDS_PB_HEADER_CANCEL_IMPORTING_ABB");
+
+       auto onContinueFunction = std::bind(&ImportController::onPopupContinue, this);
+       m_CancelPopup->setBackCallback(onContinueFunction);
+       m_CancelPopup->addButton("IDS_PB_BUTTON_CANCEL", onContinueFunction);
+       m_CancelPopup->addButton("IDS_PB_BUTTON_OK_ABB2", std::bind(&ImportController::onPopupCancel, this));
+
+       evas_object_hide(m_CancelPopup->getEvasObject());
+}
+
+bool ImportController::onPopupContinue()
+{
+       evas_object_hide(m_CancelPopup->getEvasObject());
+       m_IsPaused = false;
+       m_ContinueCondition.notify_one();
+
+       return false;
+}
+
+bool ImportController::onPopupCancel()
+{
+       cancel();
+       m_IsPaused = false;
+       m_ContinueCondition.notify_one();
+       m_CancelPopup = nullptr;
+
+       return true;
+}
+
+void ImportController::onStart()
+{
+       contacts_connect_on_thread();
+
+       for (auto &&vcard : m_Vcards) {
+               m_CurrentVcard = vcard;
+
+               int err = contacts_vcard_parse_to_contact_foreach(vcard.c_str(), onVcardParse, this);
+               WARN_IF_ERR(err, "contacts_vcard_parse_to_contact_foreach() failed.");
+       }
+
+       contacts_disconnect_on_thread();
+}
+
+void ImportController::onFinish()
+{
+       int count = m_ImportedContacts.size();
+       RETM_IF(count <= 0, "invalid count");
+       int err = NOTIFICATION_ERROR_NONE;
+
+       if (count == 1) {
+               err = notification_status_message_post(_("IDS_PB_TPOP_1_CONTACT_IMPORTED"));
+       } else {
+               char text[BUFFER_SIZE] = { 0, };
+               snprintf(text, sizeof(text), _("IDS_PB_TPOP_PD_CONTACTS_IMPORTED"), count);
+               err = notification_status_message_post(text);
+       }
+       WARN_IF_ERR(err, "notification_status_message_post() failed.");
+}
+
+void ImportController::onCanceled()
+{
+       contacts_db_delete_records(_contacts_contact._uri, m_ImportedContacts.data(), m_ImportedContacts.size());
+
+       int err = notification_status_message_post(_("IDS_PB_SBODY_IMPORTING_CANCELLED_M_STATUS_ABB"));
+       WARN_IF_ERR(err, "notification_status_message_post() failed.");
+}
+
+bool ImportController::onCancel()
+{
+       char text[BUFFER_SIZE] = { 0, };
+       snprintf(text, sizeof(text), _("IDS_PB_POP_CONTACTS_WILL_STOP_BEING_IMPORTED_FROM_PS"), m_CurrentVcard.c_str());
+       m_CancelPopup->setText(text);
+
+       evas_object_show(m_CancelPopup->getEvasObject());
+       m_IsPaused = true;
+
+       return false;
+}
+
+bool ImportController::onVcardParse(contacts_record_h record, void *data)
+{
+       RETVM_IF(!record || !data, true, "invalid data");
+       ImportController *importer = (ImportController *)data;
+
+       int id = 0;
+       int err = contacts_db_insert_record(record, &id);
+       RETVM_IF_ERR(err, true, "contacts_db_insert_record() failed.");
+
+       importer->m_ImportedContacts.push_back(id);
+
+       if (!importer->onProgress(importer->m_ImportedContacts.size())) {
+               return false;
+       }
+
+       std::mutex condVariableMutex;
+       std::unique_lock<std::mutex> locker(condVariableMutex);
+       importer->m_ContinueCondition.wait(locker, [importer]{
+               return !importer->m_IsPaused;
+       });
+
+       // Return true to continue to scan next contact, according to contacts_vcard_parse_cb specification.
+       return true;
+}