#define PROGRESS_CONTROLLER_H
#include <Elementary.h>
+#include <condition_variable>
#include <functional>
#include <tizen.h>
{
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
*/
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();
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;
};
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);
}
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()
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);
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();
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;
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;
--- /dev/null
+/*
+ * 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 */
#include "Contacts/Common/Utils.h"
#include "Contacts/Settings/ExportController.h"
+#include "Ui/Popup.h"
#include "Utils/Logger.h"
#include <contacts.h>
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();
return m_VcardPath;
}
-size_t ExportController::getTotalCount() const
-{
- return m_PersonIdList.size();
-}
-
void ExportController::createDirectory(const std::string &directoryPath)
{
std::string command("mkdir -p ");
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()
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");
-}
--- /dev/null
+/*
+ * 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;
+}