~ubuntu-branches/ubuntu/jaunty/beagle/jaunty-security

« back to all changes in this revision

Viewing changes to search/Beagle.Search.Tiles/Tile.cs

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Ebner
  • Date: 2008-05-04 00:31:32 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20080504003132-2tkm5o8moo5952ri
Tags: 0.3.7-2ubuntu1
 * Merge from Debian unstable. (LP: #225746) Remaining Ubuntu changes:
  - debian/control:
    + Rename ice{weasel,dove}-beagle to {mozilla,thunderbird}-beagle and
      and update the dependencies accordingly.
    + Change Maintainer to Ubuntu Mono Team.
  - debian/rules:
    + Install the mozilla-beagle and thunderbird-beagle extensions.
  - ice{dove,weasel}.dirs:
    + Renamed to {mozilla,thunderbird}-beagle.dirs.
    + Fixed paths to point to usr/lib/{firefox,thunderbird}

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Tile.cs
 
3
//
 
4
// Copyright (C) 2008 Lukas Lipka <lukaslipka@gmail.com>
 
5
//
 
6
 
 
7
using System;
 
8
using System.Collections.Generic;
 
9
using System.Runtime.InteropServices;
 
10
using System.Text.RegularExpressions;
 
11
using System.Diagnostics;
 
12
using Mono.Unix;
 
13
 
 
14
using Gtk;
 
15
using Beagle;
 
16
using Beagle.Util;
 
17
 
 
18
namespace Beagle.Search.Tiles {
 
19
 
 
20
        public abstract class Tile : Gtk.EventBox {
 
21
 
 
22
                private Beagle.Hit hit = null;
 
23
                private Beagle.Query query = null;
 
24
 
 
25
                private Gtk.HBox hbox = null;
 
26
                private Gtk.Image icon = null;
 
27
                private DetailsPane details = null;
 
28
 
 
29
                private string title = null;
 
30
                private string snippet = null;
 
31
                private DateTime timestamp;
 
32
                private double score = 0.0f;
 
33
 
 
34
                // Default the tile group to documents, it is up
 
35
                // to the each tile to set a specific group.
 
36
 
 
37
                private TileGroup group = TileGroup.Documents;
 
38
 
 
39
                // DND targets
 
40
 
 
41
                static Gtk.TargetEntry[] targets = new Gtk.TargetEntry[] {
 
42
                        new Gtk.TargetEntry ("text/uri-list", 0, 0)
 
43
                };
 
44
 
 
45
                private List<TileAction> actions = new List<TileAction> ();
 
46
 
 
47
                protected bool EnableOpenWith = false;
 
48
 
 
49
                public event EventHandler Selected;
 
50
 
 
51
                public delegate void GotSnippetHandler (string snippet);
 
52
                public event GotSnippetHandler GotSnippet;
 
53
 
 
54
                public Tile (Hit hit, Query query) : base ()
 
55
                {
 
56
                        base.AboveChild = true;
 
57
                        base.AppPaintable = true;
 
58
                        base.CanFocus = true;
 
59
 
 
60
                        this.hit = hit;
 
61
                        this.query = query;
 
62
                        this.timestamp = hit.Timestamp;
 
63
                        this.score = hit.Score;
 
64
 
 
65
                        Gtk.Drag.SourceSet (this, Gdk.ModifierType.Button1Mask, targets,
 
66
                                            Gdk.DragAction.Copy | Gdk.DragAction.Move);
 
67
 
 
68
                        int pad = (int)StyleGetProperty ("focus-line-width") + (int)StyleGetProperty ("focus-padding") + 1;
 
69
 
 
70
                        hbox = new Gtk.HBox (false, 5);
 
71
                        hbox.BorderWidth = (uint)(pad + Style.Xthickness);
 
72
                        hbox.Show ();
 
73
 
 
74
                        icon = new Gtk.Image ();
 
75
                        icon.Show ();
 
76
                        hbox.PackStart (icon, false, false, 0);
 
77
 
 
78
                        Add (hbox);
 
79
                }
 
80
 
 
81
                protected void AddAction (TileAction action)
 
82
                {
 
83
                        actions.Add (action);
 
84
                }
 
85
 
 
86
                protected void RemoveAction (TileAction action)
 
87
                {
 
88
                        actions.Remove (action);
 
89
                }
 
90
 
 
91
                private void ShowPopupMenu ()
 
92
                {
 
93
                        Gtk.Menu menu = new Gtk.Menu ();
 
94
                        
 
95
                        // Add the default 'Open' menu item
 
96
 
 
97
                        TileAction open = new TileAction (Catalog.GetString ("Open"), Stock.Open, Open);
 
98
 
 
99
                        ActionMenuItem open_menu_item = new ActionMenuItem (open);
 
100
                        menu.Append (open_menu_item);
 
101
 
 
102
#if ENABLE_OPEN_WITH
 
103
                        if (EnableOpenWith) {
 
104
                                // FIXME: Not sure if going with the parent is
 
105
                                // the right thing to do in all cases.
 
106
                                string mimetype = Utils.GetFirstPropertyOfParent (hit, "beagle:MimeType");
 
107
 
 
108
                                OpenWithMenu owm = new OpenWithMenu (mimetype);
 
109
                                owm.ApplicationActivated += OpenWith;
 
110
                                owm.AppendToMenu (menu);
 
111
                        }
 
112
#endif
 
113
 
 
114
                        if (Actions.Count > 0) {
 
115
                                SeparatorMenuItem separator = new SeparatorMenuItem ();
 
116
                                menu.Append (separator);
 
117
 
 
118
                                foreach (TileAction action in Actions) {
 
119
                                        ActionMenuItem item = new ActionMenuItem (action);
 
120
                                        menu.Append (item);
 
121
                                }
 
122
                        }
 
123
 
 
124
                        menu.ShowAll ();
 
125
                        menu.Popup ();
 
126
                }
 
127
 
 
128
                protected override void OnDragBegin (Gdk.DragContext context)
 
129
                {
 
130
                        if (!icon.Visible)
 
131
                                return;
 
132
 
 
133
                        WidgetFu.SetDragImage (context, icon);
 
134
                }
 
135
 
 
136
                protected override void OnDragDataGet (Gdk.DragContext ctx, Gtk.SelectionData data, uint info, uint time)
 
137
                {
 
138
                        byte[] uri = System.Text.Encoding.UTF8.GetBytes (Hit.EscapedUri + "\r\n");
 
139
                        data.Set (data.Target, 8, uri);
 
140
                }
 
141
 
 
142
                /*protected override void OnSizeRequested (ref Gtk.Requisition req)
 
143
                {
 
144
                        // base.OnSizeRequested (ref req) should work,
 
145
                        // but it doesn't
 
146
                        req = hbox.SizeRequest ();
 
147
 
 
148
                        int pad = (int)StyleGetProperty ("focus-line-width") + (int)StyleGetProperty ("focus-padding") + 1;
 
149
 
 
150
                        req.Width += 2 * (pad + Style.Xthickness);
 
151
                        req.Height += 2 * (pad + Style.Ythickness);
 
152
                }
 
153
 
 
154
                protected override void OnSizeAllocated (Gdk.Rectangle alloc)
 
155
                {
 
156
                        int pad = (int)StyleGetProperty ("focus-line-width") + (int)StyleGetProperty ("focus-padding") + 1;
 
157
 
 
158
                        alloc.X += pad + Style.Xthickness;
 
159
                        alloc.Y += pad + Style.Ythickness;
 
160
                        alloc.Width -= pad + Style.Xthickness;
 
161
                        alloc.Height -= pad + Style.Ythickness;
 
162
 
 
163
                        base.OnSizeAllocated (alloc);
 
164
                        }*/
 
165
 
 
166
                protected override bool OnExposeEvent (Gdk.EventExpose evt)
 
167
                {
 
168
                        if (!IsDrawable)
 
169
                                return false;
 
170
 
 
171
                        Cairo.Context gr = Gdk.CairoHelper.Create (evt.Window);
 
172
 
 
173
                        Gdk.Color fill = Style.BaseColors [(int)StateType.Normal];
 
174
 
 
175
                        gr.Rectangle (evt.Area.X, evt.Area.Y, evt.Area.Width, evt.Area.Height);
 
176
                        gr.Color = CairoFu.GdkColorToCairoColor (fill);
 
177
                        gr.Fill ();
 
178
 
 
179
                        if (State == StateType.Selected) {
 
180
                                CairoFu.RoundedSelection (gr, this, 0, 0, Allocation.Width, Allocation.Height);
 
181
                        }
 
182
 
 
183
                        if (HasFocus) {
 
184
                                int focus_padding = (int)StyleGetProperty ("focus-padding");
 
185
                                int x = focus_padding + Style.Xthickness;
 
186
                                int y = focus_padding + Style.Ythickness;
 
187
                                int width = Allocation.Width - 2 * (focus_padding + Style.Xthickness);
 
188
                                int height = Allocation.Height - 2 * (focus_padding + Style.Ythickness);
 
189
                                Style.PaintFocus (Style, GdkWindow, State, evt.Area, this, null, x, y, width, height);
 
190
                        }
 
191
                        
 
192
                        CairoFu.DisposeContext (gr);
 
193
 
 
194
                        if (base.OnExposeEvent (evt))
 
195
                                return true;
 
196
 
 
197
                        return false;
 
198
                }
 
199
 
 
200
                protected override bool OnButtonPressEvent (Gdk.EventButton b)
 
201
                {
 
202
                        GrabFocus ();
 
203
 
 
204
                        if (b.Button == 3) {
 
205
                                ShowPopupMenu ();
 
206
 
 
207
                                return true;
 
208
                        } else if (b.Type == Gdk.EventType.TwoButtonPress) {
 
209
                                Open ();
 
210
 
 
211
                                if (b.Button == 2 || ((b.State & Gdk.ModifierType.ShiftMask) != 0))
 
212
                                        Gtk.Application.Quit ();
 
213
 
 
214
                                return true;
 
215
                        }
 
216
 
 
217
                        return base.OnButtonPressEvent (b);
 
218
                }
 
219
 
 
220
                protected override bool OnFocusInEvent (Gdk.EventFocus f)
 
221
                {
 
222
                        if (Selected != null)
 
223
                                Selected (this, EventArgs.Empty);
 
224
 
 
225
                        return base.OnFocusInEvent (f);
 
226
                }
 
227
 
 
228
                protected override bool OnKeyPressEvent (Gdk.EventKey k)
 
229
                {
 
230
                        if (k.Key == Gdk.Key.Return || k.Key == Gdk.Key.KP_Enter) {
 
231
                                Open ();
 
232
 
 
233
                                if ((k.State & Gdk.ModifierType.ShiftMask) != 0)
 
234
                                        Gtk.Application.Quit ();
 
235
 
 
236
                                return true;
 
237
                        }
 
238
 
 
239
                        return base.OnKeyPressEvent (k);
 
240
                }
 
241
 
 
242
                protected virtual void LoadIcon (Gtk.Image image, int size)
 
243
                {
 
244
                        // This is a hack to prevent large mime icons when we
 
245
                        // dont have a thumbnail.
 
246
                        if (size > 48)
 
247
                                size = 48;
 
248
 
 
249
                        image.Pixbuf = WidgetFu.LoadMimeIcon (hit.MimeType, size);
 
250
                }
 
251
 
 
252
                protected void RequestSnippet ()
 
253
                {
 
254
                        if (snippet != null) {
 
255
                                EmitGotSnippet ();
 
256
                        } else {
 
257
                                SnippetRequest sreq = new SnippetRequest (query, hit);
 
258
                                sreq.RegisterAsyncResponseHandler (typeof (SnippetResponse), SnippetResponseReceived);
 
259
                                sreq.SendAsync ();
 
260
                        }
 
261
                }
 
262
 
 
263
                private void SnippetResponseReceived (ResponseMessage response)
 
264
                {
 
265
                        // The returned snippet uses <font color="..."><b>blah</b></font>
 
266
                        // to mark matches. The rest of the snippet might be HTML, or
 
267
                        // it might be plain text, including unescaped '<'s and '&'s.
 
268
                        // So we escape it, fix the match highlighting, and leave any
 
269
                        // other tags escaped.
 
270
 
 
271
                        // FIXME: Use the new snippeting framework
 
272
                        
 
273
                        snippet = GLib.Markup.EscapeText (((SnippetResponse)response).Snippet);
 
274
                        snippet = Regex.Replace (snippet, "&lt;font color=&quot;.*?&quot;&gt;&lt;b&gt;(.*?)&lt;/b&gt;&lt;/font&gt;", "<b>$1</b>");
 
275
                        if (snippet.Trim ().Length > 0)
 
276
                                EmitGotSnippet ();
 
277
                }
 
278
 
 
279
                private void EmitGotSnippet ()
 
280
                {
 
281
                        if (! String.IsNullOrEmpty (snippet) && GotSnippet != null)
 
282
                                GotSnippet (snippet);
 
283
                }
 
284
 
 
285
                protected virtual DetailsPane GetDetails ()
 
286
                {
 
287
                        return null;
 
288
                }
 
289
 
 
290
                public Gtk.Widget Details {
 
291
                        get {
 
292
                                if (details == null) {
 
293
                                        details = GetDetails ();
 
294
                                        if (details != null) {
 
295
                                                if (details.Icon.Pixbuf == null)
 
296
                                                        LoadIcon (details.Icon, 128);
 
297
 
 
298
                                                if (details.Snippet != null) {
 
299
                                                        GotSnippet += details.GotSnippet;
 
300
                                                        RequestSnippet ();
 
301
                                                }
 
302
                                                
 
303
                                                details.Show ();
 
304
                                        }
 
305
                                }
 
306
                                return details;
 
307
                        }
 
308
                }
 
309
 
 
310
                public virtual void Open ()
 
311
                {
 
312
                        System.Console.WriteLine ("Warning: Open method not implemented for '{0}'", this.GetType ());
 
313
                }
 
314
 
 
315
#if ENABLE_OPEN_WITH
 
316
                private void OpenWith (Gnome.Vfs.MimeApplication mime_application)
 
317
                {
 
318
                        GLib.List uri_list = new GLib.List (typeof (string));
 
319
                        uri_list.Append (Hit.EscapedUri);
 
320
                        mime_application.Launch (uri_list);
 
321
                }
 
322
#endif
 
323
 
 
324
                protected void OpenFromMime (Hit hit)
 
325
                {
 
326
                        string command = null, item;
 
327
                        bool expects_uris = false;
 
328
 
 
329
                        string mimetype = hit.MimeType;
 
330
 
 
331
                        // FIXME: This is evil.  Nautilus should be handling
 
332
                        // inode/directory, not just x-directory/normal
 
333
                        if (mimetype == "inode/directory")
 
334
                                mimetype = "x-directory/normal";
 
335
 
 
336
#if ENABLE_DESKTOP_LAUNCH
 
337
                        command = "desktop-launch";
 
338
                        expects_uris = true;
 
339
#elif ENABLE_XDG_OPEN
 
340
                        command = "xdg-open";
 
341
                        expects_uris = true;
 
342
#else
 
343
                        GnomeFu.VFSMimeApplication app;
 
344
                        app = GnomeFu.GetDefaultAction (mimetype);
 
345
                        if (app.command != null) {
 
346
                                command = app.command;
 
347
                                expects_uris = (app.expects_uris != GnomeFu.VFSMimeApplicationArgumentType.Path);
 
348
                        }
 
349
#endif                  
 
350
                        if (command == null) {
 
351
                                Console.WriteLine ("Can't open MimeType '{0}'", mimetype);
 
352
                                return;
 
353
                        }
 
354
                        
 
355
                        if (expects_uris) {
 
356
                                // FIXME: I'm not sure that opening the parent
 
357
                                // URI (if present) is the right thing to do in
 
358
                                // all cases, but it does work for all our
 
359
                                // current cases.
 
360
                                if (hit.ParentUri != null)
 
361
                                        item = hit.EscapedParentUri;
 
362
                                else
 
363
                                        item = hit.EscapedUri;
 
364
                        } else
 
365
                                item = hit.Path;
 
366
 
 
367
                        // Sometimes the command is 'quoted'
 
368
                        if (command.IndexOf ('\'') == 0 && command.LastIndexOf ('\'') == command.Length - 1)
 
369
                                command = command.Trim ('\'');
 
370
 
 
371
                        // This won't work if a program really has a space in
 
372
                        // the command filename, but I think other things would
 
373
                        // break with that too, and in practice it doesn't seem to
 
374
                        // happen.
 
375
                        //
 
376
                        // A bigger issue is that the arguments are split up by
 
377
                        // spaces, so quotation marks used to indicate a single
 
378
                        // entry in the argv won't work.  This probably should
 
379
                        // be fixed.
 
380
                        string[] arguments = null;
 
381
                        int idx = command.IndexOf (' ');
 
382
                        if (idx != -1) {
 
383
                                arguments = command.Substring (idx + 1).Split (' ');
 
384
                                command = command.Substring (0, idx);
 
385
                        }
 
386
 
 
387
                        string[] argv;
 
388
                        if (arguments == null)
 
389
                                argv = new string [] { command, item };
 
390
                        else {
 
391
                                argv = new string [arguments.Length + 2];
 
392
                                argv [0] = command;
 
393
                                argv [argv.Length - 1] = item;
 
394
                                Array.Copy (arguments, 0, argv, 1, arguments.Length);
 
395
                        }
 
396
 
 
397
                        Console.WriteLine ("Cmd: {0}", command);
 
398
                        Console.WriteLine ("Arg: {0}", String.Join (" ", argv, 1, argv.Length - 2));
 
399
                        Console.WriteLine ("Itm: {0}", item);
 
400
 
 
401
                        SafeProcess p = new SafeProcess ();
 
402
                        p.Arguments = argv;
 
403
 
 
404
                        try {
 
405
                                p.Start ();
 
406
                        } catch (Exception e) {
 
407
                                Console.WriteLine ("Error in OpenFromMime: " + e);
 
408
                        }
 
409
                }
 
410
 
 
411
                public void OpenFromUri (Uri uri)
 
412
                {
 
413
                        OpenFromUri (UriFu.UriToEscapedString (uri));
 
414
                }
 
415
 
 
416
                public void OpenFromUri (string uri)
 
417
                {
 
418
#if ENABLE_DESKTOP_LAUNCH || ENABLE_XDG_OPEN
 
419
                        SafeProcess p = new SafeProcess ();
 
420
 
 
421
#  if ENABLE_DESKTOP_LAUNCH
 
422
                        p.Arguments = new string[] { "desktop-launch", uri };
 
423
#  elif ENABLE_XDG_OPEN
 
424
                        p.Arguments = new string[] { "xdg-open", uri };
 
425
#  endif
 
426
 
 
427
                        try {
 
428
                                p.Start ();
 
429
                        } catch (Exception e) {
 
430
                                Console.WriteLine ("Could not load handler for {0}: {1}", uri, e);
 
431
                        }
 
432
#else                   
 
433
                        try {
 
434
                                Gnome.Url.Show (uri);
 
435
                        } catch (Exception e) {
 
436
                                Console.WriteLine ("Could not load handler for {0}: {1}", uri, e);
 
437
                        }
 
438
#endif
 
439
                }
 
440
 
 
441
                ///////////////////////////////////////////////////////
 
442
 
 
443
                public Beagle.Hit Hit {
 
444
                        get { return hit; }
 
445
                }
 
446
 
 
447
                public Beagle.Query Query {
 
448
                        get { return query; }
 
449
                }
 
450
 
 
451
                public TileGroup Group {
 
452
                        get { return group; }
 
453
                        protected set { group = value; }
 
454
                }
 
455
 
 
456
                protected Gtk.HBox HBox { 
 
457
                        get { return hbox; }
 
458
                }
 
459
 
 
460
                public Gtk.Image Icon {
 
461
                        get { return icon; }
 
462
                        set { icon = value; }
 
463
                }
 
464
 
 
465
                public virtual string Title {
 
466
                        get { return title; }
 
467
                        set { title = value; }
 
468
                }
 
469
 
 
470
                public virtual DateTime Timestamp {
 
471
                        get { return timestamp; }
 
472
                        set { timestamp = value; }
 
473
                }
 
474
 
 
475
                public virtual double Score {
 
476
                        get { return score; }
 
477
                        set { score = value; }
 
478
                }
 
479
 
 
480
                public IList<TileAction> Actions {
 
481
                        get { return actions; }
 
482
                }
 
483
        }
 
484
}