From 8c2f54c3f5b9889c517429129347ba63c6fc8430 Mon Sep 17 00:00:00 2001 From: Nataliia Sydorchuk Date: Thu, 25 Feb 2016 10:43:52 +0200 Subject: [PATCH] TizenRefApp-5705 Implement Import controller Change-Id: I3c1806029cb802ba811bea53d71600ac4e83117d Signed-off-by: Nataliia Sydorchuk --- lib-apps-common/inc/Ui/ProgressController.h | 22 +-- lib-apps-common/src/Ui/ProgressController.cpp | 39 +++--- .../inc/Contacts/Settings/ExportController.h | 15 +-- lib-contact/inc/Contacts/Settings/ExportItem.h | 2 - .../inc/Contacts/Settings/ImportController.h | 80 +++++++++++ .../src/Contacts/Settings/ExportController.cpp | 33 +++-- lib-contact/src/Contacts/Settings/ExportItem.cpp | 21 --- .../src/Contacts/Settings/ImportController.cpp | 148 +++++++++++++++++++++ 8 files changed, 283 insertions(+), 77 deletions(-) create mode 100644 lib-contact/inc/Contacts/Settings/ImportController.h create mode 100644 lib-contact/src/Contacts/Settings/ImportController.cpp diff --git a/lib-apps-common/inc/Ui/ProgressController.h b/lib-apps-common/inc/Ui/ProgressController.h index c241f1b..c375e5b 100644 --- a/lib-apps-common/inc/Ui/ProgressController.h +++ b/lib-apps-common/inc/Ui/ProgressController.h @@ -19,6 +19,7 @@ #define PROGRESS_CONTROLLER_H #include +#include #include #include @@ -33,11 +34,6 @@ namespace Ui { public: /** - * @brief Finish progress callback. - */ - typedef std::function 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; }; diff --git a/lib-apps-common/src/Ui/ProgressController.cpp b/lib-apps-common/src/Ui/ProgressController.cpp index e4f85c6..a5b90fd 100644 --- a/lib-apps-common/src/Ui/ProgressController.cpp +++ b/lib-apps-common/src/Ui/ProgressController.cpp @@ -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 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(); diff --git a/lib-contact/inc/Contacts/Settings/ExportController.h b/lib-contact/inc/Contacts/Settings/ExportController.h index 09fa05c..5d7b0d8 100644 --- a/lib-contact/inc/Contacts/Settings/ExportController.h +++ b/lib-contact/inc/Contacts/Settings/ExportController.h @@ -55,29 +55,22 @@ namespace Contacts std::vector 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 m_PersonIdList; std::string m_VcardPath; StorageType m_VcardStorage; diff --git a/lib-contact/inc/Contacts/Settings/ExportItem.h b/lib-contact/inc/Contacts/Settings/ExportItem.h index 668b106..1c42343 100644 --- a/lib-contact/inc/Contacts/Settings/ExportItem.h +++ b/lib-contact/inc/Contacts/Settings/ExportItem.h @@ -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 index 0000000..0546f69 --- /dev/null +++ b/lib-contact/inc/Contacts/Settings/ImportController.h @@ -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 +#include +#include + +#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 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 m_ImportedContacts; + bool m_IsPaused; + std::vector m_Vcards; + }; + } +} + +#endif /* CONTACTS_SETTINGS_IMPORT_CONTROLLER_H */ diff --git a/lib-contact/src/Contacts/Settings/ExportController.cpp b/lib-contact/src/Contacts/Settings/ExportController.cpp index 605eada..0adba39 100644 --- a/lib-contact/src/Contacts/Settings/ExportController.cpp +++ b/lib-contact/src/Contacts/Settings/ExportController.cpp @@ -17,6 +17,7 @@ #include "Contacts/Common/Utils.h" #include "Contacts/Settings/ExportController.h" +#include "Ui/Popup.h" #include "Utils/Logger.h" #include @@ -43,7 +44,7 @@ namespace ExportController::ExportController(Evas_Object *parent, const char *title, std::vector 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() diff --git a/lib-contact/src/Contacts/Settings/ExportItem.cpp b/lib-contact/src/Contacts/Settings/ExportItem.cpp index 1e98568..61e5ae2 100644 --- a/lib-contact/src/Contacts/Settings/ExportItem.cpp +++ b/lib-contact/src/Contacts/Settings/ExportItem.cpp @@ -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(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 index 0000000..35e09e9 --- /dev/null +++ b/lib-contact/src/Contacts/Settings/ImportController.cpp @@ -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 + +using namespace Contacts::Settings; + +#define BUFFER_SIZE 1024 + +ImportController::ImportController(Evas_Object *parent, const char *title, + size_t totalCount, std::vector 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 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; +} -- 2.7.4