Merge lp:~3v1n0/synapse-project/gwibber-plugin into lp:synapse-project

Proposed by Marco Trevisan (Treviño)
Status: Needs review
Proposed branch: lp:~3v1n0/synapse-project/gwibber-plugin
Merge into: lp:synapse-project
Diff against target: 424 lines (+387/-0)
4 files modified
po/POTFILES.in (+1/-0)
src/plugins/Makefile.am (+1/-0)
src/plugins/gwibber-plugin.vala (+384/-0)
src/synapse-main.vala (+1/-0)
To merge this branch: bzr merge lp:~3v1n0/synapse-project/gwibber-plugin
Reviewer Review Type Date Requested Status
Marco Trevisan (Treviño) (community) Needs Resubmitting
Michal Hruby Needs Fixing
Review via email: mp+42783@code.launchpad.net

This proposal supersedes a proposal from 2010-12-05.

Description of the change

Added new Gwibber plugin which allows to control the gwibber service (starting, stopping or reloading its data) and to send messages to the enabled social networks.

The message can be sent both writing any valid text (<= 140 chars) in synapse or selecting a gwibber binary and then writing it as a query.

To post a comment you must log in.
Revision history for this message
Michal Hruby (mhr3) wrote : Posted in a previous version of this proposal

Could you please fix the pot file issue?

review: Needs Fixing
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

> Could you please fix the pot file issue?

I don't know why but bzr doesn't allow me to do that... If I remove the file, it asks me to re-add it to stay synced with upstream, if reset it with the original one, it gives me out this output... :/

Revision history for this message
Michal Hruby (mhr3) wrote : Posted in a previous version of this proposal

The problem seems to be that you removed the pot file in r216, the only way to fix this will be probably to create a new branch... :/

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

> The problem seems to be that you removed the pot file in r216, the only way to
> fix this will be probably to create a new branch... :/

Please, check if latest revision fixes the issue... Thanks.

Revision history for this message
Michal Hruby (mhr3) wrote : Posted in a previous version of this proposal

Nope...

Revision history for this message
Michal Hruby (mhr3) wrote :

Still the same issue, as I said, you'll most likely need to re-create the branch - just `bzr branch` trunk again, copy your additions there and push it all in one commit.

review: Needs Fixing
225. By Marco Trevisan (Treviño)

merge with Head

226. By Marco Trevisan (Treviño)

reverted old synapse.pot

227. By Marco Trevisan (Treviño)

Updated pot file again

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Ok, this version should be ok for merging now... Isn't it?!

Sorry, but I'm a git addicted, and bzr is not so friendly as git is to me :P

review: Needs Resubmitting
Revision history for this message
Michal Hruby (mhr3) wrote :

> Ok, this version should be ok for merging now... Isn't it?!
>
> Sorry, but I'm a git addicted, and bzr is not so friendly as git is to me :P

Coming from the other side of the barricade, I completely understand your frustration, but it's still not right, anyhow it has still the same issue, once you delete a file from the tree and then re-add it, it's marked in the history, and you won't fix it by adding more revisions.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

> > Ok, this version should be ok for merging now... Isn't it?!
> >
> > Sorry, but I'm a git addicted, and bzr is not so friendly as git is to me :P
>
> Coming from the other side of the barricade, I completely understand your
> frustration, but it's still not right, anyhow it has still the same issue,
> once you delete a file from the tree and then re-add it, it's marked in the
> history, and you won't fix it by adding more revisions.

Mh, I thought that using the revert command in the proper way was enough for restoring a removed file (and so I read in the ML)... In fact the diff shown here and in my local tree, against the master branch doesn't report a conflict with the synapse.pot file any more... Why the diff shown here (http://pastebin.ubuntu.com/540314/) doesn't merge with master? :(

I'm hating bazaar :P, however if you can't merge, I'll re-push a newer tree as soon as I can (also if I don't like loosing the commit history! :/)

Revision history for this message
Michal Hruby (mhr3) wrote :

I was actually only looking here at the diff, and it still showed the file as being removed and re-added, but now it's ok, now I wonder if I didn't refresh the page, or Launchpad is having fun with me...

Revision history for this message
Alberto Aldegheri (albyrock87) wrote :

Trevino: Thank you for this plugin, but I have some things to say.

If I search for "Gwibber", Synapse shows me the "Gwibber launcher".

If I press tab I see:
Refresh
Stop
Send to Gwibber

The "Send to Gwibber" shouldn't be there: it should be there only while selecting the unknown match (ie simple text).

Also I think that "Send to Gwibber" shouldn't be the first Action for unknown matches:
The risk is to send to Gwibber unwanted text. (IMHO - mhr3, need I your idea about this)

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

About the "send to gwibber" thing, I agree... I've to fix that, I already gave a look to a clean way to accomplish it.

For the second point, I think that we just have to reduce its priority... Actually the default unknown action is the dictionary... However you can choose the default value you'd like to have.

I'm also writing another action class which will allow to send the written text to the specified protocol, but I'm too busy in these days for pushing it... :(

Revision history for this message
Michal Hruby (mhr3) wrote :

The "Send to Gwibber" action should try to be smart, and increase the Score based on the query, ie if I type "@[a-z].*" it's quite clear what I'd want this action, also the more words in the query, the more likely that it is for this action...

Also "Send to Gwibber" - what does that even mean? I'd be nice if the plugin looked at the available accounts and displayed "Tweet this" / "Update facebook status" etc.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

> The "Send to Gwibber" action should try to be smart, and increase the Score
> based on the query, ie if I type "@[a-z].*" it's quite clear what I'd want
> this action, also the more words in the query, the more likely that it is for
> this action...

Ok for this... Give me some priority values to use...

> Also "Send to Gwibber" - what does that even mean? I'd be nice if the plugin
> looked at the available accounts and displayed "Tweet this" / "Update facebook
> status" etc.

The version I've in my local branch, take cares of the enabled accounts, and I've also added an action for every single enabled account (i.e. Send to Twitter, Send to Identi.ca...), not to send to every enabled account; but for using the default Gwibber sending feature, I'd use a title like this or maybe "Send via Gwibber" showing to which services in the description...

Revision history for this message
Michal Hruby (mhr3) wrote :

> Ok for this... Give me some priority values to use...

Use anything, I'll tune it during the merge.

Revision history for this message
Antono Vasiljev (antono) wrote :

Yo. Any updates here?

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

No, sorry. I've no more time to maintain this, so feel free to branch and hack on this.

Unmerged revisions

227. By Marco Trevisan (Treviño)

Updated pot file again

226. By Marco Trevisan (Treviño)

reverted old synapse.pot

225. By Marco Trevisan (Treviño)

merge with Head

224. By Marco Trevisan (Treviño)

fixed the pot merging issue

223. By Marco Trevisan (Treviño)

Merging with head (again..)

222. By Marco Trevisan (Treviño)

gwibber: Added to translations potfiles

221. By Marco Trevisan (Treviño)

Merge with head branch

220. By Marco Trevisan (Treviño)

gwibber: adding GwibberQueryAction wrapping class.

This class allows to perform actions for matching queries, not just based
on the action name. For example, you can match the gwibber binary (or
desktop file), and then write your message... This will be parsed and
then, eventually, sent to gwibber.

219. By Marco Trevisan (Treviño)

gwibber: added SendMessage feature

Actually it works for every written string with length <= 140 chars.

218. By Marco Trevisan (Treviño)

Merge with master branch

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'po/POTFILES.in'
--- po/POTFILES.in 2010-12-05 14:27:47 +0000
+++ po/POTFILES.in 2010-12-05 22:26:27 +0000
@@ -14,6 +14,7 @@
14src/plugins/directory-plugin.c14src/plugins/directory-plugin.c
15src/plugins/gnome-session-plugin.c15src/plugins/gnome-session-plugin.c
16src/plugins/gnome-screensaver-plugin.c16src/plugins/gnome-screensaver-plugin.c
17src/plugins/gwibber-plugin.c
17src/plugins/hybrid-search-plugin.c18src/plugins/hybrid-search-plugin.c
18src/plugins/locate-plugin.c19src/plugins/locate-plugin.c
19src/plugins/rhythmbox-plugin.c20src/plugins/rhythmbox-plugin.c
2021
=== modified file 'src/plugins/Makefile.am'
--- src/plugins/Makefile.am 2010-12-05 14:15:45 +0000
+++ src/plugins/Makefile.am 2010-12-05 22:26:27 +0000
@@ -32,6 +32,7 @@
32 directory-plugin.vala \32 directory-plugin.vala \
33 gnome-session-plugin.vala \33 gnome-session-plugin.vala \
34 gnome-screensaver-plugin.vala \34 gnome-screensaver-plugin.vala \
35 gwibber-plugin.vala \
35 hybrid-search-plugin.vala \36 hybrid-search-plugin.vala \
36 locate-plugin.vala \37 locate-plugin.vala \
37 rhythmbox-plugin.vala \38 rhythmbox-plugin.vala \
3839
=== added file 'src/plugins/gwibber-plugin.vala'
--- src/plugins/gwibber-plugin.vala 1970-01-01 00:00:00 +0000
+++ src/plugins/gwibber-plugin.vala 2010-12-05 22:26:27 +0000
@@ -0,0 +1,384 @@
1/*
2 * Copyright (C) 2010 Marco Trevisan (Treviño) <mail@3v1n0.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 */
19
20namespace Synapse
21{
22 const string APP_BIN = "gwibber";
23 const string SERVICE_BIN = "gwibber-service";
24
25 [DBus (name = "com.Gwibber.Service")]
26 interface GwibberService : Object {
27 public const string UNIQUE_NAME = "com.Gwibber.Service";
28 public const string OBJECT_PATH = "/com/gwibber/Service";
29 public const string INTERFACE_NAME = "com.Gwibber.Service";
30
31 public abstract async void Start() throws DBus.Error;
32 public abstract async void Refresh() throws DBus.Error;
33 public abstract async void Quit() throws DBus.Error;
34 public abstract async void SendMessage(string msg) throws DBus.Error;
35 }
36
37 [DBus (name = "com.Gwibber.Accounts")]
38 interface GwibberAccounts : Object {
39 public const string UNIQUE_NAME = "com.Gwibber.Accounts";
40 public const string OBJECT_PATH = "/com/gwibber/Accounts";
41 public const string INTERFACE_NAME = "com.Gwibber.Accounts";
42
43 public abstract async string? SendEnabled(string id) throws DBus.Error;
44 public abstract async string? Get(string id) throws DBus.Error;
45 public abstract async string? List() throws DBus.Error;
46 public abstract async string? Query(string query) throws DBus.Error;
47 }
48
49 public class GwibberPlugin : ActionPlugin
50 {
51 private Gee.List<GwibberAction> actions;
52
53 static void register_plugin()
54 {
55 DataSink.PluginRegistry.get_default().register_plugin(
56 typeof (GwibberPlugin),
57 "Gwibber",
58 _ ("Allows you to post to micro-blogging services via Gwibber."),
59 "gwibber",
60 register_plugin,
61 Environment.find_program_in_path("gwibber-service") != null,
62 _ ("Gwibber is not installed")
63 );
64 }
65
66 construct
67 {
68 actions = new Gee.ArrayList<GwibberAction>();
69
70 actions.add(new Start());
71 actions.add(new Stop());
72 actions.add(new Refresh());
73 actions.add(new SendMessage());
74 }
75
76 public override bool handles_unknown()
77 {
78 return is_gwibber_running();
79 }
80
81 private static bool is_gwibber_running() {
82 return DBusNameCache.get_default().name_has_owner(GwibberService.UNIQUE_NAME);
83 }
84
85 static construct
86 {
87 register_plugin();
88 }
89
90 private abstract class GwibberAction : Object, Match
91 {
92 // from Match interface
93 public string title { get; construct set; }
94 public string description { get; set; }
95 public string icon_name { get; construct set; }
96 public bool has_thumbnail { get; construct set; }
97 public string thumbnail_path { get; construct set; }
98 public MatchType match_type { get; construct set; }
99 public int default_relevancy { get; set; }
100
101 public abstract bool valid_for_match(Match match);
102
103 public virtual bool valid_for_query(string query)
104 {
105 return false;
106 }
107
108 // stupid Vala...
109 protected async abstract void execute_internal(Match? match);
110 public void execute (Match? match)
111 {
112 execute_internal.begin(match);
113 }
114
115 public virtual int get_relevancy()
116 {
117 return is_gwibber_running() ? default_relevancy + 20 : default_relevancy;
118 }
119 }
120
121 private abstract class GwibberBinAction : GwibberAction
122 {
123 protected static string service_path = Environment.find_program_in_path(SERVICE_BIN);
124 protected static string app_path = Environment.find_program_in_path(APP_BIN);
125
126 // Stupid vala...
127 protected async abstract void execute_internal_bin(Match? match);
128 public override async void execute_internal(Match? match)
129 {
130 execute_internal_bin(match);
131 }
132
133 public override bool valid_for_match(Match match)
134 {
135 if (match.match_type == MatchType.APPLICATION)
136 {
137 ApplicationMatch? am = match as ApplicationMatch;
138
139 AppInfo app = am.app_info ??
140 new DesktopAppInfo.from_filename(am.filename);
141
142 var exe = Environment.find_program_in_path(app.get_executable());
143 if (exe == service_path || exe == app_path)
144 return true;
145 }
146
147 return false;
148 }
149 }
150
151 private class GwibberQueryAction : GwibberAction
152 {
153 private string query;
154 private GwibberAction action;
155
156 public GwibberQueryAction(string query, GwibberAction action) {
157 Object (title: action.title,
158 description: action.description,
159 icon_name: action.icon_name, has_thumbnail: action.has_thumbnail,
160 match_type: action.match_type,
161 default_relevancy: action.default_relevancy);
162
163 this.query = query;
164 this.action = action;
165 }
166
167 public override bool valid_for_match(Match match)
168 {
169 return this.action.valid_for_match(match);
170 }
171
172 public override bool valid_for_query(string query)
173 {
174 return this.action.valid_for_query(query);
175 }
176
177 protected override async void execute_internal(Match? match) {
178 var nm = new DefaultMatch(this.query);
179 nm.match_type = MatchType.UNKNOWN;
180
181 this.action.execute_internal(nm);
182 }
183
184 public override int get_relevancy()
185 {
186 return this.action.get_relevancy();
187 }
188 }
189
190 private class Start : GwibberBinAction
191 {
192 public Start()
193 {
194 Object (title: _ ("Start"),
195 description: _ ("Start Gwibber Service"),
196 icon_name: "gtk-apply", has_thumbnail: false,
197 match_type: MatchType.ACTION,
198 default_relevancy: 150);
199 }
200
201 public async override void execute_internal_bin(Match? match)
202 {
203 if (is_gwibber_running())
204 return;
205
206 try {
207 var conn = DBus.Bus.get(DBus.BusType.SESSION);
208 var service = (GwibberService)conn.get_object(GwibberService.UNIQUE_NAME,
209 GwibberService.OBJECT_PATH,
210 GwibberService.INTERFACE_NAME);
211 yield service.Start();
212 } catch (DBus.Error e) {
213 stderr.printf ("Gwibber is not available.\n%s", e.message);
214 }
215 }
216
217 public override bool valid_for_match(Match match)
218 {
219 if (is_gwibber_running())
220 return false;
221
222 return base.valid_for_match(match);
223 }
224 }
225
226 private class Stop : GwibberBinAction
227 {
228 public Stop()
229 {
230 Object (title: _ ("Stop"),
231 description: _ ("Stop Gwibber Service"),
232 icon_name: "gtk-close", has_thumbnail: false,
233 match_type: MatchType.ACTION,
234 default_relevancy: 150);
235 }
236
237 public override async void execute_internal_bin(Match? match)
238 {
239 if (!is_gwibber_running())
240 return;
241
242 try {
243 var conn = DBus.Bus.get(DBus.BusType.SESSION);
244 var service = (GwibberService)conn.get_object(GwibberService.UNIQUE_NAME,
245 GwibberService.OBJECT_PATH,
246 GwibberService.INTERFACE_NAME);
247 yield service.Quit();
248 } catch (DBus.Error e) {
249 stderr.printf ("Gwibber is not available.\n%s", e.message);
250 }
251 }
252
253 public override bool valid_for_match(Match match)
254 {
255 if (!is_gwibber_running())
256 return false;
257
258 return base.valid_for_match(match);
259 }
260 }
261
262 private class Refresh : GwibberBinAction
263 {
264 public Refresh()
265 {
266 Object (title: _ ("Refresh"),
267 description: _ ("Refresh Gwibber Accounts"),
268 icon_name: "gtk-refresh", has_thumbnail: false,
269 match_type: MatchType.ACTION,
270 default_relevancy: 150);
271 }
272
273 public override async void execute_internal_bin(Match? match)
274 {
275 if (!is_gwibber_running())
276 return;
277
278 try {
279 var conn = DBus.Bus.get(DBus.BusType.SESSION);
280 var service = (GwibberService)conn.get_object(GwibberService.UNIQUE_NAME,
281 GwibberService.OBJECT_PATH,
282 GwibberService.INTERFACE_NAME);
283 yield service.Refresh();
284 } catch (DBus.Error e) {
285 stderr.printf ("Gwibber is not available.\n%s", e.message);
286 }
287 }
288
289 public override bool valid_for_match(Match match)
290 {
291 if (!is_gwibber_running())
292 return false;
293
294 return base.valid_for_match(match);
295 }
296 }
297
298 private class SendMessage : GwibberBinAction
299 {
300 public SendMessage()
301 {
302 Object (title: _ ("Send to Gwibber"),
303 description: _ ("Send Message to Gwibber enabled accounts"),
304 icon_name: "gwibber", has_thumbnail: false,
305 match_type: MatchType.ACTION,
306 default_relevancy: 100);
307 }
308
309 public override async void execute_internal_bin(Match? match)
310 {
311
312 if (!is_gwibber_running() || match.match_type != MatchType.UNKNOWN)
313 return;
314
315 try {
316 var conn = DBus.Bus.get(DBus.BusType.SESSION);
317 var service = (GwibberService)conn.get_object(GwibberService.UNIQUE_NAME,
318 GwibberService.OBJECT_PATH,
319 GwibberService.INTERFACE_NAME);
320 yield service.SendMessage(match.title);
321 } catch (DBus.Error e) {
322 stderr.printf ("Gwibber is not available.\n%s", e.message);
323 }
324 }
325
326 public override bool valid_for_match(Match match)
327 {
328 if (!is_gwibber_running() || match.title.length > 140)
329 return false;
330
331 return (match.match_type == MatchType.UNKNOWN || base.valid_for_match(match));
332 }
333
334 public override bool valid_for_query(string query)
335 {
336 if (query.length <= 140)
337 return true;
338
339 return false;
340 }
341 }
342
343 public override ResultSet? find_for_match (Query query, Match match)
344 {
345 bool query_empty = query.query_string == "";
346 var results = new ResultSet();
347
348 if (query_empty)
349 {
350 foreach (var action in actions)
351 {
352 if (action.valid_for_match(match))
353 {
354 results.add(action, action.get_relevancy());
355 }
356 }
357 }
358 else
359 {
360 var matchers = Query.get_matchers_for_query(query.query_string, 0,
361 RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS);
362 foreach (var action in actions)
363 {
364 if (!action.valid_for_match(match)) continue;
365 foreach (var matcher in matchers)
366 {
367 if (action.valid_for_query(query.query_string))
368 {
369 results.add(new GwibberQueryAction(query.query_string, action), matcher.value);
370 break;
371 }
372 else if (matcher.key.match(action.title))
373 {
374 results.add(action, matcher.value);
375 break;
376 }
377 }
378 }
379 }
380
381 return results;
382 }
383 }
384}
0385
=== modified file 'src/synapse-main.vala'
--- src/synapse-main.vala 2010-12-05 14:20:09 +0000
+++ src/synapse-main.vala 2010-12-05 22:26:27 +0000
@@ -116,6 +116,7 @@
116 typeof (ZeitgeistPlugin),116 typeof (ZeitgeistPlugin),
117 typeof (HybridSearchPlugin),117 typeof (HybridSearchPlugin),
118 //typeof (LocatePlugin),118 //typeof (LocatePlugin),
119 typeof (GwibberPlugin),
119 typeof (GnomeSessionPlugin),120 typeof (GnomeSessionPlugin),
120 typeof (GnomeScreenSaverPlugin),121 typeof (GnomeScreenSaverPlugin),
121 typeof (UPowerPlugin),122 typeof (UPowerPlugin),