cvsimport
[beagle.git] / Best / BestWindow.cs
blobef9eb31bff9a7aaaacd1317a93ff232b3efae013
1 //
2 // BestWindow.cs
3 //
4 // Copyright (C) 2004 Novell, Inc.
5 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in all
16 // copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 // SOFTWARE.
28 using System;
29 using System.Collections;
31 using Gnome;
32 using Gtk;
33 using GD=Gdk;
35 using Mono.Unix;
37 using Beagle;
38 using Beagle.Util;
39 using Beagle.Tile;
41 namespace Best {
43 public class TypeMenuItem : Gtk.MenuItem {
45 public string Type;
47 public TypeMenuItem (string label, string type) : base (label)
49 this.Type = type;
53 public class BestWindow : Gtk.Window {
55 Gtk.AccelGroup accel_group;
56 GlobalKeybinder global_keys;
58 public BestWindow (string query) : base (WindowType.Toplevel)
60 CreateWindow (query);
63 public BestWindow () : base (WindowType.Toplevel)
65 CreateWindow (null);
68 public void FocusEntry ()
70 entry.GrabFocus ();
73 public void FocusEntryHandler (object o, EventArgs args)
75 FocusEntry ();
78 private void CreateWindow (string query)
80 Title = Best.DefaultWindowTitle;
82 DeleteEvent += new DeleteEventHandler (this.DoDelete);
83 MapEvent += new MapEventHandler (MapIt);
84 UnmapEvent += new UnmapEventHandler (UnmapIt);
86 Icon = Images.GetPixbuf ("best.png");
88 Widget content = CreateContents ();
90 VBox main = new VBox (false, 3);
91 main.PackStart (content, true, true, 3);
92 content.Show ();
93 Add (main);
94 main.Show ();
95 main.Realize ();
96 canvas.Realize ();
98 root = new SimpleRootTile ();
99 canvas.Root = root;
101 DefaultWidth = 600;
102 DefaultHeight = 675;
104 accel_group = new Gtk.AccelGroup ();
105 this.AddAccelGroup (accel_group);
106 global_keys = new GlobalKeybinder (accel_group);
108 // Close window (Ctrl-W)
109 global_keys.AddAccelerator (new EventHandler (this.HideWindowHandler),
110 (uint) Gdk.Key.w,
111 Gdk.ModifierType.ControlMask,
112 Gtk.AccelFlags.Visible);
114 // Close window (Escape)
115 global_keys.AddAccelerator (new EventHandler (this.HideWindowHandler),
116 (uint) Gdk.Key.Escape,
118 Gtk.AccelFlags.Visible);
120 // Show source (Ctrl+U)
121 global_keys.AddAccelerator (new EventHandler (this.ShowSource),
122 (uint) Gdk.Key.U,
123 Gdk.ModifierType.ControlMask,
124 Gtk.AccelFlags.Visible);
126 // Focus Entry (Ctrl+L)
127 global_keys.AddAccelerator (new EventHandler (this.FocusEntryHandler),
128 (uint) Gdk.Key.L,
129 Gdk.ModifierType.ControlMask,
130 Gtk.AccelFlags.Visible);
132 // Previous Page (PageUp)
133 global_keys.AddAccelerator (new EventHandler (this.PageBackHandler),
134 (uint) Gdk.Key.Page_Up,
136 Gtk.AccelFlags.Visible);
138 // Next Page (PageDown)
139 global_keys.AddAccelerator (new EventHandler (this.PageForwardHandler),
140 (uint) Gdk.Key.Page_Down,
142 Gtk.AccelFlags.Visible);
144 UpdateFromConf ();
145 UpdatePage ();
147 if (query != null)
148 Search (query);
152 //////////////////////////
154 int posX = 0, posY = 0;
156 public new void Present ()
158 base.Present ();
160 Move (posX, posY);
163 public new void Hide ()
165 // FIXME: Hack, why does Hide () gets invoked twice, the second time with (0,0) as window position?
167 int new_posX = 0, new_posY = 0;
169 GetPosition (out new_posX, out new_posY);
171 if (new_posX != 0 && new_posY != 0) {
172 posX = new_posX;
173 posY = new_posY;
176 base.Hide ();
179 //////////////////////////
181 Query query = null;
182 string hit_type = null;
184 private void SetBusy (bool busy)
186 if (busy) {
187 this.GdkWindow.Cursor = new Gdk.Cursor (Gdk.CursorType.Watch);
188 } else {
189 this.GdkWindow.Cursor = null;
194 private void DoDelete (object o, DeleteEventArgs args)
196 Hide ();
199 public bool WindowIsVisible;
201 private void MapIt (object o, MapEventArgs args)
203 WindowIsVisible = true;
206 private void UnmapIt (object o, UnmapEventArgs args)
208 WindowIsVisible = false;
211 private void HideWindowHandler (object o, EventArgs args)
213 Hide ();
216 private void ShowSource (object o, EventArgs args)
218 Gtk.Window win = new Gtk.Window ("Source");
219 win.SetDefaultSize (800,500);
220 Gtk.ScrolledWindow sw = new ScrolledWindow ();
221 sw.HscrollbarPolicy = Gtk.PolicyType.Automatic;
222 sw.VscrollbarPolicy = Gtk.PolicyType.Automatic;
223 Gtk.TextView view = new Gtk.TextView ();
224 view.CursorVisible = false;
225 view.Editable = false;
226 Gtk.TextBuffer buffer = view.Buffer;
227 buffer.Text = canvas.Source;
228 view.Buffer = buffer;
229 sw.Add (view);
230 win.Add (sw);
231 win.ShowAll ();
234 //////////////////////////
236 private void PageForward ()
238 if (!root.HitCollection.CanPageForward)
239 return;
241 root.HitCollection.PageForward ();
242 UpdatePage ();
245 private void PageBack ()
247 if (!root.HitCollection.CanPageBack)
248 return;
250 root.HitCollection.PageBack ();
251 UpdatePage ();
254 private void PageForwardHandler (object o, EventArgs args)
256 PageForward ();
259 private void PageBackHandler (object o, EventArgs args)
261 PageBack ();
264 //////////////////////////
266 private Gtk.Entry entry;
267 private Gtk.ListStore history;
269 private Gtk.ListStore filter_data;
271 private TileCanvas canvas;
272 private SimpleRootTile root;
273 private Gtk.Label page_label;
274 private Gtk.Button back_button;
275 private Gtk.Button forward_button;
277 private Gtk.Button StockButton (string stockid, string label)
279 Gtk.HBox button_contents = new HBox (false, 0);
280 button_contents.Show ();
281 Gtk.Widget button_image = new Gtk.Image (stockid, Gtk.IconSize.Button);
282 button_image.Show ();
283 button_contents.PackStart (button_image, false, false, 1);
284 Gtk.Label button_label = new Gtk.Label (label);
285 button_label.Show ();
286 button_contents.PackStart (button_label, false, false, 1);
288 Gtk.Button button = new Gtk.Button ();
289 button.Add (button_contents);
291 return button;
294 private Gtk.ComboBox FilterComboBox ()
296 filter_data = new Gtk.ListStore (new Type[] { typeof (string), typeof (string) });
298 Gtk.TreeIter iter;
300 iter = filter_data.Append ();
301 filter_data.SetValue (iter, 0, Catalog.GetString ("Anywhere"));
302 filter_data.SetValue (iter, 1, null);
304 iter = filter_data.Append ();
305 filter_data.SetValue (iter, 0, Catalog.GetString ("in Files"));
306 filter_data.SetValue (iter, 1, "File");
308 iter = filter_data.Append ();
309 filter_data.SetValue (iter, 0, Catalog.GetString ("in Addressbook"));
310 filter_data.SetValue (iter, 1, "Contact");
312 iter = filter_data.Append ();
313 filter_data.SetValue (iter, 0, Catalog.GetString ("in Mail"));
314 filter_data.SetValue (iter, 1, "MailMessage");
316 iter = filter_data.Append ();
317 filter_data.SetValue (iter, 0, Catalog.GetString ("in Web Pages"));
318 filter_data.SetValue (iter, 1, "WebHistory");
320 iter = filter_data.Append ();
321 filter_data.SetValue (iter, 0, Catalog.GetString ("in Chats"));
322 filter_data.SetValue (iter, 1, "IMLog");
324 Gtk.ComboBox combo = new Gtk.ComboBox (filter_data);
325 combo.Active = 0;
327 Gtk.CellRendererText renderer = new Gtk.CellRendererText ();
328 combo.PackStart (renderer, false);
329 combo.SetAttributes (renderer, new object[] { "text", 0 });
331 return combo;
334 private Gtk.Widget CreateContents ()
336 Gtk.HBox entryLine = new HBox (false, 4);
338 Gtk.Label words = new Gtk.Label (Catalog.GetString ("Search terms:"));
339 entryLine.PackStart (words, false, false, 3);
341 history = new Gtk.ListStore (new Type[] { typeof (string) });
343 Gtk.EntryCompletion comp = new Gtk.EntryCompletion ();
344 comp.Model = history;
345 comp.TextColumn = 0;
347 entry = new Gtk.Entry ("");
348 entry.Activated += new EventHandler (this.DoSearch);
349 entry.Completion = comp;
350 entryLine.PackStart (entry, true, true, 3);
352 words = new Gtk.Label ("");
353 entryLine.PackStart (words, false, false, 3);
355 Gtk.ComboBox combo = FilterComboBox ();
356 combo.Changed += new EventHandler (this.ChangeType);
357 entryLine.PackStart (combo, false, false, 3);
359 Gtk.HBox buttonContents = new HBox (false, 0);
360 Gtk.Widget buttonImg = Beagle.Images.GetWidget ("icon-search.png");
361 buttonContents.PackStart (buttonImg, false, false, 1);
362 Gtk.Label buttonLabel = new Gtk.Label (Catalog.GetString ("Find"));
363 buttonContents.PackStart (buttonLabel, false, false, 1);
365 Gtk.Button button = new Gtk.Button ();
366 button.Add (buttonContents);
367 button.Clicked += new EventHandler (this.DoSearch);
368 entryLine.PackStart (button, false, false, 3);
370 Gtk.Button clearButton = new Gtk.Button ();
371 clearButton.Label = "Clear";
372 clearButton.Clicked += new EventHandler (this.ClearSearch);
373 entryLine.PackStart (clearButton, false, false, 4);
375 canvas = new TileCanvas ();
376 canvas.Show ();
378 HBox pager = new HBox ();
379 page_label = new Label ();
380 page_label.Show ();
381 pager.PackStart (page_label, false, false, 3);
383 forward_button = StockButton ("gtk-go-forward",
384 Catalog.GetString ("Show More Results"));
385 forward_button.Show ();
386 forward_button.Clicked += new EventHandler (PageForwardHandler);
387 pager.PackEnd (forward_button, false, false, 3);
389 back_button = StockButton ("gtk-go-back",
390 Catalog.GetString ("Show Previous Results"));
391 back_button.Show ();
393 back_button.Clicked += new EventHandler (PageBackHandler);
394 pager.PackEnd (back_button, false, false, 3);
396 pager.Show ();
398 VBox contents = new VBox (false, 3);
399 contents.PackStart (entryLine, false, true, 3);
400 contents.PackStart (canvas, true, true, 3);
401 contents.PackStart (pager, false, false, 3);
403 entryLine.ShowAll ();
404 canvas.ShowAll ();
406 return contents;
409 private void UpdateFromConf ()
411 Console.WriteLine ("Reading settings from Config");
412 // FIXME: there might be weird cases with multiple screens,
413 // multiple monitors, resolution related problems that might
414 // cause problem is remapping the stored values to current
415 // screen coordinates
416 int res_x = GD.Screen.Default.Width;
417 int res_y = GD.Screen.Default.Height;
418 int pos_x = (int)(Conf.Searching.BestPosX * res_x / 100);
419 int pos_y = (int)(Conf.Searching.BestPosY * res_y / 100);
420 int width = (int)(Conf.Searching.BestWidth * res_x / 100 );
421 int height = (int)(Conf.Searching.BestHeight * res_y / 100);
423 if (pos_x != 0 || pos_y != 0) {
424 posX = pos_x;
425 posY = pos_y;
426 Move (pos_x, pos_y);
428 if (width != 0)
429 DefaultWidth = width;
430 if (height != 0)
431 DefaultHeight = height;
432 Gtk.TreeIter iter;
433 foreach (string search in Conf.Searching.SearchHistory) {
434 iter = history.Append ();
435 history.SetValue (iter, 0, search);
439 public void StoreSettingsInConf (bool with_tray)
441 Console.WriteLine ("Storing setting in Config");
442 int pos_x = posX, pos_y = posY;
443 if (with_tray && WindowIsVisible)
444 GetPosition (out pos_x, out pos_y);
445 int width = 0, height = 0;
446 GetSize (out width, out height);
448 int res_x = GD.Screen.Default.Width;
449 int res_y = GD.Screen.Default.Height;
450 Conf.Searching.BestPosX = ((float) pos_x / res_x) * 100;
451 Conf.Searching.BestPosY = ((float) pos_y / res_y) * 100;
452 Conf.Searching.BestWidth = ((float) width / res_x) * 100;
453 Conf.Searching.BestHeight = ((float) height / res_y) * 100;
454 Conf.Searching.SearchHistory = RetriveSearches ();
455 Conf.Searching.SaveNeeded = true;
456 Conf.Save ();
459 private void UpdatePage ()
461 //Console.WriteLine ("In UpdatePage");
462 back_button.Sensitive = root.HitCollection.CanPageBack;
463 forward_button.Sensitive = root.HitCollection.CanPageForward;
465 string label;
467 int results;
468 if (this.hit_type == null)
469 results = root.HitCollection.NumResults;
470 else
471 results = root.HitCollection.NumDisplayableResults;
473 if (results == 0) {
474 label = Catalog.GetString ("No results.");
475 } else if (root.HitCollection.FirstDisplayed == 0) {
476 /* To translators: {0} is the current count of results shown of {1} in total, this is the message that is initially shown */
477 /* when results are returned to the user. */
478 label = String.Format (Catalog.GetString ("Best <b>{0} results of {1}</b> are shown."),
479 root.HitCollection.LastDisplayed + 1,
480 results);
481 } else {
482 /* To translators: {0} to {1} is the interval of results currently shown of {2} results in total*/
483 label = String.Format (Catalog.GetString ("Results <b>{0} through {1} of {2}</b> are shown."),
484 root.HitCollection.FirstDisplayed + 1,
485 root.HitCollection.LastDisplayed + 1,
486 results);
488 page_label.Markup = label;
491 private string delayedQuery = null;
493 private bool RunDelayedQuery ()
495 if (delayedQuery != null) {
496 delayedQuery = null;
497 System.Console.WriteLine ("Delayed query fired");
498 StartQuery ();
501 return false;
504 private void QueueDelayedQuery (string query)
506 delayedQuery = query;
507 GLib.Timeout.Add (10000, new GLib.TimeoutHandler (RunDelayedQuery));
510 private void DoSearch (object o, EventArgs args)
512 if (entry.Text != null && entry.Text != "")
513 Search (entry.Text);
516 //private string lastType = null;
518 private void ChangeType (object o, EventArgs args)
520 Gtk.ComboBox combo = (Gtk.ComboBox) o;
521 string hit_type = null;
522 Gtk.TreeIter iter;
524 if (combo.GetActiveIter (out iter))
525 hit_type = (string) filter_data.GetValue (iter, 1);
527 if (this.hit_type == hit_type)
528 return;
530 this.hit_type = hit_type;
532 root.SetSource (this.hit_type);
533 root.HitCollection.PageFirst ();
534 UpdatePage ();
537 //////////////////////////
539 private void OnHitsAdded (HitsAddedResponse response)
541 root.Add (response.Hits);
542 UpdatePage ();
545 private void OnHitsSubtracted (HitsSubtractedResponse response)
547 root.Subtract (response.Uris);
548 UpdatePage ();
551 private void OnFinished (FinishedResponse repsonse)
553 SetBusy (false);
556 private void AttachQuery ()
558 query.HitsAddedEvent += OnHitsAdded;
559 query.HitsSubtractedEvent += OnHitsSubtracted;
560 query.FinishedEvent += OnFinished;
563 private void DetachQuery ()
565 if (query != null) {
566 query.HitsAddedEvent -= OnHitsAdded;
567 query.HitsSubtractedEvent -= OnHitsSubtracted;
568 query.FinishedEvent -= OnFinished;
569 query.Close ();
571 query = null;
575 private void StartQuery ()
577 try {
578 query.SendAsync ();
579 SetBusy (true);
580 } catch (Beagle.ResponseMessageException e) {
581 QueueDelayedQuery (entry.Text);
583 /* To translators: {0} represents the current query keywords */
584 root.Error (String.Format (Catalog.GetString ("The query for <i>{0}</i> failed." +
585 "<br>The likely cause is that the beagle daemon isn't running."), entry.Text));
586 root.OfferDaemonRestart = true;
587 } catch (Exception e) {
588 /* To translators: {0} represents the current query keywords, {1} contains the errormessage */
589 root.Error (String.Format (Catalog.GetString ("The query for <i>{0}</i> failed with error:<br>{1}<br>"),
590 entry.Text, e));
594 private void Search (String searchString)
596 entry.Text = searchString;
597 StoreSearch (searchString);
599 if (query != null) {
600 try { DetachQuery (); } catch (ObjectDisposedException e) {}
603 query = new Query ();
604 query.AddDomain (QueryDomain.Neighborhood);
606 // FIXME: Disable non-local searching for now.
607 //query.AddDomain (QueryDomain.Global);
609 query.AddText (searchString);
610 root.SetSource (hit_type);
612 AttachQuery ();
614 root.Query = query;
615 root.Start ();
617 StartQuery ();
619 UpdatePage ();
622 private void ClearSearch (object o, EventArgs args)
624 root.Clear ();
625 UpdatePage ();
626 entry.Text = "";
627 // clear search is also "stop current search" - implicitly
628 DetachQuery ();
631 private void StoreSearch (string query)
633 Gtk.TreeIter iter;
635 if (history.GetIterFirst (out iter)) {
636 string val;
638 do {
639 val = (string) history.GetValue (iter, 0);
641 if (val == query)
642 history.Remove (ref iter);
643 } while (val != query && history.IterNext (ref iter));
646 iter = history.Insert (0);
647 history.SetValue (iter, 0, query);
650 public ArrayList RetriveSearches ()
652 ArrayList searches = new ArrayList ();
654 int i = 0;
655 foreach (object[] o in history) {
656 searches.Add (o[0]);
657 i++;
659 if (i == 10)
660 break;
663 return searches;
666 public void ClearHistory ()
668 history.Clear ();
671 public void QuickSearch (string query)
673 Search (query);