~njpatel/gwibber/libgwibber-o-client-njpatel

« back to all changes in this revision

Viewing changes to lens/src/daemon.vala

  • Committer: Neil Jagdish Patel
  • Date: 2011-06-19 12:48:27 UTC
  • mfrom: (159.2.27 client-gtk3)
  • Revision ID: neil.patel@canonical.com-20110619124827-4agvjitrl6e38q2p
Merge in kens work as well as add some updates. Should have done the merge and my work separately but I forgot to commit after the merge :)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011 Canonical Ltd.
 
3
 *
 
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.
 
7
 
 
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.
 
12
 
 
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/>.
 
15
 *
 
16
 * Authored by Ken VanDine <ken.vandine@canonical.com>
 
17
 */
 
18
 
 
19
using Dee;
 
20
using Gee;
 
21
using Config;
 
22
using Gwibber;
 
23
using Unity;
 
24
 
 
25
namespace Gwibber {
 
26
 
 
27
  /* DBus name for the place. Must match out .place file */
 
28
  const string BUS_NAME = "com.canonical.Unity.Gwibber";
 
29
 
 
30
  /**
 
31
   * The Daemon class implements all of the logic for the place.
 
32
   *
 
33
   */
 
34
  public class Daemon : GLib.Object
 
35
  {
 
36
    private Unity.PlaceController control;
 
37
    private Unity.PlaceEntryInfo place_entry;
 
38
    private Gwibber.Streams streams_service;
 
39
    private Dee.Model? model;
 
40
 
 
41
    construct
 
42
    {
 
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
 
46
       * schemas.vala */
 
47
      var sections_model = new Dee.SharedModel(BUS_NAME + ".SectionsModel");
 
48
      sections_model.set_schema ("s", "s");
 
49
 
 
50
      var groups_model = new Dee.SharedModel(BUS_NAME + ".GroupsModel");
 
51
      groups_model.set_schema ("s", "s", "s");
 
52
 
 
53
      var global_groups_model = new Dee.SharedModel(BUS_NAME + ".GlobalGroupsModel");
 
54
      global_groups_model.set_schema ("s", "s", "s");
 
55
 
 
56
      var results_model = new Dee.SharedModel(BUS_NAME + ".ResultsModel");
 
57
      results_model.set_schema ("s", "s", "u", "s", "s", "s");
 
58
 
 
59
      var global_results_model = new Dee.SharedModel(BUS_NAME + ".GlobalResultsModel");
 
60
      global_results_model.set_schema ("s", "s", "u", "s", "s", "s");
 
61
      
 
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.
 
65
       *
 
66
       * Object path of the PlaceEntryInfo must match the one defined in the
 
67
       * the place entry in the place .place file
 
68
       */
 
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;
 
75
 
 
76
      populate_sections ();
 
77
      populate_groups ();
 
78
 
 
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";
 
82
 
 
83
      /* Listen for section changes and start updating our results model
 
84
       * accordingly */
 
85
      place_entry.notify["active-section"].connect (update_entry_results_model);
 
86
 
 
87
      /* Listen for changes to the place entry search */
 
88
      place_entry.notify["active-search"].connect (update_entry_results_model);
 
89
 
 
90
      /* Listen for changes to the global search */
 
91
      place_entry.notify["active-global-search"].connect (update_global_results_model);
 
92
      
 
93
      /* Listen for when the place is hidden/shown by the Unity Shell */
 
94
      place_entry.notify["active"].connect (
 
95
        (obj, pspec) => {
 
96
          debug (@"Activated: $(place_entry.active)");
 
97
          update_entry_results_model ();
 
98
        }
 
99
      );          
 
100
 
 
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);
 
108
      
 
109
      /* Export the controller on the bus. Unity can see us past this point */
 
110
      try {
 
111
        control.export ();
 
112
      } catch (IOError error) {
 
113
        critical ("Failed to export DBus service for '%s': %s",
 
114
                  control.dbus_path, error.message);
 
115
      }
 
116
 
 
117
      var streams_model = streams_service.get_stream_model();
 
118
      model = streams_model;
 
119
    }
 
120
 
 
121
    private void populate_sections ()
 
122
    {
 
123
      var sections = place_entry.sections_model;
 
124
 
 
125
      if (sections.get_n_rows() != 0)
 
126
        {
 
127
          critical ("The sections model should be empty before initial population");
 
128
          sections.clear ();
 
129
        }
 
130
 
 
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());
 
141
    }
 
142
 
 
143
    private void populate_groups ()
 
144
    {
 
145
      Icon icon;
 
146
      var groups = place_entry.entry_renderer_info.groups_model;
 
147
 
 
148
      if (groups.get_n_rows() != 0)
 
149
        {
 
150
          critical ("The groups model should be empty before initial population");
 
151
          groups.clear ();
 
152
        }
 
153
 
 
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());
 
172
    }
 
173
    
 
174
    private void update_entry_results_model ()
 
175
    {
 
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)
 
179
        return;
 
180
                    
 
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;          
 
185
       
 
186
      update_results_model (_results_model, _groups_model,
 
187
                            _search, _section);
 
188
    }
 
189
    
 
190
    private void update_global_results_model ()
 
191
    {
 
192
      /* Unlike update_entry_model() the global model may be updated
 
193
       * even though we are not active */
 
194
    
 
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 */
 
199
       
 
200
      update_results_model (_results_model, _groups_model,
 
201
                            _search, _section);
 
202
    }
 
203
 
 
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)
 
208
    {
 
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 ();
 
214
 
 
215
      iter = model.get_first_iter ();
 
216
      end = model.get_last_iter ();
 
217
      
 
218
      place_entry.freeze_notify ();
 
219
 
 
220
      if (search != null)
 
221
      { 
 
222
        if (search.get_search_string () != null)
 
223
          search_string = search.get_search_string ().down();
 
224
      }
 
225
 
 
226
      while (iter != end)
 
227
      {
 
228
        if (section == Section.MESSAGES && model.get_string(iter, StreamModelColumn.STREAM) != "messages")
 
229
        {
 
230
          iter = model.next (iter);
 
231
          continue;
 
232
        }
 
233
 
 
234
        if (section == Section.REPLIES && model.get_string(iter, StreamModelColumn.STREAM) != "replies")
 
235
        {
 
236
          iter = model.next (iter);
 
237
          continue;
 
238
        }
 
239
 
 
240
        if (section == Section.IMAGES && model.get_string(iter, StreamModelColumn.STREAM) != "images")
 
241
        {
 
242
          iter = model.next (iter);
 
243
          continue;
 
244
        }
 
245
 
 
246
        if (section == Section.VIDEOS && model.get_string(iter, StreamModelColumn.STREAM) != "videos")
 
247
        {
 
248
          iter = model.next (iter);
 
249
          continue;
 
250
        }
 
251
 
 
252
        if (section == Section.LINKS && model.get_string(iter, StreamModelColumn.STREAM) != "links")
 
253
        {
 
254
          iter = model.next (iter);
 
255
          continue;
 
256
        }
 
257
 
 
258
        if (section == Section.PRIVATE && model.get_string(iter, StreamModelColumn.STREAM) != "private")
 
259
        {
 
260
          iter = model.next (iter);
 
261
          continue;
 
262
        }
 
263
 
 
264
        if (section == Section.PUBLIC && model.get_string(iter, StreamModelColumn.STREAM) != "public")
 
265
        {
 
266
          iter = model.next (iter);
 
267
          continue;
 
268
        }
 
269
 
 
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())
 
271
          {
 
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")
 
281
            group = Group.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));
 
287
          }
 
288
        iter = model.next (iter);
 
289
      }
 
290
      if (iter == end)
 
291
      {
 
292
        iter = null;
 
293
      }
 
294
     
 
295
      Idle.add (() => {
 
296
        place_entry.thaw_notify ();
 
297
        return false;
 
298
      });
 
299
 
 
300
      if (search != null)
 
301
        search.finished ();
 
302
 
 
303
      debug ("Results has %u rows", results_model.get_n_rows());
 
304
    }
 
305
 
 
306
  } /* End Daemon class */
 
307
} /* end Gwibber namespace */