2
* Copyright 2013 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3, as published
6
* by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Charles Kerr <charles.kerr@canonical.com>
20
#include <transfer/menu.h>
22
#include <transfer/gactions.h>
23
#include <transfer/transfer.h>
25
#include <glib/gi18n.h>
28
#include <memory> // shared_ptr
39
Menu::Menu (Profile profile_in, const char* name_in):
40
m_profile{profile_in},
45
const char* Menu::name() const
50
Menu::Profile Menu::profile() const
55
GMenuModel* Menu::menu_model()
59
return G_MENU_MODEL(m_menu);
66
class MenuImpl: public Menu
69
MenuImpl(const Menu::Profile profile_in,
71
const std::shared_ptr<Transfers>& transfers,
72
const std::shared_ptr<GActions>& gactions):
73
Menu(profile_in, name_in),
74
m_transfers(transfers),
77
// initialize the menu
79
for (int i=0; i<(int)NUM_SECTIONS; i++)
80
update_section(Section(i));
82
// listen for state changes so we can update the menu accordingly
83
m_transfers->changed().connect([this](const Transfers::ValueType&){
84
update_transfer_connections();
86
update_section(TRANSFERS);
90
update_transfer_connections();
95
g_clear_object(&m_menu);
100
auto action_group = m_gactions->action_group();
101
auto action_name = g_strdup_printf("%s-header", name());
102
auto state = create_header_state();
103
g_action_group_change_action_state(action_group, action_name, state);
107
std::shared_ptr<Transfers> m_transfers;
108
std::shared_ptr<GActions> m_gactions;
109
GMenu* m_submenu = nullptr;
113
GVariant* create_header_state()
115
auto title_v = g_variant_new_string(_("Transfers"));
116
const auto visible = !m_transfers->get().empty();
119
g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT);
120
g_variant_builder_add(&b, "{sv}", "title", title_v);
121
g_variant_builder_add(&b, "{sv}", "label", title_v);
122
g_variant_builder_add(&b, "{sv}", "accessible-desc", title_v);
123
g_variant_builder_add(&b, "{sv}", "visible", g_variant_new_boolean(visible));
124
return g_variant_builder_end (&b);
129
g_assert(m_submenu == nullptr);
131
m_submenu = g_menu_new();
133
// build placeholders for the sections
134
for(int i=0; i<NUM_SECTIONS; i++)
136
auto item = g_menu_item_new(nullptr, nullptr);
137
g_menu_append_item(m_submenu, item);
138
g_object_unref(item);
141
// add submenu to the header
142
const auto detailed_action = (std::string{"indicator."} + name()) + "-header";
143
auto header = g_menu_item_new(nullptr, detailed_action.c_str());
144
g_menu_item_set_attribute(header, "x-canonical-type", "s",
145
"com.canonical.indicator.root");
146
g_menu_item_set_attribute(header, "submenu-action", "s",
147
"indicator.calendar-active");
148
g_menu_item_set_submenu(header, G_MENU_MODEL(m_submenu));
149
g_object_unref(m_submenu);
151
// add header to the menu
152
m_menu = g_menu_new();
153
g_menu_append_item(m_menu, header);
154
g_object_unref(header);
157
GMenuItem* create_transfer_menuitem(const std::shared_ptr<Transfer>& transfer)
159
const auto& id = transfer->id().c_str();
160
auto menu_item = g_menu_item_new (transfer->id().c_str(), nullptr);
161
g_menu_item_set_attribute (menu_item, "x-canonical-type", "s", "com.canonical.indicator.transfer");
162
g_menu_item_set_attribute (menu_item, "x-canonical-state", "i", transfer->state().get());
163
g_menu_item_set_attribute (menu_item, "x-canonical-uid", "s", id);
164
g_menu_item_set_attribute (menu_item, "x-canonical-time", "x", transfer->last_active().get());
165
g_menu_item_set_action_and_target_value (menu_item, "indicator.activate-transfer", g_variant_new_string(id));
166
return G_MENU_ITEM(menu_item);
169
void update_transfer(const std::shared_ptr<Transfer>& transfer)
171
g_message ("FIXME update menu for transfer '%s'", transfer->id().c_str());
174
GMenuModel* create_transfers_section()
176
auto menu = g_menu_new();
178
for (const auto& transfer : m_transfers->get())
180
auto menu_item = create_transfer_menuitem(transfer);
181
g_menu_append_item (menu, menu_item);
182
g_object_unref (menu_item);
185
return G_MENU_MODEL(menu);
188
GMenuModel* create_bulk_actions_section()
190
auto menu = g_menu_new();
192
unsigned int n_running = 0;
193
unsigned int n_stopped = 0;
194
unsigned int n_done = 0;
195
for (const auto& transfer : m_transfers->get()) {
196
switch (transfer->state()) {
197
case Transfer::STARTING:
198
case Transfer::RUNNING: ++n_running; break;
199
case Transfer::FAILED:
200
case Transfer::PAUSED: ++n_stopped; break;
201
case Transfer::CANCELING:
202
case Transfer::DONE: ++n_done; break;
207
g_menu_append (menu, _("Resume All"), "indicator.resume-all");
209
g_menu_append (menu, _("Pause All"), "indicator.pause-all");
211
g_menu_append (menu, _("Clear All"), "indicator.clear-all");
213
return G_MENU_MODEL(menu);
216
void update_section(Section section)
222
case BULK: model = create_bulk_actions_section(); break;
223
case TRANSFERS: model = create_transfers_section(); break;
224
default: model = nullptr; g_warn_if_reached();
229
g_menu_remove(m_submenu, section);
230
g_menu_insert_section(m_submenu, section, nullptr, model);
231
g_object_unref(model);
235
void update_transfer_connections()
238
for(auto& connection : m_transfer_connections)
239
connection.disconnect();
240
m_transfer_connections.clear();
243
for (auto& transfer : m_transfers->get()) {
244
auto connection = transfer->last_active().changed().connect([this,transfer](const time_t&) {
246
update_transfer(transfer);
247
update_section(BULK);
249
m_transfer_connections.push_back(connection);
253
std::vector<core::Connection> m_transfer_connections;
261
class PhoneBaseMenu: public MenuImpl
264
PhoneBaseMenu(Menu::Profile profile_,
266
const std::shared_ptr<Transfers>& transfers_,
267
const std::shared_ptr<GActions>& gactions_):
268
MenuImpl{profile_, name_, transfers_, gactions_}
275
class PhoneMenu: public PhoneBaseMenu
278
PhoneMenu(const std::shared_ptr<Transfers>& transfers_,
279
const std::shared_ptr<GActions>& actions_):
280
PhoneBaseMenu{PHONE, profile_names[PHONE], transfers_, actions_} {}
287
MenuFactory::MenuFactory(const std::shared_ptr<Transfers>& transfers_,
288
const std::shared_ptr<GActions>& gactions_):
289
m_transfers{transfers_},
290
m_gactions{gactions_}
294
std::shared_ptr<Menu>
295
MenuFactory::buildMenu(Menu::Profile profile)
297
std::shared_ptr<Menu> menu;
302
menu.reset(new PhoneMenu{m_transfers, m_gactions});
317
} // namespace transfer
318
} // namespace indicator