using System; using System.Collections; using Gtk; using Beagle; using Beagle.Util; using Mono.Unix; using Search.Tiles; using Search.Tray; namespace Search { public class MainWindow : Window { Search.GroupView view; Search.Entry entry; Gtk.Button button; Search.Spinner spinner; Gtk.Tooltips tips; Gtk.Notebook pages; Search.Pages.QuickTips quicktips; Search.Pages.RootUser rootuser; Search.Pages.StartDaemon startdaemon; Search.Pages.NoMatch nomatch; Search.Panes panes; Search.Tray.TrayIcon tray; Search.MessageArea message_area; uint timeout; string queryText; Beagle.Query currentQuery; Search.ScopeType scope = ScopeType.Everything; Search.SortType sort = SortType.Modified; Search.TypeFilter filter = null; XKeybinder keybinder = new XKeybinder (); public static bool IconEnabled = false; public static void Main (string [] args) { SystemInformation.SetProcessName ("beagle-search"); Catalog.Init ("beagle", ExternalStringsHack.LocaleDir); string query = ParseArgs (args); Gnome.Program program = new Gnome.Program ("search", "0.0", Gnome.Modules.UI, args); MainWindow window = new MainWindow (); if (query != null && query != "" && !IconEnabled) { window.entry.Text = query; window.Search (true); } program.Run (); } private static string ParseArgs (String[] args) { string query = ""; int i = 0; while (i < args.Length) { switch (args [i]) { case "--help": case "--usage": PrintUsageAndExit (); return null; case "--icon": IconEnabled = true; break; case "--autostarted": if (! Conf.Searching.Autostart) { Console.WriteLine ("beagle-search: Autostarting is disabled, not starting"); Environment.Exit (0); } break; // Ignore session management case "--sm-config-prefix": case "--sm-client-id": case "--screen": // These all take an argument, so // increment i i++; break; default: if (args [i].Length < 2 || args [i].Substring (0, 2) != "--") { if (query.Length != 0) query += " "; query += args [i]; } break; } i++; } return query; } public static void PrintUsageAndExit () { string usage = "beagle-search: GUI interface to the Beagle search system.\n" + "Web page: http://www.beagle-project.org/\n" + "Copyright (C) 2005-2006 Novell, Inc.\n\n"; usage += "Usage: beagle-search [OPTIONS] []\n\n" + "Options:\n" + " --help\t\t\tPrint this usage message.\n" + " --icon\t\t\tAdd an icon to the notification area rather than opening a search window.\n"; Console.WriteLine (usage); System.Environment.Exit (0); } public MainWindow () : base (WindowType.Toplevel) { Title = "Desktop Search"; Icon = Beagle.Images.GetPixbuf ("system-search.png"); BorderWidth = 3; DefaultWidth = 700; DefaultHeight = 550; DeleteEvent += OnWindowDelete; VBox vbox = new VBox (); vbox.Spacing = 3; UIManager uim = new UIManager (this); uim.ScopeChanged += OnScopeChanged; uim.SortChanged += OnSortChanged; uim.ShowQuickTips += OnShowQuickTips; vbox.PackStart (uim.MenuBar, false, false, 0); HBox padding_hbox = new HBox (); HBox hbox = new HBox (false, 6); Label label = new Label (Catalog.GetString ("_Find:")); hbox.PackStart (label, false, false, 0); entry = new Entry (); label.MnemonicWidget = entry; uim.FocusSearchEntry += delegate () { entry.GrabFocus (); }; entry.Activated += OnEntryActivated; entry.Changed += OnEntryChanged; hbox.PackStart (entry, true, true, 0); button = new Gtk.Button (); Gtk.HBox button_hbox = new Gtk.HBox (false, 2); Gtk.Image icon = new Gtk.Image (Gtk.Stock.Find, Gtk.IconSize.Button); button_hbox.PackStart (icon, false, false, 0); label = new Gtk.Label (Catalog.GetString ("Find Now")); button_hbox.PackStart (label, false, false, 0); button.Add (button_hbox); button.Clicked += OnButtonClicked; Gtk.VBox buttonVBox = new Gtk.VBox (false, 0); buttonVBox.PackStart (button, true, false, 0); hbox.PackStart (buttonVBox, false, false, 0); spinner = new Spinner (); hbox.PackStart (spinner, false, false, 0); padding_hbox.PackStart (hbox, true, true, 9); vbox.PackStart (padding_hbox, false, true, 6); VBox page_box = new VBox (); page_box.BorderWidth = 0; page_box.Spacing = 1; vbox.PackStart (page_box, true, true, 0); message_area = new MessageArea (); page_box.PackStart (message_area, false, false, 0); pages = new Gtk.Notebook (); pages.ShowTabs = false; pages.ShowBorder = false; page_box.PackStart (pages, true, true, 0); quicktips = new Pages.QuickTips (); quicktips.Show (); pages.Add (quicktips); rootuser = new Pages.RootUser (); rootuser.Show (); pages.Add (rootuser); startdaemon = new Pages.StartDaemon (); startdaemon.DaemonStarted += OnDaemonStarted; startdaemon.Show (); pages.Add (startdaemon); panes = new Search.Panes (); panes.Show (); pages.Add (panes); view = new GroupView (); view.TileSelected += ShowInformation; panes.MainContents = view; Add (vbox); tips = new Gtk.Tooltips (); tips.SetTip (entry, Catalog.GetString ("Type in search terms"), ""); tips.SetTip (button, Catalog.GetString ("Start searching"), ""); tips.Enable (); if (Environment.UserName == "root" && ! Conf.Daemon.AllowRoot) { pages.CurrentPage = pages.PageNum (rootuser); entry.Sensitive = button.Sensitive = uim.Sensitive = false; } else { pages.CurrentPage = pages.PageNum (quicktips); } if (IconEnabled) { tray = new Search.Tray.TrayIcon (); tray.Clicked += OnTrayActivated; tray.Search += OnTraySearch; // Attach the hide/show keybinding keybinder.Bind (Conf.Searching.ShowSearchWindowBinding.ToString (), OnTrayActivated); } else { ShowAll (); message_area.Hide (); } } Gtk.Widget oldFocus; private void SetWindowTitle (string query) { Title = String.Format ("Desktop Search: {0}", query); } private void Search (bool grabFocus) { if (timeout != 0) { GLib.Source.Remove (timeout); timeout = 0; } string query = queryText = entry.Text; if (query == null || query == "") return; SetWindowTitle (query); ShowInformation (null); if (tray != null) { tray.AddSearch (query); } filter = TypeFilter.MakeFilter (ref query); view.Clear (); view.Scope = scope; view.Sort = sort; pages.CurrentPage = pages.PageNum (panes); oldFocus = grabFocus ? Focus : null; try { if (currentQuery != null) { currentQuery.HitsAddedEvent -= OnHitsAdded; currentQuery.HitsSubtractedEvent -= OnHitsSubtracted; #if ENABLE_NETWORKING currentQuery.FoundUnknownHostEvent -= OnUnknownHostFound; #endif currentQuery.Close (); } currentQuery = new Query (); // FIXME: This should be local by default? Then we can // turn on Neighborhood on request. currentQuery.AddDomain (QueryDomain.Neighborhood); // Don't search documentation by default QueryPart_Property part = new QueryPart_Property (); part.Logic = QueryPartLogic.Prohibited; part.Type = PropertyType.Keyword; part.Key = "beagle:Source"; part.Value = "documentation"; currentQuery.AddPart (part); currentQuery.AddText (query); currentQuery.HitsAddedEvent += OnHitsAdded; currentQuery.HitsSubtractedEvent += OnHitsSubtracted; currentQuery.FinishedEvent += OnFinished; currentQuery.SendAsync (); spinner.Start (); #if ENABLE_NETWORKING currentQuery.FoundUnknownHostEvent += OnUnknownHostFound; #endif } catch (Beagle.ResponseMessageException e){ pages.CurrentPage = pages.PageNum (startdaemon); } catch (Exception e) { Console.WriteLine ("Querying the Beagle daemon failed: {0}", e.Message); } } private void OnEntryActivated (object obj, EventArgs args) { Search (true); } private void OnDaemonStarted () { Search (true); } private void OnEntryChanged (object obj, EventArgs args) { if (timeout != 0) GLib.Source.Remove (timeout); timeout = GLib.Timeout.Add (1000, OnEntryTimeout); } private bool OnEntryTimeout () { timeout = 0; Search (false); return false; } private void OnButtonClicked (object obj, EventArgs args) { Search (true); } private void OnWindowDelete (object o, Gtk.DeleteEventArgs args) { if (IconEnabled) { Hide (); args.RetVal = true; } else { Gtk.Application.Quit (); } } private void OnScopeChanged (Search.ScopeType newScope) { view.Scope = scope = newScope; CheckNoMatch (); } private void OnSortChanged (Search.SortType newSort) { view.Sort = sort = newSort; } private void OnShowQuickTips () { if (currentQuery != null) { currentQuery.HitsAddedEvent -= OnHitsAdded; currentQuery.HitsSubtractedEvent -= OnHitsSubtracted; #if ENABLE_NETWORKING currentQuery.FoundUnknownHostEvent -= OnUnknownHostFound; #endif currentQuery.Close (); currentQuery = null; } pages.CurrentPage = pages.PageNum (quicktips); } private void ShowInformation (Tiles.Tile tile) { if (tile != null) panes.Details = tile.Details; else panes.Details = null; } private void OnFinished (FinishedResponse response) { spinner.Stop (); view.Finished (oldFocus == Focus); CheckNoMatch (); } private void OnHitsAdded (HitsAddedResponse response) { foreach (Hit hit in response.Hits) { Tile tile = TileActivatorOrg.MakeTile (hit, currentQuery); if (tile == null) continue; if (filter != null && !filter.Filter (tile)) continue; view.AddHit (tile); if (pages.CurrentPageWidget != panes) pages.CurrentPage = pages.PageNum (panes); } } private void OnHitsSubtracted (HitsSubtractedResponse response) { foreach (Uri uri in response.Uris) view.SubtractHit (uri); CheckNoMatch (); } #if ENABLE_NETWORKING private void OnUnknownHostFound (object sender, MDnsEventArgs args) { Console.WriteLine ("New host found: {0}", args.Name); Gdk.Pixbuf pixbuf = Beagle.Images.GetPixbuf ("network-workgroup.png", 48, 48); string message = "There are computers near you running Beagle.\n" + "Did you want to search them securely over the network?"; string details = "You can then search other computers from the \"Search\" menu."; string button_label = "Show what's _nearby"; EventHandler button_cb = delegate (object sender, EventArgs args) { // Launch beagle-settings when this button is clicked // FIXME: This is VERY BUGGY! System.Diagnostics.Process p = new System.Diagnostics.Process (); p.StartInfo.UseShellExecute = false; p.StartInfo.FileName = "beagle-settings"; p.StartInfo.Arguments = "--network-tab"; try { p.Start (); } catch (Exception e) { Console.WriteLine ("Could not start beagle-settings: {0}", e); } }; message_area.Display (pixbuf, message, details, button_label, button_cb); } #endif private void CheckNoMatch () { MatchType matches = view.MatchState; if (matches == MatchType.Matched) { pages.CurrentPage = pages.PageNum (panes); return; } if (nomatch != null) nomatch.Destroy (); nomatch = new Pages.NoMatch (queryText, matches == MatchType.NoneInScope); nomatch.Show (); pages.Add (nomatch); pages.CurrentPage = pages.PageNum (nomatch); } ///////////////////////////////////// private void OnTrayActivated (object o, EventArgs args) { if (! Visible) { ShowAll (); entry.GrabFocus (); } else { base.Hide (); } } private void OnTraySearch (string query) { if (!Visible) ShowAll (); entry.Text = query; Search (true); } } }