// // Settings.cs // // Copyright (C) 2005 Novell, Inc. // // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // using System; using System.IO; using System.Collections; using System.Threading; using Gtk; using Gdk; using Glade; using Mono.Unix; using Beagle; using Beagle.Util; public class SettingsDialog { public static void Main (string[] args) { SettingsDialog settings = new SettingsDialog (args); settings.Run (); } //////////////////////////////////////////////////////////////// // Widgets [Widget] VBox administration_frame; [Widget] CheckButton allow_root_toggle; [Widget] CheckButton autostart_toggle; [Widget] CheckButton battery_toggle; [Widget] CheckButton press_ctrl_toggle; [Widget] CheckButton press_alt_toggle; [Widget] Entry show_search_window_entry; [Widget] SpinButton max_displayed_spinbutton; [Widget] CheckButton index_home_toggle; [Widget] Button remove_include_button; [Widget] Button remove_exclude_button; [Widget] Button display_up_button; [Widget] Button display_down_button; [Widget] Gtk.Window settings_dialog; [Widget] Gtk.Notebook notebook1; [Widget] ScrolledWindow display_sw; [Widget] ScrolledWindow include_sw; [Widget] ScrolledWindow exclude_sw; #if false DisplayView display_view; #endif IncludeView include_view; ExcludeView exclude_view; //////////////////////////////////////////////////////////////// // Zeroconf Networking [Widget] VBox networking_box; [Widget] VBox general_box; [Widget] Alignment password_box; [Widget] ScrolledWindow netbeagle_sw; [Widget] CheckButton allow_global_access_toggle; [Widget] CheckButton require_password_toggle; [Widget] Button add_netbeagle_button; [Widget] Button remove_netbeagle_button; [Widget] Entry index_name_entry; [Widget] Entry password_entry; private NetbeagleView netbeagle_view; //////////////////////////////////////////////////////////////// // Initialize public SettingsDialog (string [] args) { Application.Init (); Catalog.Init ("beagle", ExternalStringsHack.LocaleDir); Glade.XML glade = new Glade.XML (null, "settings.glade", "settings_dialog", "beagle"); glade.Autoconnect (this); administration_frame.Visible = (Environment.UserName == "root"); #if false display_view = new DisplayView (); display_view.Selection.Changed += new EventHandler (OnDisplaySelected); display_view.Show (); // The display sorting stuff is something i have been testing locally, Best CVS wont use it display_sw.Child = display_view; #endif include_view = new IncludeView (); include_view.Selection.Changed += new EventHandler (OnIncludeSelected); include_view.Show (); include_sw.Child = include_view; exclude_view = new ExcludeView (); exclude_view.Selection.Changed += new EventHandler (OnExcludeSelected); exclude_view.Show (); exclude_sw.Child = exclude_view; #if ENABLE_NETWORKING networking_box.Visible = true; netbeagle_view = new NetbeagleView (); netbeagle_view.Selection.Changed += new EventHandler (OnNetbeagleSelected); netbeagle_view.Show (); netbeagle_sw.Child = netbeagle_view; allow_global_access_toggle.Toggled += delegate (object sender, EventArgs args) { general_box.Sensitive = allow_global_access_toggle.Active; }; require_password_toggle.Toggled += delegate (object sender, EventArgs args) { password_box.Sensitive = require_password_toggle.Active; }; // parse arguments if (args.Length > 0) { foreach (string arg in args) { if (arg == "--network-tab") notebook1.CurrentPage = 3; } } #endif LoadConfiguration (); Conf.Subscribe (typeof (Conf.IndexingConfig), new Conf.ConfigUpdateHandler (OnConfigurationChanged)); Conf.Subscribe (typeof (Conf.SearchingConfig), new Conf.ConfigUpdateHandler (OnConfigurationChanged)); #if ENABLE_NETWORKING Conf.Subscribe (typeof (Conf.NetworkingConfig), new Conf.ConfigUpdateHandler (OnConfigurationChanged)); #endif } public void Run () { Application.Run (); } //////////////////////////////////////////////////////////////// // Configuration private void LoadConfiguration () { allow_root_toggle.Active = Conf.Daemon.AllowRoot; autostart_toggle.Active = Conf.Searching.Autostart; battery_toggle.Active = Conf.Indexing.IndexOnBattery; KeyBinding show_binding = Conf.Searching.ShowSearchWindowBinding; press_ctrl_toggle.Active = show_binding.Ctrl; press_alt_toggle.Active = show_binding.Alt; show_search_window_entry.Text = show_binding.Key; max_displayed_spinbutton.Value = (uint) Conf.Searching.MaxDisplayed; if (Conf.Indexing.IndexHomeDir) index_home_toggle.Active = true; foreach (string include in Conf.Indexing.Roots) include_view.AddPath (include); foreach (ExcludeItem exclude_item in Conf.Indexing.Excludes) exclude_view.AddItem (exclude_item); #if ENABLE_NETWORKING foreach (Service s in Conf.Networking.BeagleNodes) netbeagle_view.AddNode (s); allow_global_access_toggle.Active = Conf.Networking.ShareIndex; require_password_toggle.Active = Conf.Networking.PasswordRequired; index_name_entry.Text = Conf.Networking.IndexName; string password = Conf.Networking.Password.PadRight (12); password_entry.Text = password.Substring (0, 12); #endif } private void SaveConfiguration () { Conf.Daemon.AllowRoot = allow_root_toggle.Active; Conf.Searching.Autostart = autostart_toggle.Active; Conf.Indexing.IndexOnBattery = battery_toggle.Active; Conf.Searching.ShowSearchWindowBinding = new KeyBinding (show_search_window_entry.Text, press_ctrl_toggle.Active, press_alt_toggle.Active); Conf.Searching.MaxDisplayed = (int) max_displayed_spinbutton.Value; Conf.Indexing.IndexHomeDir = index_home_toggle.Active; Conf.Indexing.Roots = include_view.Includes; Conf.Indexing.Excludes = exclude_view.Excludes; #if ENABLE_NETWORKING Conf.Networking.BeagleNodes = netbeagle_view.Netbeagles; Conf.Networking.ShareIndex = allow_global_access_toggle.Active; Conf.Networking.PasswordRequired = require_password_toggle.Active; Conf.Networking.IndexName = index_name_entry.Text; Conf.Networking.Password = Password.Encode (password_entry.Text); #endif Conf.Save (true); } private void OnConfigurationChanged (Conf.Section section) { HigMessageDialog dialog = new HigMessageDialog (settings_dialog, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, Catalog.GetString ("Reload configuration"), Catalog.GetString ("The configuration file has been modified by another application. " + "Do you wish to discard the currently displayed values and reload configuration from disk?")); ResponseType response = (ResponseType) dialog.Run (); if (response == ResponseType.Yes) LoadConfiguration (); dialog.Destroy (); } //////////////////////////////////////////////////////////////// // Eventhandlers private void OnDialogResponse (object o, ResponseArgs args) { switch (args.ResponseId) { case ResponseType.Help: Gnome.Url.Show ("http://beagle-project.org/Configuring"); break; case ResponseType.Ok: SaveConfiguration (); Application.Quit (); break; default: Application.Quit (); break; } } private void OnDisplaySelected (object o, EventArgs args) { display_up_button.Sensitive = true; display_down_button.Sensitive = true; } private void OnAddIncludeClicked (object o, EventArgs args) { CompatFileChooserDialog fs_dialog = new CompatFileChooserDialog (Catalog.GetString ("Select Path"), settings_dialog, CompatFileChooserDialog.Action.SelectFolder); fs_dialog.SelectMultiple = false; ResponseType fs_response = (ResponseType) fs_dialog.Run (); string new_include = fs_dialog.Filename; fs_dialog.Destroy (); if (fs_response == ResponseType.Ok) { string error_message = ""; bool throw_error = false; ArrayList obsolete_includes = new ArrayList (); // Check and see if the current data collides with the new path in any way // FIXME: Do this with System.IO.Path or something foreach (string old_include in include_view.Includes) { if (new_include == old_include) { throw_error = true; error_message = Catalog.GetString ("The selected path is already selected for indexing and wasn't added."); } else if (new_include.StartsWith (old_include)) { throw_error = true; error_message = Catalog.GetString ("The selected path wasn't added. The list contains items that supercedes it and the data is already being indexed."); } else if (old_include.StartsWith (new_include)) { obsolete_includes.Add (old_include); } } if (throw_error) { HigMessageDialog.RunHigMessageDialog (settings_dialog, DialogFlags.Modal, MessageType.Warning, ButtonsType.Ok, Catalog.GetString ("Path not added"), error_message); } else { // Confirm the removal of obsolete includes if (obsolete_includes.Count != 0) { HigMessageDialog dialog = new HigMessageDialog (settings_dialog, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, Catalog.GetString ("Remove obsolete paths"), Catalog.GetString ("Adding this path will obsolete some of the existing include paths. " + "This will result in the removal of the old obsolete paths. Do you still wish to add it?")); ResponseType confirm_response = (ResponseType) dialog.Run (); if (confirm_response != ResponseType.Yes) return; foreach (string obsolete_include in obsolete_includes) include_view.RemovePath (obsolete_include); dialog.Destroy (); } include_view.AddPath (new_include); } } } private void OnRemoveIncludeClicked (object o, EventArgs args) { // Confirm removal HigMessageDialog dialog = new HigMessageDialog (settings_dialog, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, Catalog.GetString ("Remove path"), Catalog.GetString ("Are you sure you wish to remove this path from the list of directories to be included for indexing?")); ResponseType response = (ResponseType) dialog.Run (); dialog.Destroy (); if (response != ResponseType.Yes) return; include_view.RemoveSelectedPath (); remove_include_button.Sensitive = false; } private void OnIncludeSelected (object o, EventArgs args) { remove_include_button.Sensitive = true; } private void OnAddExcludeClicked (object o, EventArgs args) { AddExcludeDialog dialog = new AddExcludeDialog (settings_dialog); dialog.ExcludeItemAddedEvent += new ExcludeItemAddedHandler (OnExcludeItemAdded); } private void OnRemoveExcludeClicked (object o, EventArgs args) { HigMessageDialog dialog = new HigMessageDialog (settings_dialog, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, Catalog.GetString ("Remove item"), Catalog.GetString ("Are you sure you wish to remove this item from the list of data to be excluded from indexing?")); ResponseType response = (ResponseType) dialog.Run (); dialog.Destroy (); if (response != ResponseType.Yes) return; exclude_view.RemoveSelectedItem (); remove_exclude_button.Sensitive = false; } private void OnExcludeSelected (object o, EventArgs args) { remove_exclude_button.Sensitive = true; } private void OnExcludeItemAdded (ExcludeItem exclude_item) { exclude_view.AddItem (exclude_item); } //Netbeagle: Add, Remove operations private void OnAddNetbeagleClicked (object o, EventArgs args) { Service [] new_nodes; string error_message = String.Empty; bool throw_error = false; AddHostDialog dialog = new AddHostDialog (settings_dialog); ResponseType resp = (ResponseType) dialog.Run (); if (resp != ResponseType.Ok) { dialog.Destroy (); return; } new_nodes = dialog.SelectedHosts; dialog.Destroy (); // Check if the new entry matches an existing netbeagle entry foreach (Service old_node in netbeagle_view.Netbeagles) { foreach (Service node in new_nodes) { if (node == old_node) { throw_error = true; error_message = Catalog.GetString ("Remote host already present in the list."); } } } if (throw_error) { HigMessageDialog.RunHigMessageDialog (settings_dialog, DialogFlags.Modal, MessageType.Warning, ButtonsType.Ok, Catalog.GetString ("Netbeagle Node not added"), error_message); } else { foreach (Service node in new_nodes) netbeagle_view.AddNode (node); } } private void OnRemoveNetbeagleClicked (object o, EventArgs args) { // Confirm removal HigMessageDialog dialog = new HigMessageDialog (settings_dialog, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, Catalog.GetString ("Remove host"), Catalog.GetString ("Are you sure you wish to remove this host from the list?")); ResponseType response = (ResponseType) dialog.Run (); dialog.Destroy (); if (response != ResponseType.Yes) return; netbeagle_view.RemoveSelectedNode (); remove_netbeagle_button.Sensitive = false; } private void OnNetbeagleSelected (object o, EventArgs args) { remove_netbeagle_button.Sensitive = netbeagle_view.HasSelection; } //////////////////////////////////////////////////////////////// // IncludeView class IncludeView : TreeView { private ListStore store; private ArrayList includes = new ArrayList (); public ArrayList Includes { get { return includes; } } private enum TargetType { Uri, }; private static TargetEntry [] target_table = new TargetEntry [] { new TargetEntry ("STRING", 0, (uint) TargetType.Uri ), new TargetEntry ("text/plain", 0, (uint) TargetType.Uri), }; public IncludeView () { store = new ListStore (typeof (string)); this.Model = store; AppendColumn (Catalog.GetString ("Name"), new CellRendererText (), "text", 0); // Enable drag and drop folders from nautilus Gtk.Drag.DestSet (this, DestDefaults.All, target_table, DragAction.Copy | DragAction.Move); DragDataReceived += new DragDataReceivedHandler (HandleData); } public void AddPath (string path) { includes.Add (path); store.AppendValues (path); } public void RemovePath (string path) { find_path = path; found_iter = TreeIter.Zero; this.Model.Foreach (new TreeModelForeachFunc (ForeachFindPath)); store.Remove (ref found_iter); includes.Remove (path); } private string find_path; private TreeIter found_iter; private bool ForeachFindPath (TreeModel model, TreePath path, TreeIter iter) { if ((string) model.GetValue (iter, 0) == find_path) { found_iter = iter; return true; } return false; } public void RemoveSelectedPath () { TreeModel model; TreeIter iter; if (!this.Selection.GetSelected(out model, out iter)) { return; } string path = (string)model.GetValue(iter, 0); store.Remove (ref iter); includes.Remove (path); } // Handle drag and drop data. Enables users to drag a folder that he wishes // to add for indexing from Nautilus. // FIXME: Pass checks as in OnAddIncludeButtonClicked private void HandleData (object o, DragDataReceivedArgs args) { Uri uri; if (args.SelectionData.Length >=0 && args.SelectionData.Format == 8) { uri = new Uri (args.SelectionData.Text.Trim ()); AddPath (uri.LocalPath); Gtk.Drag.Finish (args.Context, true, false, args.Time); } Gtk.Drag.Finish (args.Context, false, false, args.Time); } } //////////////////////////////////////////////////////////////// // Exclude view class ExcludeView : TreeView { ArrayList excludes = new ArrayList (); public ArrayList Excludes { get { return excludes; } } public ExcludeView () { this.Model = new ListStore (typeof (ExcludeItem)); CellRendererText renderer_text = new CellRendererText (); TreeViewColumn type_column = new TreeViewColumn (); type_column.Title = Catalog.GetString ("Type"); type_column.PackStart (renderer_text, false); type_column.SetCellDataFunc (renderer_text, new TreeCellDataFunc (TypeCellDataFunc)); AppendColumn (type_column); TreeViewColumn name_column = new TreeViewColumn (); name_column.Title = Catalog.GetString ("Name"); name_column.PackStart (renderer_text, false); name_column.SetCellDataFunc (renderer_text, new TreeCellDataFunc (NameCellDataFunc)); AppendColumn (name_column); } public void RemoveSelectedItem () { TreeModel model; TreeIter iter; if (!this.Selection.GetSelected(out model, out iter)) { return; } ExcludeItem exclude_item = (ExcludeItem) model.GetValue(iter, 0); ((ListStore)this.Model).Remove (ref iter); excludes.Remove (exclude_item); } public void AddItem (ExcludeItem exclude_item) { excludes.Add (exclude_item); ((ListStore)this.Model).AppendValues (exclude_item); } private void NameCellDataFunc (TreeViewColumn column, CellRenderer renderer, TreeModel model, TreeIter iter) { ExcludeItem exclude_item = (ExcludeItem) model.GetValue (iter, 0); if (exclude_item.Type == ExcludeType.MailFolder) ((CellRendererText)renderer).Text = MailFolder.GetNameForPath (exclude_item.Value); else ((CellRendererText)renderer).Text = exclude_item.Value; } private void TypeCellDataFunc (TreeViewColumn column, CellRenderer renderer, TreeModel model, TreeIter iter) { ExcludeItem exclude_item = (ExcludeItem) model.GetValue (iter, 0); switch (exclude_item.Type) { case ExcludeType.Path: ((CellRendererText)renderer).Text = Catalog.GetString ("Path:"); break; case ExcludeType.Pattern: ((CellRendererText)renderer).Text = Catalog.GetString ("Pattern:"); break; case ExcludeType.MailFolder: ((CellRendererText)renderer).Text = Catalog.GetString ("Mail folder:"); break; } } } #if ENABLE_NETWORKING //////////////////////////////////////////////////////////////// // PasswordDialog class PasswordDialog : Dialog { [Widget] private Dialog password_dialog; [Widget] private Label title_label; [Widget] private Entry password_entry; public string Password { get { return this.password_entry.Text; } } public PasswordDialog (string name) : base (IntPtr.Zero) { Glade.XML gxml = new Glade.XML (null, "settings.glade", "password_dialog", "beagle"); gxml.Autoconnect (this); Raw = password_dialog.Handle; this.Title = String.Format ("Connecting to {0}", name); this.Present (); } } //////////////////////////////////////////////////////////////// // AddHostDialog public class AddHostDialog : Dialog { const int COL_NAME = 0; const int COL_PIXBUF = 1; const int COL_AUTH = 2; const int COL_HOST = 3; const int COL_PORT = 4; [Glade.Widget] private Dialog add_host_dialog; [Glade.Widget] private RadioButton mdns_radio_button; [Glade.Widget] private RadioButton static_radio_button; [Glade.Widget] private Alignment static_section; [Glade.Widget] private Entry name_entry; [Glade.Widget] private Entry address_entry; [Glade.Widget] private Entry password_entry; [Glade.Widget] private SpinButton port_spin_button; [Glade.Widget] private IconView icon_view; private MDnsBrowser browser; private ListStore store; private Gdk.Pixbuf unlocked_icon; private Gdk.Pixbuf locked_icon; public Service [] SelectedHosts { get { Service [] hosts; if (this.mdns_radio_button.Active == false) { Uri uri = new Uri (String.Format ("http://{0}:{1}", address_entry.Text, port_spin_button.ValueAsInt)); bool pw_required = (password_entry.Text.Length > 0) ? true : false; string name; if (name_entry.Text.Length > 0) name = name_entry.Text; else name = "Unnamed"; hosts = new Service [] { new Service (name, uri, pw_required, "X") }; } else { TreeIter iter; ArrayList list = new ArrayList (); try { foreach (TreePath path in icon_view.SelectedItems) { if (store.GetIter (out iter, path) == false) continue; string name = (string) store.GetValue (iter, COL_NAME); Service s = (Service) browser.AvailableHosts [name]; list.Add (s); } } catch (Exception e) { Console.Error.WriteLine (e.Message); } hosts = (Service []) list.ToArray (typeof (Service)); } return hosts; } } public AddHostDialog (Gtk.Window parent) : base (null, parent, DialogFlags.DestroyWithParent) { Glade.XML gxml = new Glade.XML (null, "settings.glade", "add_host_dialog", null); gxml.Autoconnect (this); Raw = add_host_dialog.Handle; this.TransientFor = parent; mdns_radio_button.Toggled += new EventHandler (OnRadioButtonToggled); // load the image to use for each node unlocked_icon = Gtk.IconTheme.Default.LoadIcon ("gnome-fs-network", 48, (IconLookupFlags) 0); locked_icon = Gtk.IconTheme.Default.LoadIcon ("gtk-dialog-authentication", 48, (IconLookupFlags) 0); CreateStore (); icon_view.Model = store; icon_view.TextColumn = COL_NAME; icon_view.PixbufColumn = COL_PIXBUF; icon_view.ColumnSpacing = 24; icon_view.ItemActivated += new ItemActivatedHandler (OnItemActivated); icon_view.GrabFocus (); this.ShowAll (); try { browser = new MDnsBrowser (); browser.HostFound += new MDnsEventHandler (OnHostFound); browser.HostRemoved += new MDnsEventHandler (OnHostRemoved); browser.Start (); } catch (Exception e) { Console.Error.WriteLine ("Avahi Daemon must be unavailable. Hiding MDns stuff."); static_radio_button.Toggle (); icon_view.Visible = false; mdns_radio_button.Visible = false; static_radio_button.Visible = false; } } private void CreateStore () { store = new ListStore (typeof (string), // Name typeof (Gdk.Pixbuf), // Icon typeof (bool), // Requires authentication typeof (string), // hostname typeof (int)); // port store.DefaultSortFunc = delegate (TreeModel model, TreeIter a, TreeIter b) { string a_name = (string) model.GetValue (a, COL_NAME); string b_name = (string) model.GetValue (b, COL_NAME); return String.Compare (a_name, b_name); }; store.SetSortColumnId (COL_NAME, SortType.Ascending); } private void OnHostFound (object sender, MDnsEventArgs args) { store.AppendValues (args.Name, (args.Service.IsProtected == true) ? locked_icon : unlocked_icon, args.Service.IsProtected, args.Address.Host, args.Address.Port); Console.WriteLine ("Port: {0}", args.Address.Port); icon_view.QueueDraw (); } private void OnHostRemoved (object sender, MDnsEventArgs args) { find_node = args.Address.Host; found_iter = TreeIter.Zero; store.Foreach (new TreeModelForeachFunc (ForeachFindNode)); store.Remove (ref found_iter); } private string find_node; private TreeIter found_iter; private bool ForeachFindNode (TreeModel model, TreePath path, TreeIter iter) { if ((string) model.GetValue (iter, COL_HOST) == find_node) { found_iter = iter; return true; } return false; } private void OnItemActivated (object sender, ItemActivatedArgs args) { TreeIter iter; store.GetIter (out iter, args.Path); try { string host = (string) store.GetValue (iter, COL_HOST); int port = (int) store.GetValue (iter, COL_PORT); Console.WriteLine ("Host activated: {0}", String.Format ("{0}:{1}", host.Trim (), port)); // The user has double clicked on the icon, so they probably expect // the same behavior as selecting this icon and clicking "Add". Respond (ResponseType.Ok); } catch (Exception e) { Console.Error.WriteLine ("Exception: {0}", e.Message); } } private void OnRadioButtonToggled (object sender, EventArgs args) { if (mdns_radio_button.Active) { icon_view.Sensitive = true; static_section.Sensitive = false; } else { icon_view.Sensitive = false; static_section.Sensitive = true; } } public override void Destroy () { if (browser != null) { browser.Dispose (); browser.HostFound -= OnHostFound; browser.HostRemoved -= OnHostRemoved; browser = null; } base.Destroy (); } } #endif //////////////////////////////////////////////////////////////// // NetbeagleView class NetbeagleView : TreeView { private ListStore store; private ArrayList netBeagleList = new ArrayList (); public ArrayList Netbeagles { get { return netBeagleList; } } public bool HasSelection { get { return (base.Selection.CountSelectedRows () > 0); } } public NetbeagleView () { store = new ListStore (typeof (Service)); this.Model = store; TreeViewColumn column = new TreeViewColumn (); column.Title = "Name"; CellRendererText renderer = new CellRendererText (); column.PackStart (renderer, true); column.SetCellDataFunc (renderer, NameCellFunc); AppendColumn (column); column = new TreeViewColumn (); column.Title = "Address"; renderer = new CellRendererText (); column.PackStart (renderer, true); column.SetCellDataFunc (renderer, AddressCellFunc); AppendColumn (column); } public void AddNode (Service service) { netBeagleList.Add (service); store.AppendValues (service); } public void RemoveNode (Service s) { find_node = s; found_iter = TreeIter.Zero; this.Model.Foreach (new TreeModelForeachFunc (ForeachFindNode)); store.Remove (ref found_iter); netBeagleList.Remove (s); } public void NameCellFunc (TreeViewColumn col, CellRenderer cell, TreeModel model, TreeIter iter) { CellRendererText renderer = (CellRendererText) cell; Service s = (Service) model.GetValue (iter, 0); renderer.Markup = s.Name; } public void AddressCellFunc (TreeViewColumn col, CellRenderer cell, TreeModel model, TreeIter iter) { CellRendererText renderer = (CellRendererText) cell; Service s = (Service) model.GetValue (iter, 0); renderer.Markup = String.Format ("{0}:{1}", s.GetUri ().Host, s.GetUri ().Port); } private Beagle.Service find_node; private TreeIter found_iter; private bool ForeachFindNode (TreeModel model, TreePath path, TreeIter iter) { if ((Service) model.GetValue (iter, 0) == find_node) { found_iter = iter; return true; } return false; } public void RemoveSelectedNode () { TreeModel model; TreeIter iter; if (!this.Selection.GetSelected(out model, out iter)) { return; } Service service = (Service) model.GetValue(iter, 0); store.Remove (ref iter); netBeagleList.Remove (service); } } //////////////////////////////////////////////////////////////// // PublicfolderView class PublicfolderView: TreeView { private ListStore store; private ArrayList publicFolders = new ArrayList (); public ArrayList Publicfolders { get { return publicFolders; } } private enum TargetType { Uri, }; private static TargetEntry [] target_table = new TargetEntry [] { new TargetEntry ("STRING", 0, (uint) TargetType.Uri ), new TargetEntry ("text/plain", 0, (uint) TargetType.Uri), }; public PublicfolderView () { store = new ListStore (typeof (string)); this.Model = store; AppendColumn (Catalog.GetString ("Name"), new CellRendererText (), "text", 0); // Enable drag and drop folders from nautilus Gtk.Drag.DestSet (this, DestDefaults.All, target_table, DragAction.Copy | DragAction.Move); DragDataReceived += new DragDataReceivedHandler (HandleData); } public void AddPath (string path) { publicFolders.Add (path); store.AppendValues (path); } public void RemovePath (string path) { find_path = path; found_iter = TreeIter.Zero; this.Model.Foreach (new TreeModelForeachFunc (ForeachFindPath)); store.Remove (ref found_iter); publicFolders.Remove (path); } private string find_path; private TreeIter found_iter; private bool ForeachFindPath (TreeModel model, TreePath path, TreeIter iter) { if ((string) model.GetValue (iter, 0) == find_path) { found_iter = iter; return true; } return false; } public void RemoveSelectedPath () { TreeModel model; TreeIter iter; if (!this.Selection.GetSelected(out model, out iter)) { return; } string path = (string)model.GetValue(iter, 0); store.Remove (ref iter); publicFolders.Remove (path); } // Handle drag and drop data. Enables users to drag a folder that he wishes // to add for indexing from Nautilus. // FIXME: Pass checks as in OnAddIncludeButtonClicked private void HandleData (object o, DragDataReceivedArgs args) { Uri uri; if (args.SelectionData.Length >=0 && args.SelectionData.Format == 8) { uri = new Uri (args.SelectionData.Text.Trim ()); AddPath (uri.LocalPath); Gtk.Drag.Finish (args.Context, true, false, args.Time); } Gtk.Drag.Finish (args.Context, false, false, args.Time); } } //////////////////////////////////////////////////////////////// // Mail folder dialog class MailFolderDialog { Gtk.Window parent; FolderView folder_view; [Widget] Dialog mail_folder_dialog; [Widget] ScrolledWindow folder_sw; public event ExcludeItemAddedHandler ExcludeItemAddedEvent; public MailFolderDialog (Gtk.Window parent) { this.parent = parent; Glade.XML glade = new Glade.XML (null, "settings.glade", "mail_folder_dialog", "beagle"); glade.Autoconnect (this); folder_view = new FolderView (); folder_view.Show (); folder_sw.Child = folder_view; } private void OnDialogResponse (object o, ResponseArgs args) { if (args.ResponseId == ResponseType.Cancel) { mail_folder_dialog.Destroy (); return; } ExcludeItem exclude_item; object obj = folder_view.GetCurrentItem (); if (obj is MailAccount) { } else if (obj is MailFolder) { MailFolder folder = (MailFolder) obj; exclude_item = new ExcludeItem (ExcludeType.MailFolder, folder.Path); if (ExcludeItemAddedEvent != null) ExcludeItemAddedEvent (exclude_item); mail_folder_dialog.Destroy (); } } class FolderView : TreeView { TreeStore store; Gdk.Pixbuf folder_icon; public FolderView () { store = new TreeStore (typeof (MailFolder)); this.Model = store; folder_icon = this.RenderIcon (Stock.Open, IconSize.Menu, ""); HeadersVisible = false; TreeViewColumn column = new TreeViewColumn (); CellRendererPixbuf renderer_icon = new CellRendererPixbuf (); column.PackStart (renderer_icon, false); column.SetCellDataFunc (renderer_icon, new TreeCellDataFunc (IconCellDataFunc)); CellRendererText renderer_text = new CellRendererText (); column.PackStart (renderer_text, false); column.SetCellDataFunc (renderer_text, new TreeCellDataFunc (NameCellDataFunc)); AppendColumn (column); foreach (MailAccount account in Beagle.Util.Evolution.Accounts) { TreeIter iter = store.AppendValues (account); foreach (MailFolder folder in account.Children) { Add (iter, folder); } } } private void Add (TreeIter parent, MailFolder folder) { TreeIter current = store.AppendValues (parent, folder); foreach (MailFolder child in folder.Children) Add (current, child); } private void IconCellDataFunc (TreeViewColumn column, CellRenderer renderer, TreeModel model, TreeIter iter) { object obj = model.GetValue (iter, 0); ((CellRendererPixbuf)renderer).Pixbuf = (obj is MailAccount) ? null : folder_icon; } private void NameCellDataFunc (TreeViewColumn column, CellRenderer renderer, TreeModel model, TreeIter iter) { object obj = model.GetValue (iter, 0); if (obj is MailAccount) { MailAccount account = obj as MailAccount; ((CellRendererText)renderer).Markup = String.Format ("{0}",account.Name); } else { MailFolder folder = obj as MailFolder; ((CellRendererText)renderer).Text = folder.Name; } } public MailFolder GetCurrentItem () { TreeModel model; TreeIter iter; if (!this.Selection.GetSelected (out model, out iter)) { return null; } return (MailFolder) model.GetValue (iter, 0); } } } //////////////////////////////////////////////////////////////// // Exclude dialog private delegate void ExcludeItemAddedHandler (ExcludeItem item); class AddExcludeDialog { Gtk.Window parent; [Widget] Dialog add_exclude_dialog; [Widget] Entry value_entry; [Widget] Label value_name_label; [Widget] Button browse_button; [Widget] RadioButton type_path_radio; [Widget] RadioButton type_pattern_radio; [Widget] RadioButton type_mailfolder_radio; public event ExcludeItemAddedHandler ExcludeItemAddedEvent; private string value; public string Value { get { if (Type == ExcludeType.MailFolder) return value; else return value_entry.Text; } } public ExcludeType Type { get { if (type_path_radio.Active) return ExcludeType.Path; else if (type_pattern_radio.Active) return ExcludeType.Pattern; else return ExcludeType.MailFolder; } } public AddExcludeDialog (Gtk.Window parent) { this.parent = parent; Glade.XML glade = new Glade.XML (null, "settings.glade", "add_exclude_dialog", "beagle"); glade.Autoconnect (this); } private void OnBrowseButtonClicked (object o, EventArgs args) { switch (Type) { case ExcludeType.Path: CompatFileChooserDialog fs_dialog = new CompatFileChooserDialog (Catalog.GetString ("Select Folder"), add_exclude_dialog, CompatFileChooserDialog.Action.SelectFolder); fs_dialog.SelectMultiple = false; ResponseType response = (ResponseType) fs_dialog.Run (); if (response == ResponseType.Ok) value_entry.Text = fs_dialog.Filename; fs_dialog.Destroy (); break; case ExcludeType.MailFolder: MailFolderDialog mf_dialog = new MailFolderDialog (add_exclude_dialog); mf_dialog.ExcludeItemAddedEvent += new ExcludeItemAddedHandler (OnExcludeItemAdded); break; } } private void OnRadioGroupChanged (object o, EventArgs args) { value_entry.Text = ""; switch (Type) { case ExcludeType.Path: browse_button.Sensitive = true; value_name_label.TextWithMnemonic = Catalog.GetString ("P_ath:"); value_entry.IsEditable = true; break; case ExcludeType.MailFolder: browse_button.Sensitive = true; value_name_label.TextWithMnemonic = Catalog.GetString ("M_ail folder:"); value_entry.IsEditable = false; break; case ExcludeType.Pattern: browse_button.Sensitive = false; value_name_label.TextWithMnemonic = Catalog.GetString ("P_attern:"); value_entry.IsEditable = true; break; } } private void OnExcludeItemAdded (ExcludeItem item) { value = item.Value; value_entry.Text = MailFolder.GetNameForPath (item.Value); } private void OnDialogResponse (object o, ResponseArgs args) { if (((ResponseType)args.ResponseId) == ResponseType.Ok) { ExcludeItem exclude_item = new ExcludeItem (Type, Value); switch (Type) { case ExcludeType.Path: if (!Directory.Exists (Value)) { HigMessageDialog.RunHigMessageDialog(add_exclude_dialog, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, Catalog.GetString ("Error adding path"), Catalog.GetString ("The specified path could not be found and therefore it could not be added to the list of resources excluded for indexing.")); return; } break; } if (ExcludeItemAddedEvent != null) ExcludeItemAddedEvent (exclude_item); } add_exclude_dialog.Destroy (); } public void Destroy () { add_exclude_dialog.Destroy (); } } #if false //////////////////////////////////////////////////////////////// // Display view class DisplayView : TreeView { public DisplayView () { ListStore store = new ListStore (typeof(bool),typeof(string)); this.Model = store; AppendColumn (Catalog.GetString ("Show"), new CellRendererToggle (), "active", 0); AppendColumn (Catalog.GetString ("Name"), new CellRendererText (), "text", 1); } } #endif }