--- /dev/null
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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 __GALLERY_MODEL_I_JOB_H__
+#define __GALLERY_MODEL_I_JOB_H__
+
+#include "types.h"
+
+namespace gallery {
+
+ class IJob : public ucl::Polymorphic {
+ public:
+ virtual ucl::Result getResult() const = 0;
+ virtual bool isCancelable() const = 0;
+ virtual ucl::Result cancel() = 0;
+ };
+}
+
+#endif // __GALLERY_MODEL_I_JOB_H__
using ThumbnailPathGetCb =
ucl::Delegate<void(ucl::Result, const std::string &path)>;
+ class Remover;
+ class RemoverBuilder final {
+ public:
+ RemoverBuilder &setItems(MediaItems items);
+ IJobSRef build(const NotiHandler &onComplete) const;
+ private:
+ ucl::SharedRef<MediaItems> m_items;
+ };
+
public:
static MediaItemSRef newInstance(media_info_h media);
virtual ~MediaItem();
#ifndef __GALLERY_MODEL_TYPES_H__
#define __GALLERY_MODEL_TYPES_H__
+#include <vector>
+
#include <media_content.h>
#include "../types.h"
OTHERS
};
+ UCL_DECLARE_REF_ALIASES(IJob);
+
UCL_DECLARE_REF_ALIASES(Gallery);
UCL_DECLARE_REF_ALIASES(IMediaAlbum);
UCL_DECLARE_REF_ALIASES(MediaItem);
+
+ using MediaItems = std::vector<MediaItemSRef>;
}
#endif // __GALLERY_MODEL_TYPES_H__
Builder &setProcessingText(ucl::TString text);
Builder &setCompleteText(ucl::TString text);
Builder &setIconType(IconType value);
+ Builder &setForceProgress(bool value);
ProcessingPresenterSRef build(ucl::Widget &parent) const;
private:
ucl::TString m_processingText;
ucl::TString m_completeText;
IconType m_iconType;
+ bool m_forceProgress;
};
using DismissHandler = ucl::WeakDelegate<void()>;
ucl::Result prepare(ucl::Widget &parent,
const ucl::TString &processingText,
- const ucl::TString &completeText);
+ const ucl::TString &completeText,
+ bool forceProgress);
ucl::Result createWidget(ucl::Widget &parent,
const ucl::TString &processingText);
bool resetTimer(double timeout);
void stopTimer();
+ void showProgress();
+
void tryShowPopup();
void dismissPopup(bool force = false);
#include "ucl/util/memory.h"
#include "ucl/util/delegation.h"
+#include "ucl/misc/smartDelegation.h"
+
+namespace gallery {
+
+ using NotiHandler = ucl::WeakDelegate<void()>;
+}
+
#endif // __GALLERY_TYPES_H__
--- /dev/null
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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 "BaseJob.h"
+
+#include <Ecore.h>
+
+#include "common.h"
+
+namespace gallery {
+
+ using namespace ucl;
+
+ BaseJob::BaseJob(const NotiHandler &onComplete,
+ const bool isCancelable) :
+ m_onComplete(onComplete),
+ m_isCancelable(isCancelable),
+ m_result(RES_ILLEGAL_STATE),
+ m_selfPtr(new BaseJob *(this)),
+ m_isCancelled(0)
+ {
+ }
+
+ BaseJob::~BaseJob()
+ {
+ finish();
+ }
+
+ Result BaseJob::prepare()
+ {
+ if (!m_thread.start(
+ [this]()
+ {
+ m_result = execute();
+ notifyCompleteAsync();
+ }
+ )) {
+ LOG_RETURN(RES_FAIL, "m_thread->start() failed!");
+ }
+ return RES_OK;
+ }
+
+ Result BaseJob::getResult() const
+ {
+ if (!m_thread.wasJoinded()) {
+ LOG_RETURN(RES_ILLEGAL_STATE, "Job is not complete!");
+ }
+ return m_result;
+ }
+
+ bool BaseJob::isCancelable() const
+ {
+ return m_isCancelable;
+ }
+
+ Result BaseJob::cancel()
+ {
+ if (!m_isCancelable) {
+ LOG_RETURN(RES_NOT_SUPPORTED, "Not cancelable!");
+ }
+ if (isCancelled()) {
+ return RES_FALSE;
+ }
+ m_isCancelled.store(true);
+ return RES_OK;
+ }
+
+ bool BaseJob::isCancelled() const
+ {
+ return m_isCancelled.load();
+ }
+
+ void BaseJob::notifyCompleteAsync()
+ {
+ ecore_main_loop_thread_safe_call_async(
+ [](void *data)
+ {
+ const auto selfPtr = static_cast<BaseJob **>(data);
+ const auto self = *selfPtr;
+ delete selfPtr;
+ if (self) {
+ self->m_selfPtr = nullptr;
+ self->finish();
+ }
+ },
+ m_selfPtr);
+ }
+
+ void BaseJob::finish()
+ {
+ if (!m_thread.wasJoinded()) {
+ m_thread.join();
+ if (m_selfPtr) {
+ *m_selfPtr = nullptr;
+ }
+ if (m_onComplete) {
+ m_onComplete();
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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 __GALLERY_MODEL_BASE_JOB_H__
+#define __GALLERY_MODEL_BASE_JOB_H__
+
+#include <atomic>
+
+#include "ucl/util/threading/Thread.h"
+
+#include "model/IJob.h"
+#include "types.h"
+
+namespace gallery {
+
+ class BaseJob : public IJob {
+ public:
+ // IJob //
+
+ virtual ucl::Result getResult() const final override;
+ virtual bool isCancelable() const final override;
+ virtual ucl::Result cancel() final override;
+
+ protected:
+ BaseJob(const NotiHandler &onComplete,
+ bool isCancelable);
+ virtual ~BaseJob();
+
+ ucl::Result prepare();
+
+ bool isCancelled() const;
+
+ virtual ucl::Result execute() = 0;
+
+ private:
+ void notifyCompleteAsync();
+ void finish();
+
+ private:
+ const NotiHandler m_onComplete;
+ const bool m_isCancelable;
+ ucl::Thread m_thread;
+ ucl::Result m_result;
+ BaseJob **m_selfPtr;
+ std::atomic_int m_isCancelled;
+ };
+}
+
+#endif // __GALLERY_MODEL_BASE_JOB_H__
Result GalleryAlbum::forEachMedia(EachCb cb) const
{
+ MutexLock lock(getMediaMutex());
+
const int ret = media_info_foreach_media_from_db(m_filter,
[](media_info_h media, void *user_data)
{
Result GalleryAlbum::getMediaCount(int &count) const
{
+ MutexLock lock(getMediaMutex());
+
const int ret = media_info_get_media_count_from_db(m_filter, &count);
if ((ret != 0) || (count < 0)) {
count = 0;
LOG_RETURN(RES_FAIL,
"media_info_foreach_media_from_db() failed: %d", ret);
}
+
return RES_OK;
}
}
#include <Ecore_File.h>
+#include "BaseJob.h"
+
#include "common.h"
namespace gallery {
using namespace ucl;
+ // MediaItem::Remover //
+
+ class MediaItem::Remover final : public BaseJob {
+ public:
+ friend class MediaItem::RemoverBuilder;
+ Remover(const NotiHandler &onComplete,
+ const SharedRef<const MediaItems> &items) :
+ BaseJob(onComplete, false),
+ m_items(items)
+ {
+ }
+
+ protected:
+ // BaseJob //
+ virtual Result execute() final override
+ {
+ MutexLock lock(getMediaMutex());
+
+ for (auto &item: *m_items) {
+ if (item) {
+ FAIL_RETURN(item->removeFile(),
+ "item->removeFile() failed!");
+ } else {
+ ELOG("item is NULL!");
+ }
+ }
+
+ return RES_OK;
+ }
+
+ private:
+ const SharedRef<const MediaItems> m_items;
+ };
+
+ // MediaItem::RemoverBuilder //
+
+ MediaItem::RemoverBuilder &MediaItem::RemoverBuilder::
+ setItems(MediaItems items)
+ {
+ m_items = makeShared<MediaItems>(std::move(items));
+ return *this;
+ }
+
+ IJobSRef MediaItem::RemoverBuilder::build(
+ const NotiHandler &onComplete) const
+ {
+ if (!onComplete) {
+ LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "onComplete is NULL!");
+ }
+ if (isEmpty(m_items)) {
+ LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "Builder is empty!");
+ }
+
+ auto result = makeShared<Remover>(onComplete, m_items);
+
+ FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
+
+ return result;
+ }
+
+ // MediaItem //
+
MediaItem::MediaItem(const MediaType type) :
m_type(type),
m_resolutionX(0),
LOG_RETURN(RES_FAIL, "File can't be removed!");
}
- const int ret = media_info_delete_from_db(m_mediaId.c_str());
- if (ret != 0) {
- LOG_RETURN(RES_FAIL, "media_info_delete_from_db() failed: %d", ret);
- }
+ {
+ MutexLock lock(getMediaMutex());
- freeMediaInfo();
- m_isValid = false;
+ const int ret = media_info_delete_from_db(m_mediaId.c_str());
+ if (ret != 0) {
+ LOG_RETURN(RES_FAIL, "media_info_delete_from_db() failed: %d", ret);
+ }
+
+ freeMediaInfo();
+ m_isValid = false;
+ }
if (!ecore_file_remove(m_filePath.c_str())) {
FLOG("ecore_file_remove() failed! Attemting to rescan....");
+ MutexLock lock(getMediaMutex());
const int ret = media_content_scan_file(m_filePath.c_str());
if (ret != 0) {
ELOG("media_content_scan_file() failed: %d", ret);
auto cbProxy = util::makeUnique(new ThumbCbProxy{this, cb});
- const int ret = media_info_create_thumbnail(m_media,
- CALLBACK_B(ThumbCbProxy::completeCb), cbProxy.get());
- if (ret != 0) {
- LOG_RETURN(RES_FAIL, "media_info_clone() failed: %d", ret);
+ {
+ MutexLock lock(getMediaMutex());
+
+ const int ret = media_info_create_thumbnail(m_media,
+ CALLBACK_B(ThumbCbProxy::completeCb), cbProxy.get());
+ if (ret != 0) {
+ LOG_RETURN(RES_FAIL, "media_info_clone() failed: %d", ret);
+ }
}
m_thumbCbProxy = std::move(cbProxy);
return;
}
+ MutexLock lock(getMediaMutex());
+
const int ret = media_info_cancel_thumbnail(m_media);
if (ret != 0) {
namespace gallery {
+ using namespace ucl;
+
bool getProperty(media_info_h media,
int (*get)(media_info_h media, char **value),
std::string &result, const bool optional)
}
return true;
}
+
+ Mutex &getMediaMutex()
+ {
+ static Mutex mutex{true};
+ return mutex;
+ }
}
#ifndef __GALLERY_MODEL_HELPERS_H__
#define __GALLERY_MODEL_HELPERS_H__
+#include "ucl/util/threading.h"
+
#include "model/types.h"
namespace gallery {
bool getProperty(image_meta_h imageMeta,
int (*get)(image_meta_h imageMeta, int *value),
int &result, bool mayBeZero = false);
+
+ ucl::Mutex &getMediaMutex();
}
#include "helpers.hpp"
// ProcessingPresenter::Builder //
ProcessingPresenter::Builder::Builder() :
- m_iconType(IconType::NONE)
+ m_iconType(IconType::NONE),
+ m_forceProgress(false)
{
}
return *this;
}
+ ProcessingPresenter::Builder &ProcessingPresenter::Builder::
+ setForceProgress(const bool value)
+ {
+ m_forceProgress = value;
+ return *this;
+ }
+
ProcessingPresenterSRef ProcessingPresenter::Builder::
build(Widget &parent) const
{
auto result = makeShared<ProcessingPresenter>(m_iconType);
FAIL_RETURN_VALUE(result->prepare(parent,
- m_processingText, m_completeText), {},
+ m_processingText, m_completeText, m_forceProgress), {},
"result->prepare() failed!");
return result;
Result ProcessingPresenter::prepare(Widget &parent,
const TString &processingText,
- const TString &completeText)
+ const TString &completeText,
+ const bool forceProgress)
{
FAIL_RETURN(createWidget(parent, processingText),
"createWidget() failed!");
FAIL_RETURN(createIcon(), "createIcon() failed!");
}
- if (!resetTimer(impl::IDLE_WAIT_TIME_SEC)) {
+ if (forceProgress) {
+ showProgress();
+ } else if (!resetTimer(impl::IDLE_WAIT_TIME_SEC)) {
LOG_RETURN(RES_FAIL, "resetTimer() failed!");
}
}
}
+ void ProcessingPresenter::showProgress()
+ {
+ m_widget->emit(impl::SIGNAL_SHOW);
+
+ m_state = State::PROCESSING;
+ m_mayComplete = false;
+
+ resetTimer(impl::PROCESSING_MIN_TIME_SEC);
+ }
+
void ProcessingPresenter::tryShowPopup()
{
if (m_isComplete && m_mayComplete && m_popup) {
switch (m_state) {
case State::WAITING:
- m_widget->emit(impl::SIGNAL_SHOW);
- m_state = State::PROCESSING;
- m_mayComplete = false;
- resetTimer(impl::PROCESSING_MIN_TIME_SEC);
+ showProgress();
break;
case State::PROCESSING:
return RES_FAIL;
}
- m_scrollLockIndex = (m_scrollOffset / m_slotSize);
+ m_scrollLockIndex = std::min(
+ (m_scrollOffset / m_slotSize), (m_itemCount - 1));
m_isInSelectMode = enabled;
if (newScrollOffset != m_scrollOffset) {
DLOG("newScrollOffset: %d; m_scrollOffset: %d;",
newScrollOffset, m_scrollOffset);
- m_scrollOffset= newScrollOffset;
+ m_scrollOffset = newScrollOffset;
return true;
}
class Mutex : public NonCopyable {
public:
- Mutex();
+ Mutex(bool recursive = false);
~Mutex();
void lock();
void unlock();
namespace ucl {
- inline Mutex::Mutex() :
+ inline Mutex::Mutex(const bool recursive) :
m_mutex()
{
- pthread_mutex_init(&m_mutex, NULL);
+ if (recursive) {
+ pthread_mutexattr_t attr = {};
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&m_mutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+ } else {
+ pthread_mutex_init(&m_mutex, nullptr);
+ }
}
inline Mutex::~Mutex()