2
* Copyright (C) 2011 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/>.
16
* Authored by Ken VanDine <ken.vandine@canonical.com>
27
/* DBus name for the place. Must match out .place file */
28
const string BUS_NAME = "com.canonical.Unity.Gwibber";
31
* The Daemon class implements all of the logic for the place.
34
public class Daemon : GLib.Object
36
private Unity.PlaceController control;
37
private Unity.PlaceEntryInfo place_entry;
38
private Gwibber.Streams streams_service;
39
private Dee.Model? model;
43
streams_service = new Gwibber.Streams();
44
/* Create all the models we need to share with the Unity shell.
45
* The model column schemas must align with what we defined in
47
var sections_model = new Dee.SharedModel(BUS_NAME + ".SectionsModel");
48
sections_model.set_schema ("s", "s");
50
var groups_model = new Dee.SharedModel(BUS_NAME + ".GroupsModel");
51
groups_model.set_schema ("s", "s", "s");
53
var global_groups_model = new Dee.SharedModel(BUS_NAME + ".GlobalGroupsModel");
54
global_groups_model.set_schema ("s", "s", "s");
56
var results_model = new Dee.SharedModel(BUS_NAME + ".ResultsModel");
57
results_model.set_schema ("s", "s", "u", "s", "s", "s");
59
var global_results_model = new Dee.SharedModel(BUS_NAME + ".GlobalResultsModel");
60
global_results_model.set_schema ("s", "s", "u", "s", "s", "s");
62
/* Create a PlaceEntryInfo. The properties of the PlaceEntryInfo is
63
* automatically mapped back and forth over the bus, and removes most
64
* DBusisms from the place daemon code.
66
* Object path of the PlaceEntryInfo must match the one defined in the
67
* the place entry in the place .place file
69
place_entry = new Unity.PlaceEntryInfo ("/com/canonical/unity/gwibber/main");
70
place_entry.sections_model = sections_model;
71
place_entry.entry_renderer_info.groups_model = groups_model;
72
place_entry.entry_renderer_info.results_model = results_model;
73
place_entry.global_renderer_info.groups_model = global_groups_model;
74
place_entry.global_renderer_info.results_model = global_results_model;
79
/* Unity preloads the icon defined in the .place file even before the
80
* place daemon is running - when we come up it will ratify the icon */
81
place_entry.icon = @"$(Config.PREFIX)/share/gwibber/unity/applications-microblogging.png";
83
/* Listen for section changes and start updating our results model
85
place_entry.notify["active-section"].connect (update_entry_results_model);
87
/* Listen for changes to the place entry search */
88
place_entry.notify["active-search"].connect (update_entry_results_model);
90
/* Listen for changes to the global search */
91
place_entry.notify["active-global-search"].connect (update_global_results_model);
93
/* Listen for when the place is hidden/shown by the Unity Shell */
94
place_entry.notify["active"].connect (
96
debug (@"Activated: $(place_entry.active)");
97
update_entry_results_model ();
101
/* The last thing we do is export the controller. Once that is up,
102
* clients will expect the Dee.SharedModels to work.
103
* The 'place' EntryInfo is exported for Unity to show by adding it to
104
* the controller. You can add more than one EntryInfo here if you have
105
* more than one place entry to export from the same place daemon */
106
control = new Unity.PlaceController ("/com/canonical/unity/gwibber");
107
control.add_entry (place_entry);
109
/* Export the controller on the bus. Unity can see us past this point */
112
} catch (IOError error) {
113
critical ("Failed to export DBus service for '%s': %s",
114
control.dbus_path, error.message);
117
var streams_model = streams_service.get_stream_model();
118
model = streams_model;
121
private void populate_sections ()
123
var sections = place_entry.sections_model;
125
if (sections.get_n_rows() != 0)
127
critical ("The sections model should be empty before initial population");
131
/* The row offsets should match those from the Section enum */
132
sections.append (_("Everything"), "");
133
sections.append (_("Messages"), "");
134
sections.append (_("Replies"), "");
135
sections.append (_("Images"), "");
136
sections.append (_("Videos"), "");
137
sections.append (_("Links"), "");
138
sections.append (_("Private"), "");
139
sections.append (_("Public"), "");
140
debug ("Sections has %u rows", sections.get_n_rows());
143
private void populate_groups ()
146
var groups = place_entry.entry_renderer_info.groups_model;
148
if (groups.get_n_rows() != 0)
150
critical ("The groups model should be empty before initial population");
154
/* The row offsets should match those from the Group enum */
155
icon = new ThemedIcon ("tray-message");
156
groups.append ("UnityHorizontalTileRenderer", _("Everything"), icon.to_string());
157
icon = new ThemedIcon ("tray-message");
158
groups.append ("UnityHorizontalTileRenderer", _("Messages"), icon.to_string());
159
icon = new ThemedIcon ("mail_reply");
160
groups.append ("UnityHorizontalTileRenderer", _("Replies"), icon.to_string());
161
icon = new ThemedIcon ("gnome-mime-image");
162
groups.append ("UnityHorizontalTileRenderer", _("Images"), icon.to_string());
163
icon = new ThemedIcon ("video");
164
groups.append ("UnityHorizontalTileRenderer", _("Videos"), icon.to_string());
165
icon = new ThemedIcon ("web-browser");
166
groups.append ("UnityHorizontalTileRenderer", _("Links"), icon.to_string());
167
icon = new ThemedIcon ("mail-send-receive");
168
groups.append ("UnityHorizontalTileRenderer", _("Private"), icon.to_string());
169
icon = new ThemedIcon ("evolution");
170
groups.append ("UnityHorizontalTileRenderer", _("Public"), icon.to_string());
171
debug ("Groups has %u rows", groups.get_n_rows());
174
private void update_entry_results_model ()
176
/* If we're not active just ignore anything Unity tells us to do
177
* it's not gonna show on the screen anyway */
178
if (!place_entry.active)
181
var _results_model = place_entry.entry_renderer_info.results_model;
182
var _groups_model = place_entry.entry_renderer_info.groups_model;
183
var _search = place_entry.active_search;
184
var _section = (Section)place_entry.active_section;
186
update_results_model (_results_model, _groups_model,
190
private void update_global_results_model ()
192
/* Unlike update_entry_model() the global model may be updated
193
* even though we are not active */
195
var _results_model = place_entry.global_renderer_info.results_model;
196
var _groups_model = place_entry.global_renderer_info.groups_model;
197
var _search = place_entry.active_global_search;
198
var _section = Section.ALL; /* We have no active section in global mode */
200
update_results_model (_results_model, _groups_model,
204
/* Generic method to update a results model. We do it like this to minimize
205
* code dup between updating the global- and the entry results model */
206
private void update_results_model (Dee.Model results_model, Dee.Model groups_model,
207
Unity.PlaceSearch? search, Section section)
209
unowned Dee.ModelIter iter, end;
210
string search_string = null;
211
Group group = Group.ALL;
212
debug ("Rebuilding results model");
213
results_model.clear ();
215
iter = model.get_first_iter ();
216
end = model.get_last_iter ();
218
place_entry.freeze_notify ();
222
if (search.get_search_string () != null)
223
search_string = search.get_search_string ().down();
228
if (section == Section.MESSAGES && model.get_string(iter, StreamModelColumn.STREAM) != "messages")
230
iter = model.next (iter);
234
if (section == Section.REPLIES && model.get_string(iter, StreamModelColumn.STREAM) != "replies")
236
iter = model.next (iter);
240
if (section == Section.IMAGES && model.get_string(iter, StreamModelColumn.STREAM) != "images")
242
iter = model.next (iter);
246
if (section == Section.VIDEOS && model.get_string(iter, StreamModelColumn.STREAM) != "videos")
248
iter = model.next (iter);
252
if (section == Section.LINKS && model.get_string(iter, StreamModelColumn.STREAM) != "links")
254
iter = model.next (iter);
258
if (section == Section.PRIVATE && model.get_string(iter, StreamModelColumn.STREAM) != "private")
260
iter = model.next (iter);
264
if (section == Section.PUBLIC && model.get_string(iter, StreamModelColumn.STREAM) != "public")
266
iter = model.next (iter);
270
if (search_string == null || search_string in model.get_string(iter, StreamModelColumn.SENDER).down() || search_string in model.get_string(iter, StreamModelColumn.MESSAGE).down())
272
if (model.get_string(iter, StreamModelColumn.STREAM) == "messages")
273
group = Group.MESSAGES;
274
else if (model.get_string(iter, StreamModelColumn.STREAM) == "replies")
275
group = Group.REPLIES;
276
else if (model.get_string(iter, StreamModelColumn.STREAM) == "images")
277
group = Group.IMAGES;
278
else if (model.get_string(iter, StreamModelColumn.STREAM) == "videos")
279
group = Group.VIDEOS;
280
else if (model.get_string(iter, StreamModelColumn.STREAM) == "links")
282
else if (model.get_string(iter, StreamModelColumn.STREAM) == "private")
283
group = Group.PRIVATE;
284
else if (model.get_string(iter, StreamModelColumn.STREAM) == "public")
285
group = Group.PUBLIC;
286
results_model.append(model.get_string(iter, StreamModelColumn.URL), model.get_string(iter, StreamModelColumn.ICON_URI), group, "text/html", model.get_string(iter, StreamModelColumn.SENDER), model.get_string(iter, StreamModelColumn.MESSAGE));
288
iter = model.next (iter);
296
place_entry.thaw_notify ();
303
debug ("Results has %u rows", results_model.get_n_rows());
306
} /* End Daemon class */
307
} /* end Gwibber namespace */