Oops, fix a scale problem with the RSS size calculation
[beagle.git] / search / Search.cs
blobcbfcdafc90d8aab7a96ab5fbe91eca0949214672
1 //
2 // Search.cs
3 //
4 // Copyright (c) 2006 Novell, Inc.
5 //
7 using System;
8 using System.Collections;
10 using Gtk;
11 using Beagle;
12 using Beagle.Util;
13 using Mono.Unix;
15 using Search.Tiles;
16 using Search.Tray;
18 namespace Search {
20 public class MainWindow : Window {
22 private Gtk.Button button;
23 private Gtk.Tooltips tips;
24 private Gtk.Notebook pages;
26 private Search.UIManager uim;
27 private Search.NotificationArea notification_area;
28 private Search.GroupView view;
29 private Search.Entry entry;
30 private Search.Spinner spinner;
31 private Search.Panes panes;
32 private Search.Tray.TrayIcon tray;
34 private Search.Pages.QuickTips quicktips;
35 private Search.Pages.RootUser rootuser;
36 private Search.Pages.StartDaemon startdaemon;
37 private Search.Pages.NoMatch nomatch;
39 private uint timeout;
41 private string query_text;
42 private Beagle.Query current_query;
43 private Search.ScopeType scope = ScopeType.Everything;
44 private Search.SortType sort = SortType.Modified;
45 private Search.TypeFilter filter = null;
46 private bool show_details = true;
48 private XKeybinder keybinder = new XKeybinder ();
50 public static bool IconEnabled = false;
52 public static void Main (string [] args)
54 SystemInformation.SetProcessName ("beagle-search");
56 Catalog.Init ("beagle", ExternalStringsHack.LocaleDir);
58 string query = ParseArgs (args);
60 Gnome.Program program = new Gnome.Program ("search", "0.0",
61 Gnome.Modules.UI, args);
63 MainWindow window = new MainWindow ();
65 if (query != null && query != "" && !IconEnabled) {
66 window.entry.Text = query;
67 window.Search (true);
70 program.Run ();
73 private static string ParseArgs (String[] args)
75 string query = "";
76 int i = 0;
78 while (i < args.Length) {
79 switch (args [i]) {
80 case "--help":
81 case "--usage":
82 PrintUsageAndExit ();
83 return null;
85 case "--icon":
86 IconEnabled = true;
87 break;
89 case "--autostarted":
90 if (! Conf.Searching.Autostart) {
91 Console.WriteLine ("beagle-search: Autostarting is disabled, not starting");
92 Environment.Exit (0);
94 break;
96 // Ignore session management
97 case "--sm-config-prefix":
98 case "--sm-client-id":
99 case "--screen":
100 // These all take an argument, so
101 // increment i
102 i++;
103 break;
105 default:
106 if (args [i].Length < 2 || args [i].Substring (0, 2) != "--") {
107 if (query.Length != 0)
108 query += " ";
109 query += args [i];
111 break;
114 i++;
117 return query;
120 public static void PrintUsageAndExit ()
122 string usage =
123 "beagle-search: GUI interface to the Beagle search system.\n" +
124 "Web page: http://www.beagle-project.org/\n" +
125 "Copyright (C) 2005-2006 Novell, Inc.\n\n";
127 usage +=
128 "Usage: beagle-search [OPTIONS] [<query string>]\n\n" +
129 "Options:\n" +
130 " --help\t\t\tPrint this usage message.\n" +
131 " --icon\t\t\tAdd an icon to the notification area rather than opening a search window.\n";
133 Console.WriteLine (usage);
134 System.Environment.Exit (0);
137 public MainWindow () : base (WindowType.Toplevel)
139 Title = Catalog.GetString ("Desktop Search");
140 Icon = Beagle.Images.GetPixbuf ("system-search.png");
142 DefaultWidth = 700;
143 DefaultHeight = 550;
144 DeleteEvent += OnWindowDelete;
146 VBox vbox = new VBox ();
147 vbox.Spacing = 3;
149 uim = new UIManager (this);
150 uim.ScopeChanged += OnScopeChanged;
151 uim.SortChanged += OnSortChanged;
152 uim.ToggleDetails += OnToggleDetails;
153 uim.ShowQuickTips += OnShowQuickTips;
154 vbox.PackStart (uim.MenuBar, false, false, 0);
156 HBox hbox = new HBox (false, 6);
158 Label label = new Label (Catalog.GetString ("_Find:"));
159 hbox.PackStart (label, false, false, 0);
161 entry = new Entry ();
162 entry.Activated += OnEntryActivated;
163 hbox.PackStart (entry, true, true, 0);
165 label.MnemonicWidget = entry;
166 uim.FocusSearchEntry += delegate () { entry.GrabFocus (); };
168 // The auto search after timeout feauture is now optional
169 // and can be disabled.
170 if (Beagle.Util.Conf.Searching.BeagleSearchAutoSearch) {
171 entry.Changed += OnEntryChanged;
172 entry.MoveCursor += OnEntryMoveCursor;
175 button = new Gtk.Button ();
176 Gtk.HBox button_hbox = new Gtk.HBox (false, 2);
177 Gtk.Image icon = new Gtk.Image (Gtk.Stock.Find, Gtk.IconSize.Button);
178 button_hbox.PackStart (icon, false, false, 0);
179 label = new Gtk.Label (Catalog.GetString ("Find Now"));
180 button_hbox.PackStart (label, false, false, 0);
181 button.Add (button_hbox);
182 button.Clicked += OnButtonClicked;
184 Gtk.VBox buttonVBox = new Gtk.VBox (false, 0);
185 buttonVBox.PackStart (button, true, false, 0);
186 hbox.PackStart (buttonVBox, false, false, 0);
188 spinner = new Spinner ();
189 hbox.PackStart (spinner, false, false, 0);
191 HBox padding_hbox = new HBox ();
192 padding_hbox.PackStart (hbox, true, true, 9);
193 vbox.PackStart (padding_hbox, false, true, 6);
195 VBox view_box = new VBox (false, 3);
196 vbox.PackStart (view_box, true, true, 0);
198 HBox na_padding = new HBox ();
199 view_box.PackStart (na_padding, false, true, 0);
201 notification_area = new NotificationArea ();
202 na_padding.PackStart (notification_area, true, true, 3);
204 pages = new Gtk.Notebook ();
205 pages.ShowTabs = false;
206 pages.ShowBorder = false;
207 pages.BorderWidth = 3;
208 view_box.PackStart (pages, true, true, 0);
210 quicktips = new Pages.QuickTips ();
211 quicktips.Show ();
212 pages.Add (quicktips);
214 rootuser = new Pages.RootUser ();
215 rootuser.Show ();
216 pages.Add (rootuser);
218 startdaemon = new Pages.StartDaemon ();
219 startdaemon.DaemonStarted += OnDaemonStarted;
220 startdaemon.Show ();
221 pages.Add (startdaemon);
223 panes = new Search.Panes ();
224 panes.Show ();
225 pages.Add (panes);
227 view = new GroupView ();
228 view.TileSelected += ShowInformation;
229 view.CategoryToggled += OnCategoryToggled;
230 panes.MainContents = view;
232 Add (vbox);
234 tips = new Gtk.Tooltips ();
235 tips.SetTip (entry, Catalog.GetString ("Type in search terms"), "");
236 tips.SetTip (button, Catalog.GetString ("Start searching"), "");
237 tips.Enable ();
239 if (Environment.UserName == "root" && ! Conf.Daemon.AllowRoot) {
240 pages.CurrentPage = pages.PageNum (rootuser);
241 entry.Sensitive = button.Sensitive = uim.Sensitive = false;
242 } else {
243 pages.CurrentPage = pages.PageNum (quicktips);
246 if (IconEnabled) {
247 tray = new Search.Tray.TrayIcon ();
248 tray.Clicked += OnTrayActivated;
249 tray.Search += OnTraySearch;
251 // Attach the hide/show keybinding
252 keybinder.Bind (Conf.Searching.ShowSearchWindowBinding.ToString (), OnTrayActivated);
253 } else {
254 ShowAll ();
257 StartCheckingIndexingStatus ();
260 private void SetWindowTitle (string query)
262 Title = String.Format ( Catalog.GetString ("Desktop Search: {0}"), query);
265 // Whether we should grab focus from the text entry
266 private bool grab_focus;
268 private void Search (bool grab_focus)
270 if (timeout != 0) {
271 GLib.Source.Remove (timeout);
272 timeout = 0;
275 string query = query_text = entry.Text;
276 if (query == null || query == "")
277 return;
279 SetWindowTitle (query);
280 ShowInformation (null);
282 if (tray != null) {
283 tray.AddSearch (query);
286 filter = TypeFilter.MakeFilter (ref query);
288 view.Clear ();
289 view.Scope = scope;
290 view.Sort = sort;
291 pages.CurrentPage = pages.PageNum (panes);
293 this.grab_focus = grab_focus;
295 try {
296 if (current_query != null) {
297 current_query.HitsAddedEvent -= OnHitsAdded;
298 current_query.HitsSubtractedEvent -= OnHitsSubtracted;
299 current_query.Close ();
302 current_query = new Query ();
303 current_query.AddDomain (QueryDomain.Neighborhood);
305 // Don't search documentation by default
306 QueryPart_Property part = new QueryPart_Property ();
307 part.Logic = QueryPartLogic.Prohibited;
308 part.Type = PropertyType.Keyword;
309 part.Key = "beagle:Source";
310 part.Value = "documentation";
311 current_query.AddPart (part);
313 current_query.AddText (query);
314 current_query.HitsAddedEvent += OnHitsAdded;
315 current_query.HitsSubtractedEvent += OnHitsSubtracted;
316 current_query.FinishedEvent += OnFinished;
318 current_query.SendAsync ();
319 spinner.Start ();
320 } catch (Beagle.ResponseMessageException) {
321 pages.CurrentPage = pages.PageNum (startdaemon);
322 } catch (Exception e) {
323 Console.WriteLine ("Querying the Beagle daemon failed: {0}", e.Message);
327 private void OnEntryActivated (object obj, EventArgs args)
329 Search (true);
332 private void OnDaemonStarted ()
334 Search (true);
337 private void OnEntryChanged (object obj, EventArgs args)
339 if (timeout != 0)
340 GLib.Source.Remove (timeout);
341 timeout = GLib.Timeout.Add (1000, OnEntryTimeout);
344 private void OnEntryMoveCursor (object obj, EventArgs args)
346 if (timeout != 0)
347 GLib.Source.Remove (timeout);
348 timeout = GLib.Timeout.Add (1000, OnEntryTimeout);
351 private bool OnEntryTimeout ()
353 timeout = 0;
354 Search (false);
355 return false;
358 private void OnButtonClicked (object obj, EventArgs args)
360 Search (true);
363 private void OnWindowDelete (object o, Gtk.DeleteEventArgs args)
365 if (IconEnabled) {
366 Hide ();
367 args.RetVal = true;
368 } else {
369 Gtk.Application.Quit ();
373 private void OnScopeChanged (Search.ScopeType toggled, bool active)
375 if (active)
376 view.Scope = scope = scope | toggled;
377 else
378 view.Scope = scope = scope ^ toggled;
380 CheckNoMatch ();
383 private void OnCategoryToggled (ScopeType toggled)
385 string name = ScopeType.GetName (typeof (ScopeType), toggled);
386 try {
387 ToggleAction act = (ToggleAction) uim.GetAction ("/ui/MenuBar/Search/Scope/" + name);
388 act.Active = ! act.Active;
390 catch (Exception ex) {
391 Console.WriteLine("Exception caught when trying to deactivate menu entry {0}:",name);
392 Console.WriteLine(ex);
393 return;
398 private void OnSortChanged (Search.SortType newSort)
400 view.Sort = sort = newSort;
403 private void OnToggleDetails (bool active)
405 show_details = active;
406 if (panes.Details != null)
407 panes.ToggleDetails (show_details);
408 else
409 panes.ToggleDetails (false);
412 private void OnShowQuickTips ()
414 if (current_query != null) {
415 current_query.HitsAddedEvent -= OnHitsAdded;
416 current_query.HitsSubtractedEvent -= OnHitsSubtracted;
417 current_query.Close ();
418 current_query = null;
421 pages.CurrentPage = pages.PageNum (quicktips);
424 private void ShowInformation (Tiles.Tile tile)
426 if (tile != null) {
427 panes.Details = tile.Details;
428 if (tile.Details != null)
429 panes.ToggleDetails (show_details);
430 else
431 panes.ToggleDetails (false);
432 } else {
433 panes.Details = null;
434 panes.ToggleDetails (false);
438 private void OnFinished (FinishedResponse response)
440 spinner.Stop ();
441 view.Finished (grab_focus);
442 grab_focus = false;
444 CheckNoMatch ();
447 private void OnHitsAdded (HitsAddedResponse response)
449 foreach (Hit hit in response.Hits) {
450 Tile tile = TileActivatorOrg.MakeTile (hit, current_query);
451 if (tile == null)
452 continue;
454 if (filter != null && !filter.Filter (tile))
455 continue;
457 view.AddHit (tile);
458 if (pages.CurrentPageWidget != panes)
459 pages.CurrentPage = pages.PageNum (panes);
463 private void OnHitsSubtracted (HitsSubtractedResponse response)
465 foreach (Uri uri in response.Uris)
466 view.SubtractHit (uri);
468 CheckNoMatch ();
471 private void CheckNoMatch ()
473 MatchType matches = view.MatchState;
474 if (matches == MatchType.Matched) {
475 pages.CurrentPage = pages.PageNum (panes);
476 return;
479 if (nomatch != null)
480 nomatch.Destroy ();
481 nomatch = new Pages.NoMatch (query_text, matches == MatchType.NoneInScope);
482 nomatch.Show ();
483 pages.Add (nomatch);
484 pages.CurrentPage = pages.PageNum (nomatch);
487 /////////////////////////////////////
489 private void OnTrayActivated (object o, EventArgs args)
491 if (! Visible) {
492 base.ShowAll ();
493 base.Present ();
494 entry.GrabFocus ();
495 } else {
496 base.Hide ();
500 private void OnTraySearch (string query)
502 if (!Visible)
503 ShowAll ();
505 entry.Text = query;
506 Search (true);
509 //////////////////////////////////////
511 private void StartCheckingIndexingStatus ()
513 InformationalMessagesRequest msg_request = new InformationalMessagesRequest ();
514 msg_request.IndexingStatusEvent += OnIndexingStatusEvent;
515 msg_request.SendAsync ();
518 private void OnIndexingStatusEvent (IndexingStatus status)
520 if (status == IndexingStatus.Running) {
521 NotificationMessage m = new NotificationMessage ();
522 m.Icon = Gtk.Stock.DialogInfo;
523 m.Title = Catalog.GetString ("Beagle is indexing your data");
524 m.Message = Catalog.GetString ("The Beagle service is in the process of indexing your data. Search results may be incomplete until indexing has finished.");
525 notification_area.Display (m);
526 } else {
527 notification_area.Hide ();