/*
* Copyright 2013 Canonical Ltd.
* Copyright 2021 Robert Tari
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* Authors:
* Charles Kerr
* Robert Tari
*/
#include
#include // split_settings_location()
#include
#include
#include
namespace ayatana {
namespace indicator {
namespace datetime {
/***
****
***/
namespace
{
DateTime datetime_from_timet_variant(GVariant* v)
{
int64_t t = 0;
if (v != nullptr)
if (g_variant_type_equal(G_VARIANT_TYPE_INT64,g_variant_get_type(v)))
t = g_variant_get_int64(v);
if (t != 0)
return DateTime::Local(t);
else
return DateTime::NowLocal();
}
bool lookup_appointment_by_uid(const std::shared_ptr& state, const gchar* uid, Appointment& setme)
{
bool bRet = false;
std::for_each(state->calendar_upcoming->appointments().get().begin(), state->calendar_upcoming->appointments().get().end(), [uid, &setme, &bRet](const Appointment& appt)
{
if (appt.uid == uid)
{
setme = appt;
bRet = true;
}
});
return bRet;
}
void on_appointment_activated (GSimpleAction*, GVariant *vdata, gpointer gself)
{
auto self = static_cast(gself);
Appointment appt;
const gchar* uid = nullptr;
gint64 time = 0;
g_variant_get(vdata, "(&sx)", &uid, &time);
if (lookup_appointment_by_uid(self->state(), uid, appt))
self->open_appointment(appt, DateTime::Local(time));
}
void on_alarm_activated (GSimpleAction*, GVariant*, gpointer gself)
{
static_cast(gself)->open_alarm_app();
}
void on_calendar_activated (GSimpleAction*, GVariant* vt, gpointer gself)
{
const auto dt = datetime_from_timet_variant(vt);
static_cast(gself)->open_calendar_app(dt);
}
void on_settings_activated (GSimpleAction*, GVariant*, gpointer gself)
{
static_cast(gself)->open_settings_app();
}
void on_set_location(GSimpleAction * /*action*/,
GVariant * param,
gpointer gself)
{
char * zone;
char * name;
split_settings_location(g_variant_get_string(param, nullptr), &zone, &name);
static_cast(gself)->set_location(zone, name);
g_free(name);
g_free(zone);
}
void on_calendar_active_changed(GSimpleAction * /*action*/,
GVariant * state,
gpointer gself)
{
// reset the date when the menu is shown
if (g_variant_get_boolean(state))
{
auto self = static_cast(gself);
self->set_calendar_date(self->state()->clock->localtime(), true);
}
}
void on_calendar_date_activated(GSimpleAction * /*action*/,
GVariant * state,
gpointer gself)
{
const time_t t = g_variant_get_int64(state);
g_return_if_fail(t != 0);
auto dt = DateTime::Local(t).start_of_day();
static_cast(gself)->set_calendar_date(dt, false);
}
GVariant* create_default_header_state()
{
GVariantBuilder b;
g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add(&b, "{sv}", "accessible-desc", g_variant_new_string("accessible-desc"));
g_variant_builder_add(&b, "{sv}", "label", g_variant_new_string("label"));
g_variant_builder_add(&b, "{sv}", "title", g_variant_new_string("title"));
g_variant_builder_add(&b, "{sv}", "visible", g_variant_new_boolean(true));
return g_variant_builder_end(&b);
}
GVariant* create_calendar_state(const std::shared_ptr& state)
{
gboolean days[32] = { 0 };
for (const auto& appt : state->calendar_month->appointments().get())
days[appt.begin.day_of_month()] = true;
GVariantBuilder day_builder;
g_variant_builder_init(&day_builder, G_VARIANT_TYPE("ai"));
for (guint i=0; icalendar_month->month().get().to_unix());
g_variant_builder_add(&dict_builder, "{sv}", key, v);
key = "show-week-numbers";
v = g_variant_new_boolean(state->settings->show_week_numbers.get());
g_variant_builder_add(&dict_builder, "{sv}", key, v);
return g_variant_builder_end(&dict_builder);
}
} // unnamed namespace
/***
****
***/
Actions::Actions(const std::shared_ptr& state):
m_state(state),
m_actions(g_simple_action_group_new())
{
GActionEntry entries[] = {
{ "desktop.open-appointment", on_appointment_activated, "(sx)", nullptr },
{ "desktop.open-alarm-app", on_alarm_activated },
{ "desktop.open-calendar-app", on_calendar_activated, "x", nullptr },
{ "desktop.open-settings-app", on_settings_activated },
{ "phone.open-appointment", on_appointment_activated, "(sx)", nullptr },
{ "phone.open-alarm-app", on_alarm_activated },
{ "phone.open-calendar-app", on_calendar_activated, "x", nullptr },
{ "phone.open-settings-app", on_settings_activated },
{ "calendar-active", nullptr, nullptr, "false", on_calendar_active_changed },
{ "set-location", on_set_location, "s" }
};
g_action_map_add_action_entries(G_ACTION_MAP(m_actions),
entries,
G_N_ELEMENTS(entries),
this);
// add the header actions
auto gam = G_ACTION_MAP(m_actions);
auto v = create_default_header_state();
auto a = g_simple_action_new_stateful("desktop-header", nullptr, v);
g_action_map_add_action(gam, G_ACTION(a));
g_object_unref(a);
a = g_simple_action_new_stateful("desktop_greeter-header", nullptr, v);
g_action_map_add_action(gam, G_ACTION(a));
g_object_unref(a);
a = g_simple_action_new_stateful("phone-header", nullptr, v);
g_action_map_add_action(gam, G_ACTION(a));
g_object_unref(a);
a = g_simple_action_new_stateful("phone_greeter-header", nullptr, v);
g_action_map_add_action(gam, G_ACTION(a));
g_object_unref(a);
// add the calendar action
v = create_calendar_state(state);
a = g_simple_action_new_stateful("calendar", G_VARIANT_TYPE_INT64, v);
g_action_map_add_action(gam, G_ACTION(a));
g_signal_connect(a, "activate", G_CALLBACK(on_calendar_date_activated), this);
g_object_unref(a);
///
/// Keep our GActionGroup's action's states in sync with m_state
///
m_state->calendar_month->month().changed().connect([this](const DateTime&){
update_calendar_state();
});
m_state->calendar_month->appointments().changed().connect([this](const std::vector&){
update_calendar_state();
});
m_state->settings->show_week_numbers.changed().connect([this](bool){
update_calendar_state();
});
// FIXME: rebuild the calendar state when show-week-number changes
}
Actions::~Actions()
{
g_clear_object(&m_actions);
}
void Actions::update_calendar_state()
{
g_action_group_change_action_state(action_group(),
"calendar",
create_calendar_state(m_state));
}
void Actions::set_calendar_date(const DateTime& date, bool bUpdateCalendar)
{
if (bUpdateCalendar)
{
m_state->calendar_month->month().set(date);
}
m_state->calendar_upcoming->date().set(date);
}
GActionGroup* Actions::action_group()
{
return G_ACTION_GROUP(m_actions);
}
const std::shared_ptr Actions::state() const
{
return m_state;
}
} // namespace datetime
} // namespace indicator
} // namespace ayatana