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

Proposed by Marco Trevisan (Treviño) on 2010-12-05
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) Resubmit on 2010-12-05
Michal Hruby 2010-12-05 Needs Fixing on 2010-12-05
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.
Michal Hruby (mhr3) wrote : Posted in a previous version of this proposal

Could you please fix the pot file issue?

review: Needs Fixing
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... :/

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... :/

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.

Michal Hruby (mhr3) wrote : Posted in a previous version of this proposal

Nope...

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) on 2010-12-05

merge with Head

226. By Marco Trevisan (Treviño) on 2010-12-05

reverted old synapse.pot

227. By Marco Trevisan (Treviño) on 2010-12-05

Updated pot file again

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: Resubmit
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.

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! :/)

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...

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)

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... :(

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.

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...

Michal Hruby (mhr3) wrote :

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

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

Antono Vasiljev (antono) wrote :

Yo. Any updates here?

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) on 2010-12-05

Updated pot file again

226. By Marco Trevisan (Treviño) on 2010-12-05

reverted old synapse.pot

225. By Marco Trevisan (Treviño) on 2010-12-05

merge with Head

224. By Marco Trevisan (Treviño) on 2010-12-05

fixed the pot merging issue

223. By Marco Trevisan (Treviño) on 2010-12-05

Merging with head (again..)

222. By Marco Trevisan (Treviño) on 2010-12-05

gwibber: Added to translations potfiles

221. By Marco Trevisan (Treviño) on 2010-12-05

Merge with head branch

220. By Marco Trevisan (Treviño) on 2010-12-05

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) on 2010-12-04

gwibber: added SendMessage feature

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

218. By Marco Trevisan (Treviño) on 2010-12-04

Merge with master branch

Preview Diff

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