worldclock: implement MVP pattern. 72/90172/4
authorRadoslaw Czerski <r.czerski@samsung.com>
Fri, 30 Sep 2016 13:07:19 +0000 (15:07 +0200)
committerRadoslaw Czerski <r.czerski@samsung.com>
Fri, 30 Sep 2016 13:07:19 +0000 (15:07 +0200)
Change-Id: I318885286cc10ca55e293f8f8690ae664de6a070
Signed-off-by: Radoslaw Czerski <r.czerski@samsung.com>
clock/inc/Model/WorldClock.h
clock/inc/Presenter/WorldClockPresenter.h [new file with mode: 0644]
clock/inc/View/WorldClockView.h
clock/src/Model/WorldClock.cpp
clock/src/Presenter/WorldClockPresenter.cpp [new file with mode: 0644]
clock/src/View/MainView.cpp
clock/src/View/WorldClockView.cpp

index 6aa24fe..26c8711 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2016 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 _CLOCK_WORLDCLOCK_H_
 #define _CLOCK_WORLDCLOCK_H_
 
 
 namespace model {
 
-       struct Timezone{
-                       int x_coord;
-                       int zone_width;
-                       int gmt_offset; /*minutes*/
-                       std::vector<model::Location> places;
+       /*
+        * @brief Structure for time zone details
+        */
+
+       struct Timezone {
+                       int x_coord; /**< x coordinate of top-left corner of the time zone area(specified in GUI guide) relative to world map top-left corner */
+                       int zone_width; /**< Width of the time zone given in GUI Guide */
+                       int gmt_offset; /**< [minutes] Time zone offset in relatively to GMT 0. */
+                       std::vector<model::Location> places /**< Locations of the time zone that will be marked on the map */;
        };
 
        class WorldClock {
                public:
+                       enum Direction {
+                               LEFT,
+                               RIGHT
+                       };
+
+                       /*
+                        * @brief Constructs the WorldClock object. It will also load UserLocation list from preferences.
+                        */
                        WorldClock();
+
+                       /*
+                        * @brief Locations list made of locations(cities) chosen by user.
+                        */
                        std::vector<model::Location> UserLocations;
 
+                       /*
+                        * @brief Adds location to UserLocations list.
+                        * @remarks The location is retrieved from called Worldclock-efl app
+                        *
+                        * @param[in] l location to add
+                        */
                        void AddUserLocation(model::Location l);
+
+                       /*
+                        * @brief Deletes location from UserLocations list
+                        *
+                        * @param[in] l location to remove from UserLocation list
+                        */
                        void RemoveUserLocation(model::Location l);
 
-                       void InitTimeZones();
-                       void InitLocations();
+                       /*
+                        * @brief Gets current time zone set to display
+                        *
+                        * @return time zone number [from 0 to (time_zones_.size() - 1)]
+                        */
                        int GetCurrentTimezoneNo() const;
+
+                       /*
+                        * @brief Gets time zone marked ad current
+                        *
+                        * @return pointer to time zone
+                        */
+                       const Timezone *GetCurrentTimezone() const;
+
+                       /*
+                        * @brief Sets specified time zone as current
+                        *
+                        * @param[in] timezone time zone to set as current
+                        */
+                       void SetCurrentTimezone(const Timezone *timezone);
+
+                       /*
+                        * @brief Gets timezone position in time_zone_ list
+                        *
+                        * @param[in] timezone time zone
+                        *
+                        * @return position of the timezone
+                        */
                        int GetTimezoneNo(const Timezone *timezone) const;
-                       Timezone *GetCurrentTimezone() const;
-                       const char *GetCurrentTzString() const;
-                       char *OffsetToString(int offset) const;
-                       void SetCurrentTimezone(int tz);
+
+                       /*
+                        * @brief Gets total number of time zones stored in time_zone_ list
+                        *
+                        * @return number of time zones
+                        */
                        int GetTimezonesCount() const;
+
+                       /*
+                        * @brief Gets total number of locations stored in locations_ list
+                        *
+                        * @return number of locations
+                        */
                        int GetLocationsCount() const;
+
+                       /*
+                        * @brief Retrieve time zone for specified offset
+                        * @param[in] offset offset in minutes between GMT 0 and returned time zone
+                        *
+                        * @return time zone that match specified offset
+                        */
                        const Timezone *GetTimezoneByOffset(int offset) const;
+
+                       /*
+                        * @brief Gets location using its no in locations_ list
+                        * @remarks This function is for temporary usage and will be removed before final version
+                        *
+                        * param[no] location number
+                        *
+                        * @return location
+                        */
                        const model::Location *GetLocation(int no) const;
 
+                       /*
+                        * @brief Sets next on the left to current time zone as current
+                        * param[in] direction direction to change current time zone to
+                        */
+                       void MoveCurrentTimezone(Direction direction);
+
                private:
-                       int current_tz_;
-                       model::Location user_location_;
+
+                       /*
+                        * @brief Gets time zone by its no in time_zone_ list
+                        */
+                       const Timezone *GetTimezone(int no) const;
+
+                       /*
+                        * @brief Currently set time zone.
+                        * It means the time zone to be displayed on world map and its details will be displayed below the map
+                        */
+                       const Timezone *current_tz_;
+
+                       /*
+                        * @brief List of locations that may be shown on the map with corresponding time zone
+                        */
                        static std::vector<model::Location> locations_;
+
+                       /*
+                        * @brief List of time zones that may be shown on the map
+                        */
                        static std::vector<Timezone> time_zones_;
 
        };
diff --git a/clock/inc/Presenter/WorldClockPresenter.h b/clock/inc/Presenter/WorldClockPresenter.h
new file mode 100644 (file)
index 0000000..bae22e5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016 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 _CLOCK_PRESENTER_WORLDCLOCK_H_
+#define _CLOCK_PRESENTER_WORLDCLOCK_H_
+
+#include "View/WorldClockView.h"
+#include "Model/WorldClock.h"
+
+namespace presenter {
+
+       class WorldClockPresenter {
+               public:
+                       WorldClockPresenter(view::WorldClockView *view, model::WorldClock *model);
+                       ~WorldClockPresenter();
+
+               private:
+                       view::WorldClockView *view_;
+                       model::WorldClock *model_;
+
+                       void OnLeftArrowButtonClicked();
+                       void OnRightArrowButtonClicked();
+                       void OnCustomListItemClicked();
+
+                       void OnMapViewUpdateRequest();
+       };
+}
+
+#endif /* _CLOCK_PRESENTER_WORLDCLOCK_H_ */
index 2b1ba87..836195a 100644 (file)
 #ifndef _CLOCK_VIEW_WORLDCLOCK_H_
 #define _CLOCK_VIEW_WORLDCLOCK_H_
 
+
+#include <vector>
+
 #include "Model/WorldClock.h"
 #include "View/PageView.h"
 #include "View/View.h"
 
 namespace view {
+
+       enum class WorldClockSignals {
+               BUTTON_LEFT_ARROW_CLICKED,
+               BUTTON_RIGHT_ARROW_CLICKED,
+
+               CUSTOM_LIST_ITEM_CLICKED,
+               UPDATE_MAP_VIEW,
+
+               MAX
+       };
+
+
        class WorldClockView: public ui::IView {
                public:
                        WorldClockView();
 
                        Evas_Object *GetEvasObject(){return world_clock_;};
 
+                       void RegisterSignal(std::function<void(void)>func, view::WorldClockSignals signal);
+
                        void UpdateMapAndTimezoneDetails(const model::Timezone *timezone);
 
                        void AppendItemToCustomList(const model::Location *location);
 
+                       const model::Location *GetLastClickedItem();
+
                private:
                        void CreateTimezoneDetails();
                        void CreateCustomLocationsList();
@@ -58,13 +77,23 @@ namespace view {
                        static char *TextGet(void *data, Evas_Object *obj, const char *part);
                        static void Del(void *data, Evas_Object *obj);
 
+                       void SetItemLastClicked(const model::Location *location);
+
+                       void EmitSignal(view::WorldClockSignals signal);
+
+                       const char *OffsetToString(int offset);
+
                        static Elm_Genlist_Item_Class world_clock_itc_;
 
-                       model::WorldClock *world_clock_data_;
                        Evas_Object *world_clock_;
                        Evas_Object *timezone_details_;
                        Evas_Object *timezone_cities_;
                        Evas_Object *custom_locations_list_;
+
+                       const model::Location *item_last_clicked_;
+
+                       std::vector<std::function<void(void)>> signals
+                                               = std::vector<std::function<void(void)>>((int)WorldClockSignals::MAX, nullptr);
        };
 }
 
index a17cfb7..f339f94 100644 (file)
@@ -132,28 +132,31 @@ std::vector<Timezone> WorldClock::time_zones_ = {
 
 WorldClock::WorldClock()
 {
-       SetCurrentTimezone(12); // Need to load and store currently set tz to file or any app_data if possible
+       SetCurrentTimezone(&time_zones_.at(12));
+       /* Need to load and store currently set tz to file or any app_data if possible
+        *
+        * Also All User Locations (from Custom list) need to be stored and loaded from file/app preferences/other
+        */
 }
 
 int WorldClock::GetCurrentTimezoneNo() const
 {
-       return current_tz_;
+       return GetTimezoneNo(current_tz_);
 }
 
 int WorldClock::GetTimezoneNo(const model::Timezone *timezone) const
 {
-       for (int i = timezone->gmt_offset / 60 + 11; i < time_zones_.size() - 1; i++) {
+       for (int i = timezone->gmt_offset / 60 + 11; i < time_zones_.size(); i++) {
                        if (time_zones_.at(i).gmt_offset == timezone->gmt_offset) {
                                return i;
                        }
                }
-
-       return current_tz_;
+       return -1;
 }
 
 const Timezone *WorldClock::GetTimezoneByOffset(int offset) const
 {
-       for (int i = offset / 60 + 11; i < time_zones_.size() - 1; i++) {
+       for (int i = offset / 60 + 11; i < time_zones_.size(); i++) {
                if (time_zones_.at(i).gmt_offset == offset) {
                        return &time_zones_.at(i);
                }
@@ -161,33 +164,19 @@ const Timezone *WorldClock::GetTimezoneByOffset(int offset) const
        return NULL;
 }
 
-Timezone *WorldClock::GetCurrentTimezone() const
+const Timezone *WorldClock::GetCurrentTimezone() const
 {
-       return &time_zones_.at(GetCurrentTimezoneNo());
+       return current_tz_;
 }
 
-const char *WorldClock::GetCurrentTzString() const
+void WorldClock::SetCurrentTimezone(const Timezone *timezone)
 {
-       return OffsetToString(GetCurrentTimezone()->gmt_offset);
+       current_tz_ = timezone;
 }
 
-char *WorldClock::OffsetToString(int offset) const
+const Timezone *WorldClock::GetTimezone(int no) const
 {
-       int remainder;
-       char remainder_str[6];
-       static char tz_offset[6] = { 0, };
-
-       remainder = (offset % 60) * 100 / 60;
-       snprintf(remainder_str, 3, "%d", (remainder % 10) ? remainder : remainder / 10);
-
-       snprintf(tz_offset, 6, "%s%d%s%s", (offset < 0) ? "" : "+", offset / 60,
-               ((offset % 60) ? "." : ""), (remainder) ? remainder_str : "");
-       return &tz_offset[0];
-}
-
-void WorldClock::SetCurrentTimezone(int tz)
-{
-       current_tz_ = tz;
+       return &time_zones_.at(no);
 }
 
 int WorldClock::GetTimezonesCount() const
@@ -204,3 +193,25 @@ const model::Location *WorldClock::GetLocation(int no) const
 {
        return &locations_.at(no);
 }
+
+void model::WorldClock::MoveCurrentTimezone(Direction direction)
+{
+       int current_tz = GetCurrentTimezoneNo();
+
+       switch (direction) {
+               case LEFT:
+                       if (current_tz == 0)
+                               SetCurrentTimezone(GetTimezone(GetTimezonesCount() - 1));
+                       else
+                               SetCurrentTimezone(GetTimezone(current_tz - 1));
+                       break;
+               case RIGHT:
+                       if (current_tz == GetTimezonesCount() - 1)
+                               SetCurrentTimezone(GetTimezone(0));
+                       else
+                               SetCurrentTimezone(GetTimezone(current_tz + 1));
+                       break;
+               default:
+                       ERR("Invalid direction");
+       }
+}
diff --git a/clock/src/Presenter/WorldClockPresenter.cpp b/clock/src/Presenter/WorldClockPresenter.cpp
new file mode 100644 (file)
index 0000000..9d6ce21
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 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 "Presenter/WorldClockPresenter.h"
+
+namespace presenter {
+
+WorldClockPresenter::WorldClockPresenter(view::WorldClockView *view, model::WorldClock *model)
+                       : view_(view), model_(model)
+{
+       view_->RegisterSignal(std::bind(&WorldClockPresenter::OnLeftArrowButtonClicked, this),
+                       view::WorldClockSignals::BUTTON_LEFT_ARROW_CLICKED);
+       view_->RegisterSignal(std::bind(&WorldClockPresenter::OnRightArrowButtonClicked, this),
+                               view::WorldClockSignals::BUTTON_RIGHT_ARROW_CLICKED);
+       view_->RegisterSignal(std::bind(&WorldClockPresenter::OnCustomListItemClicked, this),
+                               view::WorldClockSignals::CUSTOM_LIST_ITEM_CLICKED);
+
+       /* Temporary added custom list items */
+       view_->AppendItemToCustomList(model_->GetLocation(0));
+       view_->AppendItemToCustomList(model_->GetLocation(12));
+       view_->AppendItemToCustomList(model_->GetLocation(32));
+       view_->AppendItemToCustomList(model_->GetLocation(54));
+       view_->AppendItemToCustomList(model_->GetLocation(70));
+
+       view_->UpdateMapAndTimezoneDetails(model_->GetCurrentTimezone());
+}
+
+WorldClockPresenter::~WorldClockPresenter()
+{
+}
+
+void WorldClockPresenter::OnLeftArrowButtonClicked()
+{
+       model_->MoveCurrentTimezone(model::WorldClock::LEFT);
+       view_->UpdateMapAndTimezoneDetails(model_->GetCurrentTimezone());
+}
+
+void WorldClockPresenter::OnRightArrowButtonClicked()
+{
+       model_->MoveCurrentTimezone(model::WorldClock::RIGHT);
+       view_->UpdateMapAndTimezoneDetails(model_->GetCurrentTimezone());
+}
+
+void WorldClockPresenter::OnCustomListItemClicked()
+{
+       const model::Location *location = view_->GetLastClickedItem();
+
+       model_->SetCurrentTimezone(model_->GetTimezoneByOffset(location->gmt_offset_));
+       view_->UpdateMapAndTimezoneDetails(model_->GetCurrentTimezone());
+
+}
+
+void WorldClockPresenter::OnMapViewUpdateRequest()
+{
+       view_->UpdateMapAndTimezoneDetails(model_->GetCurrentTimezone());
+}
+
+} /* presenter */
index c2fa634..ca390ce 100644 (file)
@@ -35,6 +35,7 @@
 #include "Presenter/EditAlarmPresenter.h"
 #include "Model/AlarmProvider.h"
 
+#include "Presenter/WorldClockPresenter.h"
 #include "Presenter/StopWatchPresenter.h"
 #include "Presenter/TimerPresenter.h"
 
@@ -151,7 +152,10 @@ void MainView::CreatePages()
        new AlarmPresenter(alarm, AlarmProvider::GetInstance());
        alarm_ = alarm;
 
-       world_clock_ = new WorldClockView();
+       WorldClockView *worldClock = new WorldClockView();
+       model::WorldClock *worldClockModel = new model::WorldClock();
+       new WorldClockPresenter(worldClock, worldClockModel);
+       world_clock_ = worldClock;
 
        StopWatchView *stopWatch = new StopWatchView();
        model::StopWatch *stopWatchModel = new model::StopWatch();
index abbbb88..4bdb9db 100644 (file)
@@ -34,6 +34,8 @@ struct LocationItemData {
                WorldClockView *wc_view;
                Evas_Object *time;
 
+               const model::Location *location;
+
                char *ampm;
                char *date;
                char *city_country;
@@ -68,6 +70,7 @@ void WorldClockView::AppendItemToCustomList(const model::Location *location)
        Time t;
        std::stringstream ss;
 
+       data->location = location;
        data->wc_view = this;
        ss << location->name << ", " << location->country;
        data->city_country = strdup(ss.str().c_str());
@@ -92,12 +95,8 @@ void WorldClockView::ItemClicked(void *data, Evas_Object *obj, void *event_info)
 {
        LocationItemData *lid = static_cast<LocationItemData *>(data);
 
-       /* TODO send event to WC model to update 'Current' timezone.
-       (Model need to fire event(view refresh update) when data are updated.)*/
-
-       const model::Timezone *tz = lid->wc_view->world_clock_data_->GetTimezoneByOffset(lid->gmt_offset);
-       lid->wc_view->world_clock_data_->SetCurrentTimezone(lid->wc_view->world_clock_data_->GetTimezoneNo(tz));
-       lid->wc_view->UpdateMapAndTimezoneDetails(tz);
+       lid->wc_view->SetItemLastClicked(lid->location);
+       lid->wc_view->EmitSignal(view::WorldClockSignals::CUSTOM_LIST_ITEM_CLICKED);
 
        elm_genlist_item_selected_set(lid->it, EINA_FALSE);
 }
@@ -175,28 +174,15 @@ void WorldClockView::Del(void *data, Evas_Object *obj)
 void WorldClockView::ChangeTimezoneCb(void *data, Evas_Object *obj, const char *emission,
         const char *source)
 {
-       /* TODO send event to WC presenter to update 'Current' timezone.
-       (Model need to fire event(view refresh update) when data are updated.)*/
-
        WorldClockView *world_clock_view = static_cast<WorldClockView *>(data);
-       model::WorldClock *world_clock_data = world_clock_view->world_clock_data_;
 
-       int current_tz = world_clock_data->GetCurrentTimezoneNo();
 
        if (!strcmp(source, "main.world.map:arrow.left")) {
-               if (current_tz == 0)
-                       world_clock_data->SetCurrentTimezone(
-                               world_clock_data->GetTimezonesCount() - 1);
-               else
-                       world_clock_data->SetCurrentTimezone(current_tz - 1);
+               world_clock_view->EmitSignal(view::WorldClockSignals::BUTTON_LEFT_ARROW_CLICKED);
 
        } else if (!strcmp(source, "main.world.map:arrow.right")) {
-               if (current_tz == world_clock_data->GetTimezonesCount() - 1)
-                       world_clock_data->SetCurrentTimezone(0);
-               else
-                       world_clock_data->SetCurrentTimezone(current_tz + 1);
+               world_clock_view->EmitSignal(view::WorldClockSignals::BUTTON_RIGHT_ARROW_CLICKED);
        }
-       world_clock_view->UpdateMapAndTimezoneDetails(world_clock_data->GetCurrentTimezone());
 }
 
 // TODO FOR DEBUGING ONLY - need to be removed when application is ready
@@ -216,7 +202,6 @@ void message_cb(void *data, Evas_Object *obj, Edje_Message_Type type, int id, vo
 
 WorldClockView::WorldClockView()
 {
-       world_clock_data_ = new model::WorldClock(); // TODO create Presenter for WorldClock
        world_clock_ = elm_layout_add(MainView::GetInstance().GetEvasObject());
 
        if(!elm_layout_file_set(world_clock_,
@@ -236,13 +221,6 @@ WorldClockView::WorldClockView()
        elm_theme_extension_add(NULL,
                        Utils::GetAppResourcePath(Utils::APP_DIR_RESOURCE, "edje/CitiesListItem.edj"));
 
-       /* Temporary hardcoded list items */
-       AppendItemToCustomList(world_clock_data_->GetLocation(0));
-       AppendItemToCustomList(world_clock_data_->GetLocation(12));
-       AppendItemToCustomList(world_clock_data_->GetLocation(32));
-       AppendItemToCustomList(world_clock_data_->GetLocation(54));
-       AppendItemToCustomList(world_clock_data_->GetLocation(70));
-
        elm_layout_signal_callback_add(world_clock_, "timezone,go,left",
                "main.world.map:arrow.left", WorldClockView::ChangeTimezoneCb,
                static_cast<void *>(this));
@@ -273,14 +251,13 @@ void WorldClockView::UpdateTimezoneLocationsDots(const model::Timezone *timezone
                msg->val[3] = i;
                edje_object_message_send(elm_layout_edje_get(world_clock_), EDJE_MESSAGE_INT_SET,
                        MESSAGE_ID_SET_LOCATION_DOT_POSITION, (void *) msg);
-
                free(msg);
        }
 }
 
 void WorldClockView::UpdateGmtOffset(const model::Timezone *timezone)
 {
-       const char *offset = world_clock_data_->OffsetToString(timezone->gmt_offset);
+       const char *offset = OffsetToString(timezone->gmt_offset);
        elm_object_part_text_set(world_clock_, "main.world.map:timezone_offset", offset);
 }
 
@@ -319,8 +296,10 @@ void WorldClockView::CreateTimezoneDetails()
 
        CreateTimezoneCitiesList();
 
-       // TODO load timezone to display on map from app preferences(it must be saved on app temination)
-       UpdateMapAndTimezoneDetails(world_clock_data_->GetCurrentTimezone());
+       EmitSignal(view::WorldClockSignals::UPDATE_MAP_VIEW);
+
+       /* TODO load timezone to display on map from app preferences(it must be saved on app temination)*/
+
 }
 
 void WorldClockView::UpdateMapAndTimezoneDetails(const model::Timezone *timezone)
@@ -427,8 +406,7 @@ void WorldClockView::CreateTimezoneCitiesList()
 
 void WorldClockView::UpdateTimezoneCitiesList(const model::Timezone *timezone)
 {
-       const std::vector < model::Location > *cities_list = ( (timezone) ?
-                       &timezone->places : &world_clock_data_->GetCurrentTimezone()->places);
+       const std::vector < model::Location > *cities_list = &timezone->places;
 
        char cities[MAX_CITIES_LEN];
        snprintf(cities, sizeof(cities), "%s", cities_list->at(0).name.c_str());
@@ -446,3 +424,37 @@ void WorldClockView::UpdateTimezoneCitiesList(const model::Timezone *timezone)
        elm_object_text_set(timezone_cities_, cities_formatted);
 }
 
+const model::Location *WorldClockView::GetLastClickedItem()
+{
+       return item_last_clicked_;
+}
+
+void WorldClockView::SetItemLastClicked(const model::Location *location)
+{
+       item_last_clicked_ = location;
+}
+
+void WorldClockView::RegisterSignal(std::function<void(void)>func, view::WorldClockSignals signal)
+{
+       signals.at((int)signal) = func;
+}
+
+void WorldClockView::EmitSignal(view::WorldClockSignals signal)
+{
+       if (signals.at((int)signal) != nullptr)
+               signals.at((int)signal)();
+}
+
+const char *WorldClockView::OffsetToString(int offset)
+{
+       int remainder;
+       char remainder_str[6];
+       static char tz_offset[6] = { 0, };
+
+       remainder = (offset % 60) * 100 / 60;
+       snprintf(remainder_str, 3, "%d", (remainder % 10) ? remainder : remainder / 10);
+
+       snprintf(tz_offset, 6, "%s%d%s%s", (offset < 0) ? "" : "+", offset / 60,
+               ((offset % 60) ? "." : ""), (remainder) ? remainder_str : "");
+       return &tz_offset[0];
+}