4 // Copyright (c) 2006 Novell, Inc.
8 using System
.Collections
;
20 public class MainWindow
: Window
{
22 private Gtk
.Button button
;
23 private Gtk
.Tooltips tips
;
24 private Gtk
.Notebook pages
;
25 private Gtk
.Statusbar statusbar
;
27 private Search
.UIManager uim
;
28 private Search
.NotificationArea notification_area
;
29 private Search
.GroupView view
;
30 private Search
.Entry entry
;
31 private Search
.Spinner spinner
;
32 private Search
.Panes panes
;
33 private Search
.Tray
.TrayIcon tray
;
35 private Search
.Pages
.QuickTips quicktips
;
36 private Search
.Pages
.RootUser rootuser
;
37 private Search
.Pages
.StartDaemon startdaemon
;
38 private Search
.Pages
.NoMatch nomatch
;
42 private string query_text
;
43 private Beagle
.Query current_query
;
44 private Search
.ScopeType scope
= ScopeType
.Everything
;
45 private Search
.SortType sort
= SortType
.Modified
;
46 private Search
.TypeFilter filter
= null;
47 private bool show_details
= true;
48 private int total_matches
= -1;
50 private XKeybinder keybinder
= new XKeybinder ();
52 public static bool IconEnabled
= false;
54 public static void Main (string [] args
)
56 SystemInformation
.SetProcessName ("beagle-search");
58 Catalog
.Init ("beagle", ExternalStringsHack
.LocaleDir
);
60 string query
= ParseArgs (args
);
62 Gnome
.Program program
= new Gnome
.Program ("search", "0.0",
63 Gnome
.Modules
.UI
, args
);
65 MainWindow window
= new MainWindow ();
67 if (query
!= null && query
!= "" && !IconEnabled
) {
68 window
.entry
.Text
= query
;
75 private static string ParseArgs (String
[] args
)
80 while (i
< args
.Length
) {
92 // FIXME: This option is deprecated and will be removed in a future release.
95 // Ignore session management
96 case "--sm-config-prefix":
97 case "--sm-client-id":
99 // These all take an argument, so
105 if (args
[i
].Length
< 2 || args
[i
].Substring (0, 2) != "--") {
106 if (query
.Length
!= 0)
119 public static void PrintUsageAndExit ()
122 "beagle-search: GUI interface to the Beagle search system.\n" +
123 "Web page: http://www.beagle-project.org/\n" +
124 "Copyright (C) 2005-2006 Novell, Inc.\n\n";
127 "Usage: beagle-search [OPTIONS] [<query string>]\n\n" +
129 " --help\t\t\tPrint this usage message.\n" +
130 " --icon\t\t\tAdd an icon to the notification area rather than opening a search window.\n";
132 Console
.WriteLine (usage
);
133 System
.Environment
.Exit (0);
136 public MainWindow () : base (WindowType
.Toplevel
)
138 Title
= Catalog
.GetString ("Desktop Search");
139 Icon
= Beagle
.Images
.GetPixbuf ("system-search.png");
143 DeleteEvent
+= OnWindowDelete
;
145 VBox vbox
= new VBox ();
148 uim
= new UIManager (this);
149 uim
.ScopeChanged
+= OnScopeChanged
;
150 uim
.SortChanged
+= OnSortChanged
;
151 uim
.ToggleDetails
+= OnToggleDetails
;
152 uim
.ShowQuickTips
+= OnShowQuickTips
;
153 vbox
.PackStart (uim
.MenuBar
, false, false, 0);
155 HBox hbox
= new HBox (false, 6);
157 Label label
= new Label (Catalog
.GetString ("_Find:"));
158 hbox
.PackStart (label
, false, false, 0);
160 entry
= new Entry ();
161 entry
.Activated
+= OnEntryActivated
;
162 hbox
.PackStart (entry
, true, true, 0);
164 label
.MnemonicWidget
= entry
;
165 uim
.FocusSearchEntry
+= delegate () { entry.GrabFocus (); }
;
167 // The auto search after timeout feauture is now optional
168 // and can be disabled.
169 if (Beagle
.Util
.Conf
.Searching
.BeagleSearchAutoSearch
) {
170 entry
.Changed
+= OnEntryChanged
;
171 entry
.MoveCursor
+= OnEntryMoveCursor
;
174 button
= new Gtk
.Button ();
175 Gtk
.HBox button_hbox
= new Gtk
.HBox (false, 2);
176 Gtk
.Image icon
= new Gtk
.Image (Gtk
.Stock
.Find
, Gtk
.IconSize
.Button
);
177 button_hbox
.PackStart (icon
, false, false, 0);
178 label
= new Gtk
.Label (Catalog
.GetString ("Find Now"));
179 button_hbox
.PackStart (label
, false, false, 0);
180 button
.Add (button_hbox
);
181 button
.Clicked
+= OnButtonClicked
;
183 Gtk
.VBox buttonVBox
= new Gtk
.VBox (false, 0);
184 buttonVBox
.PackStart (button
, true, false, 0);
185 hbox
.PackStart (buttonVBox
, false, false, 0);
187 spinner
= new Spinner ();
188 hbox
.PackStart (spinner
, false, false, 0);
190 HBox padding_hbox
= new HBox ();
191 padding_hbox
.PackStart (hbox
, true, true, 9);
192 vbox
.PackStart (padding_hbox
, false, true, 6);
194 VBox view_box
= new VBox (false, 3);
195 vbox
.PackStart (view_box
, true, true, 0);
197 HBox na_padding
= new HBox ();
198 view_box
.PackStart (na_padding
, false, true, 0);
200 notification_area
= new NotificationArea ();
201 na_padding
.PackStart (notification_area
, true, true, 3);
203 pages
= new Gtk
.Notebook ();
204 pages
.ShowTabs
= false;
205 pages
.ShowBorder
= false;
206 pages
.BorderWidth
= 3;
207 view_box
.PackStart (pages
, true, true, 0);
209 quicktips
= new Pages
.QuickTips ();
211 pages
.Add (quicktips
);
213 rootuser
= new Pages
.RootUser ();
215 pages
.Add (rootuser
);
217 startdaemon
= new Pages
.StartDaemon ();
218 startdaemon
.DaemonStarted
+= OnDaemonStarted
;
220 pages
.Add (startdaemon
);
222 panes
= new Search
.Panes ();
226 view
= new GroupView ();
227 view
.TileSelected
+= ShowInformation
;
228 view
.CategoryToggled
+= OnCategoryToggled
;
229 panes
.MainContents
= view
;
231 this.statusbar
= new Gtk
.Statusbar ();
232 vbox
.PackEnd (this.statusbar
, false, false, 0);
236 tips
= new Gtk
.Tooltips ();
237 tips
.SetTip (entry
, Catalog
.GetString ("Type in search terms"), "");
238 tips
.SetTip (button
, Catalog
.GetString ("Start searching"), "");
241 if (Environment
.UserName
== "root" && ! Conf
.Daemon
.AllowRoot
) {
242 pages
.CurrentPage
= pages
.PageNum (rootuser
);
243 entry
.Sensitive
= button
.Sensitive
= uim
.Sensitive
= false;
245 pages
.CurrentPage
= pages
.PageNum (quicktips
);
249 tray
= new Search
.Tray
.TrayIcon ();
250 tray
.Clicked
+= OnTrayActivated
;
251 tray
.Search
+= OnTraySearch
;
253 // Attach the hide/show keybinding
254 keybinder
.Bind (Conf
.Searching
.ShowSearchWindowBinding
.ToString (), OnTrayActivated
);
259 StartCheckingIndexingStatus ();
262 private void SetWindowTitle (string query
)
264 Title
= String
.Format ( Catalog
.GetString ("Desktop Search: {0}"), query
);
267 private int TotalMatches
{
268 get { return this.total_matches; }
270 if (this.total_matches
!= -1)
271 this.statusbar
.Pop (0);
273 this.total_matches
= value;
275 if (this.total_matches
> -1) {
277 int tile_count
= view
.TileCount
;
279 if (tile_count
== this.total_matches
)
280 message
= String
.Format (Catalog
.GetString ("Showing all {0} matches"), this.total_matches
);
282 message
= String
.Format (Catalog
.GetString ("Showing the top {0} of {1} total matches"), view
.TileCount
, this.total_matches
);
284 this.statusbar
.Push (0, message
);
289 // Whether we should grab focus from the text entry
290 private bool grab_focus
;
292 private void Search (bool grab_focus
)
295 GLib
.Source
.Remove (timeout
);
299 string query
= query_text
= entry
.Text
;
300 if (query
== null || query
== "")
303 SetWindowTitle (query
);
304 ShowInformation (null);
307 tray
.AddSearch (query
);
310 filter
= TypeFilter
.MakeFilter (ref query
);
315 pages
.CurrentPage
= pages
.PageNum (panes
);
317 this.grab_focus
= grab_focus
;
320 if (current_query
!= null) {
322 current_query
.HitsAddedEvent
-= OnHitsAdded
;
323 current_query
.HitsSubtractedEvent
-= OnHitsSubtracted
;
324 current_query
.Close ();
329 current_query
= new Query ();
330 current_query
.AddDomain (QueryDomain
.Neighborhood
);
332 // Don't search documentation by default
333 QueryPart_Property part
= new QueryPart_Property ();
334 part
.Logic
= QueryPartLogic
.Prohibited
;
335 part
.Type
= PropertyType
.Keyword
;
336 part
.Key
= "beagle:Source";
337 part
.Value
= "documentation";
338 current_query
.AddPart (part
);
340 current_query
.AddText (query
);
341 current_query
.HitsAddedEvent
+= OnHitsAdded
;
342 current_query
.HitsSubtractedEvent
+= OnHitsSubtracted
;
343 current_query
.FinishedEvent
+= OnFinished
;
345 current_query
.SendAsync ();
347 } catch (Beagle
.ResponseMessageException
) {
348 pages
.CurrentPage
= pages
.PageNum (startdaemon
);
349 } catch (Exception e
) {
350 Console
.WriteLine ("Querying the Beagle daemon failed: {0}", e
.Message
);
354 private void OnEntryActivated (object obj
, EventArgs args
)
359 private void OnDaemonStarted ()
364 private void OnEntryChanged (object obj
, EventArgs args
)
367 GLib
.Source
.Remove (timeout
);
368 timeout
= GLib
.Timeout
.Add (1000, OnEntryTimeout
);
371 private void OnEntryMoveCursor (object obj
, EventArgs args
)
374 GLib
.Source
.Remove (timeout
);
375 timeout
= GLib
.Timeout
.Add (1000, OnEntryTimeout
);
378 private bool OnEntryTimeout ()
385 private void OnButtonClicked (object obj
, EventArgs args
)
390 private void OnWindowDelete (object o
, Gtk
.DeleteEventArgs args
)
396 Gtk
.Application
.Quit ();
400 private void OnScopeChanged (Search
.ScopeType toggled
, bool active
)
403 view
.Scope
= scope
= scope
| toggled
;
405 view
.Scope
= scope
= scope ^ toggled
;
410 private void OnCategoryToggled (ScopeType toggled
)
412 string name
= ScopeType
.GetName (typeof (ScopeType
), toggled
);
414 ToggleAction act
= (ToggleAction
) uim
.GetAction ("/ui/MenuBar/Search/Scope/" + name
);
415 act
.Active
= ! act
.Active
;
417 catch (Exception ex
) {
418 Console
.WriteLine("Exception caught when trying to deactivate menu entry {0}:",name
);
419 Console
.WriteLine(ex
);
425 private void OnSortChanged (Search
.SortType newSort
)
427 view
.Sort
= sort
= newSort
;
430 private void OnToggleDetails (bool active
)
432 show_details
= active
;
433 if (panes
.Details
!= null)
434 panes
.ToggleDetails (show_details
);
436 panes
.ToggleDetails (false);
439 private void OnShowQuickTips ()
441 if (current_query
!= null) {
443 current_query
.HitsAddedEvent
-= OnHitsAdded
;
444 current_query
.HitsSubtractedEvent
-= OnHitsSubtracted
;
445 current_query
.Close ();
446 current_query
= null;
449 pages
.CurrentPage
= pages
.PageNum (quicktips
);
452 private void ShowInformation (Tiles
.Tile tile
)
455 panes
.Details
= tile
.Details
;
456 if (tile
.Details
!= null)
457 panes
.ToggleDetails (show_details
);
459 panes
.ToggleDetails (false);
461 panes
.Details
= null;
462 panes
.ToggleDetails (false);
466 private void OnFinished (FinishedResponse response
)
469 view
.Finished (grab_focus
);
475 private void OnHitsAdded (HitsAddedResponse response
)
477 foreach (Hit hit
in response
.Hits
) {
478 Tile tile
= TileActivatorOrg
.MakeTile (hit
, current_query
);
482 if (filter
!= null && !filter
.Filter (tile
))
486 if (pages
.CurrentPageWidget
!= panes
)
487 pages
.CurrentPage
= pages
.PageNum (panes
);
490 TotalMatches
+= response
.NumMatches
;
493 private void OnHitsSubtracted (HitsSubtractedResponse response
)
495 foreach (Uri uri
in response
.Uris
)
496 view
.SubtractHit (uri
);
498 TotalMatches
-= response
.Uris
.Count
;
503 private void CheckNoMatch ()
505 MatchType matches
= view
.MatchState
;
506 if (matches
== MatchType
.Matched
) {
507 pages
.CurrentPage
= pages
.PageNum (panes
);
513 nomatch
= new Pages
.NoMatch (query_text
, matches
== MatchType
.NoneInScope
);
516 pages
.CurrentPage
= pages
.PageNum (nomatch
);
519 /////////////////////////////////////
521 private void OnTrayActivated (object o
, EventArgs args
)
532 private void OnTraySearch (string query
)
541 //////////////////////////////////////
543 private void StartCheckingIndexingStatus ()
545 InformationalMessagesRequest msg_request
= new InformationalMessagesRequest ();
546 msg_request
.IndexingStatusEvent
+= OnIndexingStatusEvent
;
547 msg_request
.SendAsync ();
550 private void OnIndexingStatusEvent (IndexingStatus status
)
552 if (status
== IndexingStatus
.Running
) {
553 NotificationMessage m
= new NotificationMessage ();
554 m
.Icon
= Gtk
.Stock
.DialogInfo
;
555 m
.Title
= Catalog
.GetString ("Your data is being indexed");
556 m
.Message
= Catalog
.GetString ("The search service is in the process of indexing your data. Search results may be incomplete until indexing has finished.");
557 notification_area
.Display (m
);
559 notification_area
.Hide ();