// UI.Toolbar.cs created with MonoDevelop
// User: klose at 10:34 15.01.2009
// CVS release: $Id: UI.Toolbar.cs,v 1.75 2011-06-24 13:48:23 klose Exp $
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2009  Thomas Klose, Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
using System.Text;
using System.Linq;

using Gtk;
using Glade;

using Hiperscan.GUI.Figure;
using Hiperscan.Spectroscopy;
using Hiperscan.FileIO;
using Hiperscan.SGS;
using Hiperscan.Extensions;
using Hiperscan.Unix;


namespace Hiperscan.GUI
{
	
	public partial class UserInterface
	{
		
		[Widget] Gtk.HandleBox standard_handlebox = null;
		[Widget] Gtk.HandleBox figure_handlebox   = null;

		[Widget] Gtk.Toolbar standard_toolbar   = null;

		[Widget] Gtk.ImageMenuItem save_item          = null;
		[Widget] Gtk.ImageMenuItem print_item         = null;
		[Widget] Gtk.ImageMenuItem clear_item         = null;
		[Widget] Gtk.ImageMenuItem zoom_fit_item      = null;
		[Widget] Gtk.ImageMenuItem zoom_standard_item = null;
		[Widget] Gtk.ImageMenuItem zoom_in_item       = null;
		[Widget] Gtk.ImageMenuItem zoom_out_item      = null;
		[Widget] Gtk.ImageMenuItem copy_item          = null;
		[Widget] Gtk.ImageMenuItem export_item        = null;
		[Widget] Gtk.ImageMenuItem undo_item          = null;
		[Widget] Gtk.ImageMenuItem redo_item          = null;
		[Widget] Gtk.ImageMenuItem start_item         = null;
		[Widget] Gtk.ImageMenuItem quickstream_item   = null;
		[Widget] Gtk.ImageMenuItem stop_item          = null;
		[Widget] Gtk.ImageMenuItem single_item        = null;
		[Widget] Gtk.ImageMenuItem disconnect_remote_item = null;
		[Widget] Gtk.ImageMenuItem close_tab_item = null;
		
		[Widget] Gtk.MenuItem reopen_item             = null;
		[Widget] Gtk.MenuItem save_container_item     = null;
		[Widget] Gtk.MenuItem send_item               = null;
		[Widget] Gtk.MenuItem insert_annotations_item = null;
		[Widget] Gtk.MenuItem clear_annotations_item  = null;
		[Widget] Gtk.MenuItem copy_plot_data_item     = null;

		[Widget] Gtk.MenuItem clear_background_item   = null;
		[Widget] Gtk.MenuItem sync_axes_item          = null;
		[Widget] Gtk.CheckMenuItem lock_axes_item     = null;
		
		[Widget] Gtk.Image lock_axes_image = null;
		
		[Widget] Gtk.CheckMenuItem data_sources_item       = null;
		[Widget] Gtk.CheckMenuItem properties_item         = null;
		[Widget] Gtk.CheckMenuItem plot_browser_item       = null;
		[Widget] Gtk.CheckMenuItem standard_toolbar_item   = null;
		[Widget] Gtk.CheckMenuItem figure_toolbar_item     = null;
		[Widget] Gtk.CheckMenuItem extensions_toolbar_item = null;
		
		[Widget] Gtk.RadioMenuItem english_item = null;
		[Widget] Gtk.RadioMenuItem german_item  = null;
		[Widget] Gtk.RadioMenuItem system_item = null;
		
		[Widget] Gtk.RadioMenuItem axis_type_wavelength_item = null;
		[Widget] Gtk.RadioMenuItem axis_type_wavecount_item  = null;

		[Widget] Gtk.MenuItem plot_type_item   = null;
		[Widget] Gtk.MenuItem themes_item      = null;
//		[Widget] Gtk.MenuItem insert_text_item = null;
		
		[Widget] Gtk.SpinButton x_min_spin = null;
		[Widget] Gtk.SpinButton x_max_spin = null;
		[Widget] Gtk.SpinButton y_min_spin = null;
		[Widget] Gtk.SpinButton y_max_spin = null;
		
		[Widget] Gtk.ComboBox plot_type_combo              = null;
//		[Widget] Gtk.ComboBox default_output_culture_combo = null;
		
		[Widget] Gtk.HBox x_minmax_hbox         = null;
		[Widget] Gtk.HBox y_minmax_hbox         = null;
		
		[Widget] Gtk.ToolButton save_button          = null;
		[Widget] Gtk.ToolButton print_button         = null;
		[Widget] Gtk.ToolButton clear_button         = null;
		[Widget] Gtk.ToolButton zoom_fit_button      = null;
		[Widget] Gtk.ToolButton single_button        = null;
		[Widget] Gtk.ToolButton start_button         = null;
		[Widget] Gtk.ToolButton stop_button          = null;
		[Widget] Gtk.ToolButton quickstream_button   = null;
		[Widget] Gtk.ToolButton undo_button          = null;
		[Widget] Gtk.ToolButton redo_button          = null;
		[Widget] Gtk.ToolButton zoom_standard_button = null;
		[Widget] Gtk.ToolButton zoom_in_button       = null;
		[Widget] Gtk.ToolButton zoom_out_button      = null;
		[Widget] Gtk.ToolButton copy_button          = null;
		[Widget] Gtk.ToolButton export_button        = null;
		
		[Widget] Gtk.ToolButton insert_text_button        = null;
		[Widget] Gtk.ToolButton insert_line_button        = null;
		[Widget] Gtk.ToolButton insert_rectangle_button   = null;
		[Widget] Gtk.ToolButton insert_ellipse_button     = null;
		[Widget] Gtk.ToolButton insert_arrow_button       = null;
		[Widget] Gtk.ToolButton insert_doublearrow_button = null;

		[Widget] Gtk.ToolButton plot_tv_save_button       = null;
		[Widget] Gtk.ToolButton plot_tv_copy_button       = null;
		[Widget] Gtk.ToolButton plot_tv_delete_button     = null;
		[Widget] Gtk.ToolButton plot_tv_auto_color_button = null;
		[Widget] Gtk.ToolButton plot_tv_move_up_button    = null;
		[Widget] Gtk.ToolButton plot_tv_move_down_button  = null;
		[Widget] Gtk.ToolButton plot_tv_add_button        = null;
		[Widget] Gtk.ToolButton plot_tv_remove_button     = null;
		
		[Widget] Gtk.ToggleToolButton data_sources_button    = null;
		[Widget] Gtk.ToggleToolButton property_editor_button = null;
		[Widget] Gtk.ToggleToolButton plot_browser_button    = null;
		[Widget] Gtk.ToggleToolButton edit_x_constraints_button  = null;
		
		[Widget] Gtk.ToolItem  x_constraints_item  = null;
		[Widget] Gtk.Alignment x_constraints_align = null;
		
		[Widget] Gtk.MenuItem extensions_menuitem = null;
		[Widget] Gtk.Menu extensions_menu = null;
		
		[Widget] Gtk.VBox plot_browser_vbox = null;
		[Widget] Gtk.Menu edit_menu         = null;
		[Widget] Gtk.Menu spectrometer_menu = null;
		[Widget] Gtk.Menu figure_menu       = null;
		
		private XConstraintsEntry x_constraints_entry = null;
		
		internal static Gdk.Color  entry_error_color = new Gdk.Color(255, 150, 150);

		
		private void UIPlotControlsSensitive(bool val)
		{
			this.save_item.Sensitive               = val && this.device_list.AllIdleOrDisconnected;
			this.save_container_item.Sensitive     = val && this.device_list.AllIdleOrDisconnected;
			this.send_item.Sensitive               = val && this.device_list.AllIdleOrDisconnected;
			this.print_item.Sensitive              = val && this.device_list.AllIdleOrDisconnected;
			this.export_item.Sensitive             = val && this.device_list.AllIdleOrDisconnected;
			this.insert_annotations_item.Sensitive = val;
			this.clear_annotations_item.Sensitive  = val && (this.ScrolledPlot.Plot.Annotations.Count > 0);
			this.clear_item.Sensitive              = val;
			this.zoom_fit_item.Sensitive           = val;
			this.zoom_standard_item.Sensitive      = val;
			this.zoom_in_item.Sensitive            = val;
			this.zoom_out_item.Sensitive           = val;
			this.copy_item.Sensitive               = val;
			this.copy_plot_data_item.Sensitive     = val;
			
			this.undo_button.Sensitive = this.device_list.AllIdleOrDisconnected && this.plot_info_list.Current.CurrentSpectra.UndoIsPossible;
			this.undo_item.Sensitive   = this.device_list.AllIdleOrDisconnected && this.plot_info_list.Current.CurrentSpectra.UndoIsPossible;
			this.redo_button.Sensitive = this.device_list.AllIdleOrDisconnected && this.plot_info_list.Current.CurrentSpectra.RedoIsPossible;
			this.redo_item.Sensitive   = this.device_list.AllIdleOrDisconnected && this.plot_info_list.Current.CurrentSpectra.RedoIsPossible;
			
			this.save_button.Sensitive               = val && this.device_list.AllIdleOrDisconnected;
			this.print_button.Sensitive              = val && this.device_list.AllIdleOrDisconnected;
			this.export_button.Sensitive             = val && this.device_list.AllIdleOrDisconnected;
			this.clear_button.Sensitive              = val;
			this.edit_x_constraints_button.Sensitive = val;
			this.zoom_fit_button.Sensitive           = val;
			this.zoom_standard_button.Sensitive      = val;
			this.zoom_in_button.Sensitive            = val;
			this.zoom_out_button.Sensitive           = val;
			this.copy_button.Sensitive               = val;
			
			this.insert_text_button.Sensitive = val;
			this.insert_line_button.Sensitive = val;
			this.insert_rectangle_button.Sensitive = val;
			this.insert_ellipse_button.Sensitive = val;
			this.insert_arrow_button.Sensitive = val;
			this.insert_doublearrow_button.Sensitive = val;

			this.x_minmax_hbox.Sensitive = val;
			this.y_minmax_hbox.Sensitive = val;
			
			if (this.ScrolledPlot != null)
				this.ScrolledPlot.Sensitive = val;
			
			this.plot_browser_vbox.Sensitive = !this.plot_tv.IsEmpty;
		}
		
		private void UpdateFigureControls()
		{
			bool val = (this.plot_info_list.Background != null);
			this.clear_background_item.Sensitive = val;
			this.sync_axes_item.Sensitive  = val;
			this.lock_axes_item.Sensitive  = val;
			this.lock_axes_image.Sensitive = val;
		}
		
		public void UpdateDeviceControls()
		{
			bool single       = false;
			bool quick        = false;
			bool start        = false;
			bool stop         = false;
			bool remote       = false;
			bool unprogrammed = false;
			bool idle         = false;
			
			foreach (Device dev in this.active_devices)
			{
				if (dev.Info.IsRemote)
					remote = true;
				
				Device.State state = dev.GetState();

				switch (state)
				{
					
				case Device.State.Idle:
					single = true;
					start  = true;
					quick  = true;
					idle   = true;
					break;
					
				case Device.State.Continuous:
				case Device.State.Stream:
					single = true;
					quick  = true;
					stop   = true;
					break;

				case Device.State.QuickStream:
					single = true;
					start  = true;
					stop   = true;
					break;
					
				case Device.State.Unprogrammed:
					unprogrammed = true;
					break;
				}
			}
			
			this.single_item.Sensitive            = single;
			this.start_item.Sensitive             = start;
			this.stop_item.Sensitive              = stop;
			this.quickstream_item.Sensitive       = quick;
			this.disconnect_remote_item.Sensitive = remote;
			this.single_button.Sensitive          = single;
			
			foreach (IPlugin plugin in this.plugins.Values)
			{
				if (plugin.MenuInfos != null)
				{
					foreach (MenuInfo info in plugin.MenuInfos)
					{
						if (!info.IsSensitive)
						{
							info.MenuItem.Sensitive = false;
							continue;
						}
						
						if (info.NeedSingleDevice && this.active_devices.Count != 1)
						{
							info.MenuItem.Sensitive = false;
							continue;
						}
						
						if (info.NeedIdleDevice)
							info.MenuItem.Sensitive = idle;
						
						if (info.NeedUnprogrammedOrIdleDevice)
							info.MenuItem.Sensitive = unprogrammed || idle;
					}
				}
				
				if (plugin.ToolbarInfos != null)
				{
					foreach (ToolbarInfo info in plugin.ToolbarInfos)
					{
						if (!info.IsSensitive)
						{
							info.ToolItem.Sensitive = false;
							continue;
						}
						
						if (info.NeedSingleDevice && this.active_devices.Count != 1)
						{
							info.ToolItem.Sensitive = false;
							continue;
						}
						
						if (info.NeedIdleDevice)
							info.ToolItem.Sensitive = idle;
						
						if (info.NeedUnprogrammedOrIdleDevice)
							info.ToolItem.Sensitive = unprogrammed || idle;
					}
				}
			}
			this.start_button.Sensitive       = start;
			this.stop_button.Sensitive        = stop;
			this.quickstream_button.Sensitive = quick;
			
			bool val = this.device_list.AllIdleOrDisconnected && !this.ScrolledPlot.Plot.IsEmpty;
			this.save_item.Sensitive           = val;
			this.save_container_item.Sensitive = val;
			this.send_item.Sensitive           = val;
			this.print_item.Sensitive          = val;
			this.export_item.Sensitive         = val;
			this.undo_button.Sensitive = val && this.plot_info_list.Current.CurrentSpectra.UndoIsPossible;
			this.undo_item.Sensitive   = val && this.plot_info_list.Current.CurrentSpectra.UndoIsPossible;
			this.redo_button.Sensitive = val && this.plot_info_list.Current.CurrentSpectra.RedoIsPossible;
			this.redo_item.Sensitive   = val && this.plot_info_list.Current.CurrentSpectra.RedoIsPossible;

			this.save_button.Sensitive   = val;
			this.print_button.Sensitive  = val;
			this.export_button.Sensitive = val;
		}
		
		public void UpdatePluginInfos()
		{
			bool hide_edit_shortcuts_item = true;
			bool hide_standard_handlebox = true;
			bool no_extensions_active = true;
			bool plot_types_changed = false;
			
			foreach (Widget w in this.standard_toolbar_widgets)
			{
				if (this.standard_toolbar_item.Active)
				{
					w.NoShowAll = false;
					w.ShowAll();
					hide_standard_handlebox = false;
				}
				else
				{
					w.NoShowAll = true;
					w.Visible = false;
				}
			}
			
			foreach (IPlugin plugin in this.plugins.Values)
			{
				if (plugin.MenuInfos != null && plugin.MenuInfos.Length > 0)
				{				
					if (plugin.Active)
						hide_edit_shortcuts_item = false;
					
					if (plugin.MenuInfos.Length == 1)
					{
						plugin.MenuInfos[0].MenuItem.Visible = plugin.Active;
						plugin.MenuInfos[0].MenuItem.NoShowAll = !plugin.Active;
					}
					else if (plugin.MenuInfos.Length > 1)
					{
						plugin.MenuInfos[0].SubMenuItem.Visible = plugin.Active;
						plugin.MenuInfos[0].SubMenuItem.NoShowAll = !plugin.Active;
						if (plugin.Active)
							plugin.MenuInfos[0].SubMenuItem.ShowAll();
					}
				}

				if (plugin.ToolbarInfos != null)
				{
					if (plugin.Active && this.extensions_toolbar_item.Active)
						hide_standard_handlebox = false;
					
					if (plugin.Active)
						no_extensions_active = false;

					bool active = plugin.Active && this.extensions_toolbar_item.Active;
					
					foreach (ToolbarInfo info in plugin.ToolbarInfos)
					{
						info.ToolItem.Visible = active;
						info.ToolItem.NoShowAll = !active;
						if (active)
							info.ToolItem.ShowAll();
					}
				}
				
//				string guid = plugin.Guid.ToString();
//				if (this.plot_types.ContainsKey(guid))
//				{
//					foreach (PlotTypeInfo plot_type in this.plot_types[guid])
//					{
//						if (plot_type.Active != plugin.Active)
//						{
//							plot_types_changed = true;
//							plot_type.Active = plugin.Active;
//						}
//					}
//				}
				
				if (plugin.PlotTypeInfos != null)
				{
					plot_types_changed = true;
					
					if (plugin.Active)
					{
						if (!this.plot_types.ContainsKey(plugin.Guid.ToString()))
						    this.plot_types.Add(plugin.Guid.ToString(), plugin.PlotTypeInfos);
						else
							this.plot_types[plugin.Guid.ToString()] = plugin.PlotTypeInfos;
					}
					else
					{
						if (this.plot_types.ContainsKey(plugin.Guid.ToString()))
							this.plot_types.Remove(plugin.Guid.ToString());
					}
				}
				
				if (plugin.FileTypeInfos != null)
				{
					if (plugin.Active)
					{
						if (!this.file_types.ContainsKey(plugin.Guid.ToString()))
						    this.file_types.Add(plugin.Guid.ToString(), plugin.FileTypeInfos);
					}
					else
					{
						if (this.file_types.ContainsKey(plugin.Guid.ToString()))
							this.file_types.Remove(plugin.Guid.ToString());
					}
				}
			}
			
			bool show_separator = false;
			bool show_first_separator = false;
			SeparatorToolItem first_separator = null;
			SeparatorToolItem last_separator = null;
			foreach (Widget w in this.extension_toolbar_widgets)
			{
				if (w is SeparatorToolItem)
				{
					if (first_separator == null)
						first_separator = (SeparatorToolItem)w;
					
					w.Visible = show_separator;
					w.NoShowAll = !show_separator;
					
					if (show_separator)
					{
						last_separator = (SeparatorToolItem)w;
						show_separator = false;
					}
				}
				else 
				{
					if (w.Visible)
						show_first_separator = this.standard_toolbar_item.Active;
					
					show_separator = w.Visible;
				}
			}
			
			if (show_first_separator && first_separator != null)
			{
				first_separator.NoShowAll = false;
				first_separator.ShowAll();
			}
			
			if (!show_separator && last_separator != null)
			{
				last_separator.Visible = false;
				last_separator.NoShowAll = true;
			}
			
			if (this.edit_shortcuts_item != null)
			{
				if (hide_edit_shortcuts_item)
				{
					this.edit_shortcuts_item.NoShowAll = true;
					this.edit_shortcuts_item.Visible = false;
				}
				else
				{
					this.edit_shortcuts_item.NoShowAll = false;
					this.edit_shortcuts_item.ShowAll();
				}
			}
			
			this.extensions_toolbar_item.Sensitive = !no_extensions_active;
			
			if (hide_standard_handlebox)
			{
				this.standard_handlebox.NoShowAll = true;
				this.standard_handlebox.Visible = false;
			}
			else
			{
				this.standard_handlebox.NoShowAll = false;
				this.standard_handlebox.ShowAll();
			}
			
			
			if (this.figure_toolbar_item.Active)
			{
				this.figure_handlebox.NoShowAll = false;
				this.figure_handlebox.ShowAll();
			}
			else
			{
				this.figure_handlebox.NoShowAll = true;
				this.figure_handlebox.Visible = false;
			}
				
			if (plot_types_changed)
				this.UpdatePlotTypes();

			// update file list
			foreach (FileFilter filter in this.bg_filechooser.Filters)
			{
				this.bg_filechooser.RemoveFilter(filter);
			}
			foreach (FileTypeInfo type in this.FileTypes)
			{
				if (type.RwType != FileRwType.WriteOnly && !type.IsContainer)
					this.bg_filechooser.AddFilter(this.GetFileFilter(type));
			}
		}

		private void UpdatePlotTypes()
		{
			ListStore store = new ListStore(typeof(string), typeof(PlotTypeInfo), typeof(RadioMenuItem));
			CellRendererText text = new CellRendererText();
			
			this.plot_type_combo.Clear();
			this.plot_type_combo.PackStart(text, false);
			this.plot_type_combo.SetAttributes(text, "text", 0);
			this.plot_type_combo.Model = store;
			
			Menu plot_type_menu = new Menu();
			RadioMenuItem menu_group = null;
			
			foreach (PlotTypeInfo[] plot_types in this.plot_types.Values)
			{
				foreach (PlotTypeInfo plot_type in plot_types)
				{
					if (!plot_type.Active)
						continue;
					
					RadioMenuItem item;
					if (menu_group == null)
					{
						item = new RadioMenuItem(plot_type.Name);
						menu_group = item;
					}
					else
					{
						item = new RadioMenuItem(menu_group, plot_type.Name);
					}
					
					this.__update_plot_type_helper(item, plot_type);
					
					plot_type_menu.Append(item);
					store.AppendValues(plot_type.Name, plot_type, item);
				}
			}
			
			this.plot_type_item.Submenu = plot_type_menu;
			this.plot_type_item.ShowAll();
			
			this.PlotType = this.plot_types["quickstep"][0];
		}
		
		private void __update_plot_type_helper(RadioMenuItem item, PlotTypeInfo plot_type)
		{
			item.Activated += delegate(object o, EventArgs e) {
				RadioMenuItem r = o as RadioMenuItem;
				if (r.Active)
					this.PlotType = plot_type;
			};
		}
		
		private void InitializeThemes()
		{
			if (MainClass.OS != MainClass.OSType.Windows || !Directory.Exists("Themes"))
				return;
			
			string[] dirs = Directory.GetDirectories("Themes");
			if (dirs.Length < 1)
				return;
			
			this.themes_item.NoShowAll = false;
			
			List<string> themes = new List<string>();
			foreach (string dir in dirs)
			{
				themes.Add(Path.GetFileName(dir));
			}
			themes.Sort();
			themes.Insert(0, Catalog.GetString("System"));
			              
			Menu theme_menu = new Menu();
			RadioMenuItem menu_group = null;
			
			foreach (string theme in themes)
			{
				RadioMenuItem item;
				if (menu_group == null)
				{
					item = new RadioMenuItem(theme);
					menu_group = item;
				}
				else
				{
					item = new RadioMenuItem(menu_group, theme);
				}
				
				item.Activated += delegate(object sender, EventArgs e) {
					if (!this.initialized)
						return;
					RadioMenuItem r = sender as RadioMenuItem;
					if (!r.Active)
						return;
					string t = ((Label)r.Child).Text;
					if (t == Catalog.GetString("System"))
						Settings.Current.GtkTheme = "SYSTEM";
					else
						Settings.Current.GtkTheme = t;
					new InfoMessage(this.parent,
					                Catalog.GetString("In order to apply the new theme, please restart {0}"),
					                MainClass.ApplicationName);
				};
					
				theme_menu.Append(item);
				
				if (Settings.Current.GtkTheme == theme)
					item.Active = true;
			}

			this.themes_item.Submenu = theme_menu;
			this.themes_item.ShowAll();
		}

		internal void OnXMinSpinChanged(object o, System.EventArgs e)
		{
			SpinButton s = o as SpinButton;
			if (this.ScrolledPlot.Plot.ReverseXAxes)
				this.ScrolledPlot.XMax = s.Value;
			else
				this.ScrolledPlot.XMin = s.Value;
		}

		internal void OnXMaxSpinChanged(object o, System.EventArgs e)
		{
			SpinButton s = o as SpinButton;
			if (this.ScrolledPlot.Plot.ReverseXAxes)
				this.ScrolledPlot.XMin = s.Value;
			else
				this.ScrolledPlot.XMax = s.Value;
		}

		internal void OnYMinSpinChanged(object o, EventArgs e)
		{
			SpinButton s = o as SpinButton;
			this.ScrolledPlot.YMin = s.Value;
		}

		internal void OnYMaxSpinChanged(object o, EventArgs e)
		{
			SpinButton s = o as SpinButton;
			this.ScrolledPlot.YMax = s.Value;
		}
		
//		internal void OnRefreshButtonClicked(object o, System.EventArgs e)
//		{
//			this.UpdatePlot();
//		}

		internal void OnEditXConstraintsButtonToggled(object o, EventArgs e)
		{
			ToggleToolButton b = o as ToggleToolButton;
			if (b.Active)
			{
				this.x_constraints_item.NoShowAll = false;
				this.x_constraints_item.ShowAll();
				GLib.Timeout.Add(500, delegate {
					this.x_constraints_entry.HasFocus = true;
					return false;
				});
			}
			else
			{
				this.x_constraints_item.HideAll();
				this.x_constraints_item.NoShowAll = true;
				if (this.plot_info_list.Current.XConstraints != null)
				{
					this.plot_info_list.Current.XConstraints = null;
					this.UpdatePlot(this.plot_info_list.Current);
				}
			}
		}
		
		internal void OnXConstraintsFocusOut(object o, FocusOutEventArgs e)
		{
			if (!this.edit_x_constraints_button.Active)
				return;
			
			XConstraintsEntry entry = o as XConstraintsEntry;
			
			if (this.plot_info_list.Current.XConstraints.ToString() == entry.Text)
				return;
			
			this.plot_info_list.Current.XConstraints = DataSet.XConstraints.CreateFromString(entry.Text);
			if (this.plot_info_list.Current.XConstraints == null)
				return;
			
			Console.WriteLine("Setting X-Constraints '{0}' for figure '{1}'.", this.plot_info_list.Current.XConstraints.ToString(), this.plot_info_list.Current.Name);
			List<string> constraints = Settings.Current.XConstraints;
			string new_constraint = this.plot_info_list.Current.XConstraints.ToString();
			if (!constraints.Contains(new_constraint))
			    constraints.Add(new_constraint);
			Settings.Current.XConstraints = constraints;
			this.x_constraints_entry.UpdateCompletion();
			this.UpdatePlot(this.plot_info_list.Current);
			this.x_constraints_entry.SelectRegion(0, 0);
		}
		
		internal void OnZoomFitButtonClicked(object o, EventArgs e)
		{
			this.ScrolledPlot.Plot.FitView();
			this.ScrolledPlot.XZoom = 1.0;
			this.ScrolledPlot.YZoom = 1.0;
		}
		
		internal void OnZoomStandardButtonClicked(object o, System.EventArgs e)
		{
			this.ScrolledPlot.YMin = this.PlotType.StandardMin;
			this.ScrolledPlot.YMax = this.PlotType.StandardMax;
			this.ScrolledPlot.YZoom = 1.0;
		}
		
		internal void OnClearButtonClicked(object o, System.EventArgs e)
		{
			this.ClearPlot();
		}
		
		internal void OnMinimizeItemClicked(object o, EventArgs e)
		{
			this.parent.Hide();
			TrayIcon.Initialize();
			TrayIcon.Update();
		}
		
		internal void OnExitButtonClicked(object o, System.EventArgs e)
		{
			if (string.IsNullOrEmpty(MainClass.AutoPlugin))
				MainClass.Quit(false);
			else
				MainClass.MainWindow.Hide();
		}

		internal void OnOpenDirectoryClicked(object o, System.EventArgs e)
		{
			FileChooserDialog chooser = new QSFileChooserDialog(Catalog.GetString("Choose directory"),
				                                                this.parent,
			                                                    FileChooserAction.SelectFolder,
			                                                    Stock.Open,
			                                                    ResponseType.Ok,
			                                                    Stock.Cancel,
			                                                    ResponseType.Cancel);
			if (!string.IsNullOrEmpty(Settings.Current.OpenDirectoryPath))
				chooser.SetCurrentFolder(Settings.Current.OpenDirectoryPath);
			else
				chooser.SetCurrentFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
			
			ResponseType choice = (ResponseType)chooser.Run();
			if (choice == ResponseType.Ok)
			{
				chooser.Hide();

				this.AddFileTv(chooser.Filename);

				// switch property editor to directory mode? 
				//ScrolledFileTv tv = this.file_notebook.CurrentPageWidget as ScrolledFileTv;
				//if (tv != null)
				//	tv.SelectParentDir();

				List<string> paths = Settings.Current.DataBrowserPaths;
				paths.Add(chooser.Filename);
				Settings.Current.DataBrowserPaths = paths;

				Settings.Current.OpenDirectoryPath = chooser.CurrentFolder;
			}
			chooser.Destroy();
		}
		
		internal void OnOpenButtonClicked(object o, System.EventArgs e)
		{
			FileChooserDialog chooser = new QSFileChooserDialog(Catalog.GetString("Choose file to open"), 
				                                                this.parent, 
			                                                    FileChooserAction.Open,
			                                                    Stock.Open,
			                                                    ResponseType.Ok,
			                                                    Stock.Cancel,
			                                                    ResponseType.Cancel);
			foreach (FileTypeInfo type in this.FileTypes)
			{
				if (type.RwType != FileRwType.WriteOnly && !type.IsContainer)
					chooser.AddFilter(this.GetFileFilter(type));
			}
			foreach (FileTypeInfo type in this.FileTypes)
			{
				if (type.RwType != FileRwType.WriteOnly && type.IsContainer)
					chooser.AddFilter(this.GetFileFilter(type));
			}
			chooser.SelectMultiple = true;

			if (!string.IsNullOrEmpty(Settings.Current.OpenFilePath))
				chooser.SetCurrentFolder(Settings.Current.OpenFilePath);
			else
				chooser.SetCurrentFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));

			try
			{
				ResponseType choice = (ResponseType)chooser.Run();
				if (choice == ResponseType.Ok)
				{
					chooser.Hide();
					UserInterface.ProcessEvents_();

					FileTypeInfo file_type = this.GetFileTypeInfo(chooser.Filter, true, false);
//					if (chooser.Filenames.Length > 0)
//						this.current_spectra.AddHistoryEntry();

					bool first_iteration = true;
					for (int ix=0; ix < chooser.Filenames.Length; ++ix)
					{
						string file = chooser.Filenames[ix];

                        Console.WriteLine("Opening file: " + file);

						Spectrum[] spectra;
						List<MetaData> meta_data = null;
						
						if (file_type.IsContainer)
							spectra = file_type.ReadContainer(file, out meta_data);
						else
							spectra = new Spectrum[] { file_type.Read(file) };
						
						if (first_iteration)
						{
							this.plot_info_list.Current.CurrentSpectra.AddHistoryEntry();
							first_iteration = false;
						}
						
						for (int jx=0; jx < spectra.Length; ++jx)
						{
							this.AddSpectrum(spectra[jx], false, false, true);
						}
						this.ScrolledPlot.RestoreAnnotations(meta_data);

						this.ShowProgress((double)ix/(double)chooser.Filenames.Length);
					}
					this.HideProgress();
					this.ScrolledPlot.Plot.RequestUpdate();
					this.CurrentSpectra.NotifyChanges();

					if (this.PlotType.Interdependent)
						this.UpdateCurrentPlot();

					Settings.Current.OpenFilePath = chooser.CurrentFolder;
				}
			}
			catch (Exception ex)
			{
				new InfoMessage(this.parent, 
				                Catalog.GetString("Error while reading file: {0}"),
				                ex.Message);
			}
			finally
			{
				chooser.Destroy();
			}
		}
		
		internal void OnReopenItemActivated(object o, EventArgs e)
		{
			UserInterface.ProcessEvents_();
			for (int ix=0; ix < Settings.Current.ReopenPaths.Count; ++ix)
			{
				string path = Settings.Current.ReopenPaths[ix];
				this.ShowProgress((double)ix / (double)Settings.Current.ReopenPaths.Count);

				try
				{
					bool ignore_interdependence = ix < Settings.Current.ReopenPaths.Count-1;
					this.AddSpectrum(CSV.Read(path), false, false, ignore_interdependence);
				}
				catch (Exception ex)
				{
					new InfoMessage(this.parent,
					                Catalog.GetString("Cannot reopen file: {0}"),
					                ex.Message);
				}
			}
			this.CurrentSpectra.NotifyChanges();
			this.ScrolledPlot.Plot.RequestUpdate();
			this.HideProgress();
			this.reopen_item.Sensitive = false;
		}

		internal void OnSaveButtonClicked(object o, System.EventArgs e)
		{
			try
			{
				this.SetWatchCursor(null, null);
				this.ProcessEvents();
				this.StopAllStreams();
				this.SaveAll(this.plot_info_list.Current.CurrentSpectra, string.Empty, false);
				this.UpdateProperties();
			}
			finally
			{
				this.SetArrowCursor(null, null);
			}
		}
		
		internal void OnSaveContainerClicked(object o, EventArgs e)
		{
			try
			{
				this.SetWatchCursor(null, null);
				this.ProcessEvents();

				this.StopAllStreams();

				using (QSFileChooserDialog chooser = new QSFileChooserDialog(Catalog.GetString("Specify container file name to save spectra"), 
				                                                             this.parent,
				                                                             FileChooserAction.Save,
				                                                             Stock.Save,
				                                                             ResponseType.Ok,
				                                                             Stock.Cancel,
				                                                             ResponseType.Cancel)
				      )
				{
					foreach (FileTypeInfo type in this.FileTypes)
					{
						if (type.RwType != FileRwType.ReadOnly && type.IsContainer)
                            chooser.AddFilter(this.GetFileFilter(type), type.Extensions.First());
					}
					FileTypeInfo file_type = new CsvContainerFileTypeInfo();
					OutputCulture output_culture = Settings.Current.StandardOutputCulture;
					chooser._CurrentName  = Catalog.GetString("untitled_container");
					chooser.Filter = this.GetFileFilter(file_type);
					chooser.OutputCulture = output_culture;
				
					if (!string.IsNullOrEmpty(Settings.Current.ContainerSaveFilePath))
						chooser.SetCurrentFolder(Settings.Current.ContainerSaveFilePath);
					else
						chooser.SetCurrentFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
					
					chooser.DoOverwriteConfirmation = true;
				
					try
					{
						int choice = chooser._Run();
						file_type = this.GetFileTypeInfo(chooser.Filter, false, true);

						output_culture = chooser.OutputCulture;
					
						if (choice == (int)ResponseType.Ok)
						{
							chooser.Hide();
							file_type.WriteContainer(new List<Spectrum>(plot_info_list.Current.CurrentSpectra.Values),
							                         this.ScrolledPlot.CreateMetaData(),
							                         chooser.Filename,
							                         this.OutputCultureInfo(chooser.OutputCulture));
							Settings.Current.ContainerSaveFilePath = chooser.CurrentFolder;
						}
					}
					catch (Exception ex)
					{
						Console.WriteLine(ex);
						new InfoMessage(this.parent, 
						                Catalog.GetString("Error while saving spectrum container: {0}"),
						                ex.Message);
					}
					finally
					{
						chooser.Destroy();
					}
				}
			}
			finally
			{
				this.SetArrowCursor(null, null);
			}
		}
		
		public void SaveAll(ICurrentSpectra current_spectra, string first_fname, bool save_all)
		{
			bool anticipate = false;
			string last_fname = string.Empty;
			
			// we need a copy because the list can be changed within the loop
			CurrentSpectra spectra = new CurrentSpectra((CurrentSpectra)current_spectra);

			List<string> keys = new List<string>(spectra.Keys);
			keys.Sort();

			OutputCulture output_culture = this.StandardOutputCulture;
			FileTypeInfo file_type = new CsvFileTypeInfo();
			bool? cancel = null;

			for (int ix=0; ix < keys.Count; ++ix)
			{
				if (ix == keys.Count-1)
					cancel = false;
				
				string key = keys[ix];
				Spectrum spectrum = spectra[key];
				
				if (spectrum.IsPreview)
					continue;

				bool new_spectrum = false;
				if ((spectrum.SpectrumType == SpectrumType.Stream ||
				     spectrum.SpectrumType == SpectrumType.Single ||
				     spectrum.SpectrumType == SpectrumType.ProcessedFluidSpecimen ||
				     spectrum.SpectrumType == SpectrumType.ProcessedSolidSpecimen ||
				     spectrum.SpectrumType == SpectrumType.Unknown))
					new_spectrum = true;

				if (spectrum.FileInfo == null)
				{
					try
					{
						if (new_spectrum)
							UserInterface._SetCreator(spectrum);
						
						string fname;
						if (!string.IsNullOrEmpty(first_fname))
						{
							fname = first_fname;
							first_fname = string.Empty;
							anticipate = true;
						}
						else
						{
							fname = string.Empty;
							if (anticipate)
								fname = this.AnticipateFilename(last_fname);
							if (string.IsNullOrEmpty(fname))
								fname = this.GenerateFilename(spectrum);
						}
						
						if (save_all)
						{
							string fullname = Path.Combine(Settings.Current.SaveFilePath, fname);
                            if (!fullname.EndsWith("." + file_type.Extensions.First(), StringComparison.InvariantCulture))
                                fullname += "." + file_type.Extensions.First();
							
							bool do_write = true;
							if (File.Exists(fullname))
							{
								Dialog dialog = new OverwriteSpectrumDialog(this.parent, Path.GetFileName(fullname));
								ResponseType choice = (ResponseType)dialog.Run();
								dialog.Destroy();
								do_write = (choice == ResponseType.Yes);
							}
							
							if (do_write)
							{
								file_type.Write(spectrum, fullname, this.OutputCultureInfo(output_culture));
								spectrum.FileInfo = new FileInfo(fullname);
								last_fname = fname;
								continue;
							}
						}

						save_all = keys.Count > 1;
						bool again = false;
						string current_fname = fname;
						do 
						{
							last_fname = this.SaveNewSpectrum(spectrum, current_fname, ref file_type, ref save_all, ref again, ref cancel, ref output_culture);
							current_fname = last_fname;
						}
						while (again);

						if (cancel == true)
							break;

						if (fname != last_fname)
								anticipate = true;
					}
					catch (NullReferenceException ex)
					{
						throw ex;
					}
					catch (Exception ex)
					{
						Console.WriteLine(ex.ToString());
						new InfoMessage(this.parent,
						                Catalog.GetString("Cannot save spectrum '{0}': {1}"),
						                spectrum.Label, ex.Message);
					}
				}
				else if (spectrum.SpectrumType != SpectrumType.QuickStream)
				{
					try
					{
						file_type.Write(spectrum, spectrum.FileInfo.FullName, spectrum.CultureInfo);
					}
					catch (System.Exception ex)
					{
						Console.WriteLine(ex.ToString());
						new InfoMessage(this.parent,
						                Catalog.GetString("Cannot save spectrum '{0}' to file '{1}': {2}"),
						                spectrum.Label, spectrum.Id.Remove(0, 12), ex.Message);
					}
				}
			}
		}
		
		internal void OnPrintButtonClicked(object o, System.EventArgs e)
		{
			new Printer(this.parent, this.ScrolledPlot.Plot);
		}
		
		internal void OnSendCvscButtonClicked(object o, EventArgs e)
		{
			UserInterface.ProcessEvents_();
			try
			{
				string temp_dir  = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
				Directory.CreateDirectory(temp_dir);
				string temp_file = Path.Combine(temp_dir, Catalog.GetString("untitled_container") + ".csvc");
				
				CSV.WriteContainer(new List<Spectrum>(this.plot_info_list.Current.CurrentSpectra.Values),
                                   temp_file,
                                   this.OutputCultureInfo(this.StandardOutputCulture));
				
				MailClient.OpenWithAttachment(temp_file);
				
				GLib.Timeout.Add(60000, delegate {
					try
					{
						Directory.Delete(temp_dir, true);
					}
					catch {}
					return false;
				});
			}
			catch (Exception ex)
			{
				new InfoMessage(this.parent, Catalog.GetString("Cannot send CSVC file: {0}"), ex.Message);
			}
		}
		
		internal void OnSendPngButtonClicked(object o, EventArgs e)
		{
			UserInterface.ProcessEvents_();
			try
			{
				string temp_dir  = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
				Directory.CreateDirectory(temp_dir);
				string temp_file = Path.Combine(temp_dir, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".png");
				
				System.Drawing.Bitmap bmp = this.ScrolledPlot.Plot.GetBitmap(300f, 300f);
				bmp.Save(temp_file, System.Drawing.Imaging.ImageFormat.Png);
				
				MailClient.OpenWithAttachment(temp_file);
				
				GLib.Timeout.Add(60000, delegate {
					try
					{
						Directory.Delete(temp_dir, true);
					}
					catch {}
					return false;
				});
			}
			catch (Exception ex)
			{
				new InfoMessage(this.parent, Catalog.GetString("Cannot send PNG file: {0}"), ex.Message);
			}
		}
		
		internal void OnCopyButtonClicked(object o, System.EventArgs e)
		{
			if (MainWindow.Focus is TextView)
			{
				TextView text = MainWindow.Focus as TextView;
				text.Buffer.CopyClipboard(Clipboard.Get(Gdk.Selection.Clipboard));
				return;
			}
			else if (MainWindow.Focus is Entry)
			{
				Entry entry = MainWindow.Focus as Entry;
				entry.CopyClipboard();
				return;
			}
			this.CopyToClipboard(this.ScrolledPlot.Plot, true);
		}
		
		internal void OnCopyPlotDataItemClicked(object o, System.EventArgs e)
		{
			this.CopyToClipboard(this.ScrolledPlot.Plot, false);
		}
		
		internal void OnAnnotationSettingsItemClicked(object o, EventArgs e)
		{
			new AnnotationSettingsDialog(this.parent);
		}
		
		internal void OnInsertTextItemClicked(object o, EventArgs e)
		{
			this.CancelAnnotations();
			
			Dialog dialog = new Dialog(Catalog.GetString("Text annotation"), this.parent,
			                           DialogFlags.Modal,
			                           Stock.Ok,     ResponseType.Ok,
			                           Stock.Cancel, ResponseType.Cancel);
			
			dialog.Default = dialog.ActionArea.Children[1];
			dialog.HasSeparator = true;
			dialog.Resizable    = false;
			
			Alignment align0 = new Alignment(0f, 0f, 0f, 0f);
			Alignment align1 = new Alignment(0f, 0.5f, 0f, 0f);
			Alignment align2 = new Alignment(0f, 0.5f, 0f, 0f);
			Alignment align3 = new Alignment(1f, 0.5f, 0f, 0f);
			Alignment align4 = new Alignment(1f, 0.5f, 0f, 0f);
			
			Label label1 = new Label(Catalog.GetString("Insert Text:"));
			Label label2 = new Label(Catalog.GetString("Font settings:"));
			TextView text  = new TextView();
			FontButton  fbutton = new FontButton();
			ColorButton cbutton = new ColorButton(new Gdk.Color(0, 0, 0));
			
			if (!string.IsNullOrEmpty(Settings.Current.AnnotationTextDefaultFont))
				fbutton.SetFontName(Settings.Current.AnnotationTextDefaultFont);
			
			cbutton.Color = UserInterface.GdkColor(Settings.Current.AnnotationTextDefaultColor);
			
			text.WidthRequest  = 200;
			text.HeightRequest = 80;
			text.AcceptsTab = false;
//			text.ActivatesDefault = true;
//			entry.WidthChars = 35;
			
			align1.Add(label1);
			align2.Add(label2);
			align3.Add(fbutton);
			align4.Add(cbutton);
			
			Table table = new Table(3, 2, false);
			table.ColumnSpacing = 10;
			table.RowSpacing    = 5;
			table.Attach(align1, 0, 1, 0, 1);
			table.Attach(text,   1, 3, 0, 1);
			table.Attach(align2, 0, 1, 1, 2);
			table.Attach(align3, 1, 2, 1, 2);
			table.Attach(align4, 2, 3, 1, 2, AttachOptions.Fill, AttachOptions.Fill, 0, 0);

			align0.Add(table);
			align0.BorderWidth = 5;
			dialog.VBox.PackStart(align0);
			dialog.ShowAll();
			
			ResponseType choice = (ResponseType)dialog.Run();
			string s = text.Buffer.Text;
			System.Drawing.Font  font  = UserInterface.GetFontFromString(fbutton.FontName);
			System.Drawing.Color color = UserInterface.DrawingColor(cbutton.Color);
			
			dialog.Destroy();
			
			if (choice != ResponseType.Ok || string.IsNullOrEmpty(s))
				return;
			
			int x, y;
			this.ScrolledPlot.GetPointer(out x, out y);
			TextAnnotation ta = new TextAnnotation(this.ScrolledPlot.Plot, s, font, color);
			ta.X = this.ScrolledPlot.Plot.GetWorldXCoord(x);
			ta.Y = this.ScrolledPlot.Plot.GetWorldYCoord(y);
			this.ScrolledPlot.Plot.Annotations.Add(ta);
			this.ScrolledPlot.Plot.AsyncRefresh(true);
		}
		
		internal void OnInsertLineItemClicked(object o, EventArgs e)
		{
			this.CancelAnnotations();

			LineAnnotation a = new LineAnnotation(this.ScrolledPlot.Plot,
			                                      Settings.Current.AnnotationLineWidth,
			                                      Settings.Current.AnnotationLineColor,
			                                      Settings.Current.AnnotationLineStyle);
			this.ScrolledPlot.Plot.Annotations.Add(a);
		}
		
		internal void OnInsertArrowItemClicked(object o, EventArgs e)
		{
			this.CancelAnnotations();

			ArrowAnnotation a = new ArrowAnnotation(this.ScrolledPlot.Plot,
			                                        Settings.Current.AnnotationArrowLineWidth,
			                                        Settings.Current.AnnotationArrowColor,
			                                        Settings.Current.AnnotationArrowLineStyle,
			                                        Settings.Current.AnnotationArrowCapStyle);
			this.ScrolledPlot.Plot.Annotations.Add(a);
		}
		
		internal void OnInsertDoublearrowItemClicked(object o, EventArgs e)
		{
			this.CancelAnnotations();

			DoubleArrowAnnotation a = new DoubleArrowAnnotation(this.ScrolledPlot.Plot,
			                                                    Settings.Current.AnnotationArrowLineWidth,
			                                                    Settings.Current.AnnotationArrowColor,
			                                                    Settings.Current.AnnotationArrowLineStyle,
			                                                    Settings.Current.AnnotationArrowCapStyle);
			this.ScrolledPlot.Plot.Annotations.Add(a);
		}

		internal void OnInsertRectangleItemClicked(object o, EventArgs e)
		{
			this.CancelAnnotations();

			RectangleAnnotation a = new RectangleAnnotation(this.ScrolledPlot.Plot,
			                                                Settings.Current.AnnotationLineWidth,
			                                                Settings.Current.AnnotationLineColor,
			                                                Settings.Current.AnnotationLineStyle);
			this.ScrolledPlot.Plot.Annotations.Add(a);
		}
		
		internal void OnInsertEllipseItemClicked(object o, EventArgs e)
		{
			this.CancelAnnotations();

			EllipseAnnotation a = new EllipseAnnotation(this.ScrolledPlot.Plot,
			                                            Settings.Current.AnnotationLineWidth,
			                                            Settings.Current.AnnotationLineColor,
			                                            Settings.Current.AnnotationLineStyle);
			this.ScrolledPlot.Plot.Annotations.Add(a);
		}
		
		internal void OnClearAnnotationsItemClicked(object o, EventArgs e)
		{
			this.ScrolledPlot.Plot.Annotations.Clear();
			this.ScrolledPlot.Plot.AsyncRefresh(true);
			this.UIPlotControlsSensitive(true);
		}
		
		private void ClipboardGetFunc(Clipboard clipboard, SelectionData data, uint info)
		{
			Console.WriteLine("External application getting clipboard data");


            switch (info)
			{
				
			case 0:
				if (this.clipboard_pixbuf_data != null)
					data.SetPixbuf(this.clipboard_pixbuf_data);
				break;

			case 1:
				data.Text = this.clipboard_csv_data;
				break;

            case 2:
                data.Set(Gdk.Atom.Intern("text/plain;charset=utf-8", false), 8, Encoding.UTF8.GetBytes(this.clipboard_csv_data));
                break;

            }
        }
		
		private void ClipboardClearFunc(Clipboard clipboard)
		{
			Console.WriteLine("Clearing clipboard data");
//			this.clipboard_csv_data = string.Empty;
//			this.clipboard_pixbuf_data = null;
//			this.clipboard_data.Dispose();
//			this.clipboard_data = null;
		}
		
		internal void OnExportButtonClicked(object o, System.EventArgs e)
		{
			QSFileChooserDialog chooser = new QSFileChooserDialog(Catalog.GetString("Specify file name to export a figure"), 
				                                                  this.parent, 
			                                                      FileChooserAction.Save,
			                                                      Stock.Save,
			                                                      ResponseType.Ok,
			                                                      Stock.Cancel,
			                                                      ResponseType.Cancel);
			FileFilter filter = new FileFilter();
			filter.Name = Catalog.GetString("PNG image");
			filter.AddPattern("*.png");
			filter.Data.Add("type", "png");
			chooser.AddFilter(filter);
			filter = new FileFilter();
			filter.Name = Catalog.GetString("EMF metafile");
			filter.AddPattern("*.emf");
			filter.Data.Add("type", "emf");
			chooser.AddFilter(filter);
			filter = new FileFilter();
			filter.Name = Catalog.GetString("BMP image");
			filter.AddPattern("*.bmp");
			filter.Data.Add("type", "bmp");
			chooser.AddFilter(filter);
			filter = new FileFilter();
			filter.Name = Catalog.GetString("GIF image");
			filter.AddPattern("*.gif");
			filter.Data.Add("type", "gif");
			chooser.AddFilter(filter);
			filter = new FileFilter();
			filter.Name = Catalog.GetString("JPG image");
			filter.AddPattern("*.jpg");
			filter.Data.Add("type", "jpg");
			chooser.AddFilter(filter);
			filter = new FileFilter();
			filter.Name = Catalog.GetString("Comma separated values");
			filter.AddPattern("*.csv");
			filter.Data.Add("type", "csv");
			chooser.AddFilter(filter);
			chooser.DoOverwriteConfirmation = true;

			chooser.CurrentName = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
			
			if (!string.IsNullOrEmpty(Settings.Current.ExportFilePath))
				chooser.SetCurrentFolder(Settings.Current.ExportFilePath);
			else
				chooser.SetCurrentFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));

			try
			{
				ResponseType choice = (ResponseType)chooser.Run();
				
				if (choice == ResponseType.Ok)
				{
					chooser.Hide();
					UserInterface.ProcessEvents_();
					
					System.Drawing.Bitmap bmp = this.ScrolledPlot.Plot.GetBitmap(300f, 300f);
					
					switch ((string)chooser.Filter.Data["type"])
					{
						
					case "png":
						if (chooser.Filename.ToLower().EndsWith(".png"))
							bmp.Save(chooser.Filename, System.Drawing.Imaging.ImageFormat.Png);
						else
							bmp.Save(chooser.Filename + ".png", System.Drawing.Imaging.ImageFormat.Png);
						break;
					
					case "emf":
//						string fname;
//						if (chooser.Filename.EndsWith(".emf"))
//							fname = chooser.Filename;
//						else
//							fname = chooser.Filename + ".emf";
//						
//						System.Drawing.Graphics g = this.ScrolledPlot.Plot.CreateGraphics();
//						IntPtr hdc = g.GetHdc();
//						System.Drawing.Imaging.Metafile mf;
//						mf = new System.Drawing.Imaging.Metafile(fname, hdc);
//						System.Drawing.Graphics mg = System.Drawing.Graphics.FromImage(mf);
//						this.ScrolledPlot.Plot.Draw(mg, this.ScrolledPlot.Plot.Bounds);
//						g.ReleaseHdc(hdc);
						if (chooser.Filename.ToLower().EndsWith(".emf"))
							bmp.Save(chooser.Filename, System.Drawing.Imaging.ImageFormat.Emf);
						else
							bmp.Save(chooser.Filename + ".emf", System.Drawing.Imaging.ImageFormat.Emf);
						break;
						
					case "bmp":
						if (chooser.Filename.ToLower().EndsWith(".bmp"))
							bmp.Save(chooser.Filename, System.Drawing.Imaging.ImageFormat.Bmp);
						else
							bmp.Save(chooser.Filename + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
						break;
						
					case "gif":
						if (chooser.Filename.ToLower().EndsWith(".gif"))
							bmp.Save(chooser.Filename, System.Drawing.Imaging.ImageFormat.Gif);
						else
							bmp.Save(chooser.Filename + ".gif", System.Drawing.Imaging.ImageFormat.Gif);
						break;
						
					case "jpg":
						if (chooser.Filename.ToLower().EndsWith(".jpg"))
							bmp.Save(chooser.Filename, System.Drawing.Imaging.ImageFormat.Jpeg);
						else
							bmp.Save(chooser.Filename + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
						break;
						
					case "csv":
						string fname = chooser.Filename;
						if (!fname.ToLower().EndsWith(".csv"))
							fname += ".csv";
						List<DataSet> data_sets = new List<DataSet>(this.ScrolledPlot.Plot.DataSets.Values);
//						foreach (Spectrum spectrum in this.CurrentSpectra.Values)
//						{
//							data_sets.Add(this.PlotType.ComputeDataSet(spectrum));
//						}
						List<string> headers = new List<string>();
						headers.Add(string.Empty);
						foreach (DataSet ds in this.ScrolledPlot.Plot.DataSets.Values)
						{
							headers.Add(ds.Label);
						}
						switch (Settings.Current.AxisType)
						{
							
						case AxisType.Wavelength:
							headers[0] = Catalog.GetString("Wavelength / nm");
							CSV.Write(headers, data_sets, 1.0, fname, this.OutputCultureInfo(chooser.OutputCulture));
							break;
							
						case AxisType.Wavecount:
							headers[0] = Catalog.GetString("Wavenumber / cm^-1");
							CSV.Write(headers, data_sets, 5.0, fname, this.OutputCultureInfo(chooser.OutputCulture));
							break;
						}
						break;
						
					default:
						throw new Exception(Catalog.GetString("Cannot export figure: Unknown export format."));
					}
					
//					Gdk.Color bg_color = this.ScrolledPlot.Plot.Style.Background(StateType.Normal);
//					this.ScrolledPlot.Plot.ModifyBg(StateType.Normal, new Gdk.Color(255, 255, 255));
//					Cairo.Surface surface = this.ScrolledPlot.Plot.GetCairoSurface();
//					this.parent.KeepAbove = true;
//					UserInterface.ProcessEvents();
//
//					surface.WriteToPng(chooser.Filename);
//
//					this.parent.KeepAbove = false;
//					this.ScrolledPlot.Plot.ModifyBg(StateType.Normal, bg_color);
//					
					Settings.Current.ExportFilePath = chooser.CurrentFolder;
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("Exception while exporting figure: " + ex.ToString());
				new InfoMessage(this.parent, 
				                Catalog.GetString("Error while exporting figure: {0}"),
				                ex.Message);
			}
			finally
			{
				chooser.Destroy();
			}
		}
		
		internal void OnNewTabItemClicked(object o, EventArgs e)
		{
			this.AddPlotTab();
		}

		internal void OnCloseTabItemClicked(object o, EventArgs e)
		{
			this.RemovePlotTab(this.plot_info_list.Current);
		}
		
		internal void OnSetUnchangedBackgroundItemClicked(object o, EventArgs e)
		{
			this.plot_info_list.BackgroundType = BackgroundType.Unchanged;
			this.plot_info_list.Background = this.plot_info_list.Current;
			this.plot_tv.UpdateFigureNames();
			this.UpdateFigureControls();
		}
		
		internal void OnSetGrayscaledBackgroundItemClicked(object o, EventArgs e)
		{
			this.plot_info_list.BackgroundType = BackgroundType.Grayscaled;
			this.plot_info_list.Background = this.plot_info_list.Current;
			this.plot_tv.UpdateFigureNames();
			this.UpdateFigureControls();
		}
		
		internal void OnSetDashedBackgroundItemClicked(object o, EventArgs e)
		{
			this.plot_info_list.BackgroundType = BackgroundType.Dashed;
			this.plot_info_list.Background = this.plot_info_list.Current;
			this.plot_tv.UpdateFigureNames();
			this.UpdateFigureControls();
		}

		internal void OnClearBackgroundItemClicked(object o, EventArgs e)
		{
			this.plot_info_list.Background = null;
			this.ScrolledPlot.Plot.RequestUpdate();
			this.plot_tv.UpdateFigureNames();
			this.lock_axes_item.Active = false;
			this.UpdateFigureControls();
		}
		
		internal void OnSyncAxesItemClicked(object o, EventArgs e)
		{
			this.plot_info_list.Current.ScrolledPlot.Plot.SyncAxes();
		}
		
		internal void OnLockAxesItemToggled(object o, EventArgs e)
		{
			CheckMenuItem c = o as CheckMenuItem;
			this.ScrolledPlot.Plot.LockAxes = c.Active;
			this.SetLockAxesImage(c.Active);
		}
		
		private void SetLockAxesImage(bool val)
		{
			if (val)
			{
				this.lock_axes_image.Stock = "hiperscan.locked";
				this.lock_axes_image.TooltipText = Catalog.GetString("Axes locked");
			}
			else
			{
				this.lock_axes_image.Stock = "hiperscan.unlocked";
				this.lock_axes_image.TooltipText = Catalog.GetString("Axes unlocked");
			}
		}

		internal void OnStartButtonClicked(object o, System.EventArgs e)
		{
			this.CheckForChangedDeviceProperties();
			if (this.active_devices.Count > 0)
				this.plot_info_list.Current.CurrentSpectra.AddHistoryEntry();
			
			foreach (Device dev in this.active_devices)
				this.StartStream(dev);
		}

		internal void OnQuickstreamButtonClicked(object o, System.EventArgs e)
		{
			this.CheckForChangedDeviceProperties();
			foreach (Device dev in this.active_devices)
				this.StartQuickStream(dev);
		}
		
		internal void OnStopButtonClicked(object o, System.EventArgs e)
		{
			foreach (Device dev in this.active_devices.Connected)
				this.StopStream(dev);
		}

		internal void OnSingleButtonClicked(object o, System.EventArgs e)
		{
			this.CheckForChangedDeviceProperties();
			foreach (Device dev in this.active_devices.Connected)
				this.StartSingle(dev);
		}
		
		internal void OnShareDeviceClicked(object o, EventArgs e)
		{
			this.CheckForChangedDeviceProperties();
			new SharedDevicesManager(this.DeviceList);
		}
		
		internal void OnRefreshDeviceListClicked(object o, EventArgs e)
		{
			this.DeviceList.ResetBlacklist();
			if (!this.DeviceList.AutoUpdate)
				this.DeviceList.Update();
		}
		
		internal void OnConnectRemoteDeviceClicked(object o, EventArgs e)
		{
			this.ConnectRemoteDevice();
		}
		
		internal void OnDisconnectRemoteDeviceClicked(object o, EventArgs e)
		{
			foreach (Device dev in this.active_devices)
			{
				if (dev.Info.IsRemote)
					this.DisconnectRemoteDevice(dev);
			}
		}

		internal void OnUndoButtonClicked(object o, System.EventArgs e)
		{
			this.plot_info_list.Current.CurrentSpectra.Undo();
			this.UpdatePlot(this.plot_info_list.Current);
		}
		
		internal void OnRedoButtonClicked(object o, System.EventArgs e)
		{
			this.plot_info_list.Current.CurrentSpectra.Redo();
			this.UpdatePlot(this.plot_info_list.Current);
		}
		
		private void OnFirstEntryReached(CurrentSpectra current_spectra)
		{
			if (current_spectra.PlotInfo != this.plot_info_list.Current)
				return;
			this.undo_item.Sensitive   = false;
			this.undo_button.Sensitive = false;
		}

		private void OnLastEntryReached(CurrentSpectra current_spectra)
		{
			if (current_spectra.PlotInfo != this.plot_info_list.Current)
				return;
			this.redo_item.Sensitive   = false;
			this.redo_button.Sensitive = false;
		}
		
		private void OnUndoPossible(CurrentSpectra current_spectra)
		{
			if (current_spectra.PlotInfo != this.plot_info_list.Current)
				return;
			bool val = this.device_list.AllIdleOrDisconnected;
			this.undo_item.Sensitive   = val;
			this.undo_button.Sensitive = val;
		}

		private void OnRedoPossible(CurrentSpectra current_spectra)
		{
			if (current_spectra.PlotInfo != this.plot_info_list.Current)
				return;
			bool val = this.device_list.AllIdleOrDisconnected;
			this.redo_item.Sensitive   = val;
			this.redo_button.Sensitive = val;
		}

		internal void OnDefaultOutputCultureComboChanged(object o, System.EventArgs e)
		{
			ComboBox c = o as ComboBox;
			this.StandardOutputCulture = (OutputCulture)c.Active;
		}


		private static volatile bool __update_on_plot_type_combo_change = true;
		internal void OnPlotTypeComboChanged(object o, System.EventArgs e)
		{
			ComboBox c = o as ComboBox;
			TreeIter iter;
			
			if (c.Active == -1 || !c.GetActiveIter(out iter))
			{
				this.plot_info_list.Current.PlotType = new UndefinedPlotTypeInfo();
				return;
			}

			// FIXME: zu kompliziert Menu->PlotType->Combo
//			this.PlotType = (PlotTypeInfo)c.Model.GetValue(iter, 1);
			RadioMenuItem item = (RadioMenuItem)c.Model.GetValue(iter, 2);
			item.Active = true;

			if (__update_on_plot_type_combo_change)
				this.UpdatePlot(this.plot_info_list.Current);

			if (this.active_devices != null && this.PlotType.NeedAbsorbance)
			{
				foreach (Device dev in this.active_devices)
				{
					if (!dev.IsConnected)
						continue;

					if (!dev.CurrentConfig.HasBackgroundSpectrum || 
					    dev.CurrentConfig.DarkIntensity.Intensity == 0.0)
						this.bg_message_is_pending = true;
				}
			}
			
			if (this.bg_message_is_pending)
			{
				new InfoMessage(this.parent,
				                Catalog.GetString("Cannot display one or more spectrum sources. " +
				                                  "Please specify background spectrum and " +
				                                  "dark intensity to solve this problem.")
				                );
				this.bg_message_is_pending = false;
			}
		}
		
		internal void OnStandardToolbarItemToggled(object o, System.EventArgs e)
		{
			CheckMenuItem i = o as CheckMenuItem;
			this.UpdatePluginInfos();
			Settings.Current.StandardToolbarVisible = i.Active;
		}

		internal void OnFigureToolbarItemToggled(object o, System.EventArgs e)
		{
			CheckMenuItem i = o as CheckMenuItem;
			this.UpdatePluginInfos();
			Settings.Current.FigureToolbarVisible = i.Active;
		}

		internal void OnExtensionsToolbarItemToggled(object o, System.EventArgs e)
		{
			CheckMenuItem i = o as CheckMenuItem;
			this.UpdatePluginInfos();
			Settings.Current.ExtensionsToolbarVisible = i.Active;
		}

		internal void OnDataSourcesButtonToggled(object o, System.EventArgs e)
		{
			ToggleToolButton b = o as ToggleToolButton;
			
			if (b.Active)
			{
				this.data_sources_frame.NoShowAll = false;
				this.data_sources_frame.ShowAll();
			}
			else
			{
				this.data_sources_frame.Visible = false;
				this.data_sources_frame.NoShowAll = true;
			}
				
			this.data_sources_item.Active       = b.Active;
			Settings.Current.DataSourcesVisible = b.Active;
		}
		
		internal void OnDataSourcesItemToggled(object o, System.EventArgs e)
		{
			CheckMenuItem c = o as CheckMenuItem;
			this.data_sources_button.Active = c.Active;
		}
		
		internal void OnPropertyEditorButtonToggled(object o, System.EventArgs e)
		{
			ToggleToolButton b = o as ToggleToolButton;
			
			if (b.Active)
			{
				this.property_handlebox.NoShowAll = false;
				this.property_handlebox.ShowAll();
			}
			else
			{
				this.property_handlebox.Visible = false;
				this.property_handlebox.NoShowAll = true;
			}

			this.properties_item.Active            = b.Active;
			Settings.Current.PropertyEditorVisible = b.Active;
		}
		
		internal void OnPlotBrowserItemToggled(object o, System.EventArgs e)
		{
			CheckMenuItem c = o as CheckMenuItem;
			this.plot_browser_button.Active = c.Active;
		}

		internal void OnPropertyEditorItemToggled(object o, System.EventArgs e)
		{
			CheckMenuItem c = o as CheckMenuItem;
			this.property_editor_button.Active = c.Active;
		}
		
		internal void OnPlotBrowserButtonToggled(object o, System.EventArgs e)
		{
			ToggleToolButton b = o as ToggleToolButton;
			
			if (b.Active)
			{
				this.plot_browser_frame.NoShowAll = false;
				this.plot_browser_frame.ShowAll();
			}
			else
			{
				this.plot_browser_frame.Visible = false;
				this.plot_browser_frame.NoShowAll = true;
			}
			
			this.ScrolledPlot.Plot.LegendVisible = !b.Active || this.legend_checkbutton.Active;

			this.plot_browser_item.Active = b.Active;
			Settings.Current.PlotBrowserVisible = b.Active;
		}
		
		internal void OnLegendCheckbuttonToggled(object o, EventArgs e)
		{
			CheckButton cb = o as CheckButton;
			UserInterface.Settings.Current.AlwaysShowLegend = cb.Active;
			if (this.plot_info_list.Current != null)
				this.ScrolledPlot.Plot.LegendVisible = !this.plot_browser_button.Active || cb.Active;
		}
		
		internal void OnZoomInButtonClicked(object o, System.EventArgs e)
		{
			this.ScrolledPlot.ZoomIn();
		}

		internal void OnZoomOutButtonClicked(object o, System.EventArgs e)
		{
			this.ScrolledPlot.ZoomOut();
		}
		
		internal void OnEnglishItemToggled(object o, System.EventArgs e)
		{
			RadioMenuItem r = o as RadioMenuItem;
			if (r.Active)
				this.StandardOutputCulture = OutputCulture.English;
		}
		
		internal void OnGermanItemToggled(object o, System.EventArgs e)
		{
			RadioMenuItem r = o as RadioMenuItem;
			if (r.Active)
				this.StandardOutputCulture = OutputCulture.German;
		}
		
		internal void OnSystemItemToggled(object o, System.EventArgs e)
		{
			RadioMenuItem r = o as RadioMenuItem;
			if (r.Active)
				this.StandardOutputCulture = OutputCulture.System;
		}

		internal void OnWavelengthItemToggled(object o, System.EventArgs e)
		{
			RadioMenuItem r = o as RadioMenuItem;
			if (r.Active)
			{
				Settings.Current.AxisType = AxisType.Wavelength;
				foreach (PlotInfo pi in this.plot_info_list.Values)
				{
					pi.ScrolledPlot.Plot.ReverseXAxes = false;
					this.UpdatePlot(pi);
				}
			}
		}

		internal void OnWavecountItemToggled(object o, System.EventArgs e)
		{
			RadioMenuItem r = o as RadioMenuItem;
			if (r.Active)
			{
				Settings.Current.AxisType = AxisType.Wavecount;
				foreach (PlotInfo pi in this.plot_info_list.Values)
				{
					pi.ScrolledPlot.Plot.ReverseXAxes = true;
					this.UpdatePlot(pi);
				}
			}
		}

		internal void OnHelpButtonClicked(object o, EventArgs e)
		{
			string url = System.AppDomain.CurrentDomain.BaseDirectory.Replace("\\", "/");
			
			if (!url.EndsWith("/"))
				url += "/";
			
			this.ShowURL("file://" + url + "manual.pdf");
		}
		
		internal void OnAboutButtonClicked(object o, EventArgs e)
		{
			AboutDialog dialog = new AboutDialog();
			
			dialog.TransientFor = this.parent;
			dialog.Parent = this.parent;
			dialog.ProgramName = MainClass.ApplicationName;
			dialog.Version = MainClass.Assembly.GetName().Version.ToString();
			dialog.Comments = (MainClass.Assembly.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false)[0]
			                   as AssemblyDescriptionAttribute).Description	+ MainClass.InfoExtension;
		
			string build_date = string.Empty;
			if (!string.IsNullOrEmpty(MainClass.BuildDate))
				build_date = "\n" + Catalog.GetString("Build date:") + " " + MainClass.BuildDate;
			dialog.Copyright = (MainClass.Assembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false)[0]
			                    as AssemblyCopyrightAttribute).Copyright + build_date;
			
			
			dialog.License = Catalog.GetString(MainClass.License);
			dialog.Authors = MainClass.Authors;
			dialog.Website = "http://www.hiperscan.com";
			dialog.Logo    = MainClass.QuickStepIcons[4];
			
			Gdk.Pixbuf[] icons = new Gdk.Pixbuf[5];
			icons[0] = dialog.RenderIcon(Stock.About, IconSize.Menu,         string.Empty);
			icons[1] = dialog.RenderIcon(Stock.About, IconSize.SmallToolbar, string.Empty);
			icons[2] = dialog.RenderIcon(Stock.About, IconSize.LargeToolbar, string.Empty);
			icons[3] = dialog.RenderIcon(Stock.About, IconSize.Button,       string.Empty);
			icons[4] = dialog.RenderIcon(Stock.About, IconSize.Dialog,       string.Empty);
			dialog.IconList = icons;
			dialog.WindowPosition = WindowPosition.Center;
			
			dialog.Run();
			dialog.Destroy();
		}
		
		internal void OnPlotTvSaveClicked(object o, EventArgs e)
		{
			foreach (Spectrum spectrum in this.plot_tv.GetSelectedSpectra())
			{
				if (spectrum.IsPreview)
					continue;
				
				this.SaveNewSpectrum(spectrum, this.GenerateFilename(spectrum));
			}
			this.UpdateProperties();
		}
		
		internal void OnPlotTvCopyClicked(object o, EventArgs e)
		{
			IPlotEngine plot = new NPlotEngine((NPlotEngine)this.ScrolledPlot.Plot);
			List<Spectrum> selected_spectra = this.plot_tv.GetSelectedSpectra();
			
			if (selected_spectra.Count == 0)
				return;
			
			List<string> selected_ids = new List<string>();
			foreach (Spectrum spectrum in selected_spectra)
			{
				Console.WriteLine("Copy selected to clipboard: " + spectrum.Id);
				selected_ids.Add(spectrum.Id);
			}
			
			List<string> ids = new List<string>(plot.DataSets.Keys);
			foreach (string id in ids)
			{
				if (!selected_ids.Contains(id))
					plot.DataSets.Remove(id);
			}
			plot.ProcessChanges();
			
			this.CopyToClipboard(plot, false);
		}
		
		internal void OnPlotTvAutoColorClicked(object o, EventArgs e)
		{
			this.plot_tv.AutoColorSelected();
		}
		
		internal void OnPlotTvDeleteClicked(object o, EventArgs e)
		{
			this.plot_tv.DeleteSelected();
		}
		
		internal void OnPlotTvAddClicked(object o, EventArgs e)
		{
			this.plot_tv.AddSelected();
		}
		
		internal void OnPlotTvRemoveClicked(object o, EventArgs e)
		{
			this.plot_tv.RemoveSelected();
		}
		
		internal void OnPlotTvMoveUpClicked(object o, EventArgs e)
		{
			this.plot_tv.MoveSelectedUp();
		}
		
		internal void OnPlotTvMoveDownClicked(object o, EventArgs e)
		{
			this.plot_tv.MoveSelectedDown();
		}
		
		internal void OnLockAxesImageButtonPressed(object o, ButtonPressEventArgs e)
		{
			if (!this.lock_axes_image.Sensitive)
				return;
			
			if (e.Event.Button == 1 && e.Event.Type == Gdk.EventType.ButtonPress)
				this.lock_axes_item.Toggle();
		}
		
		
		public class XConstraintsEntry : Gtk.Entry
		{
			public class XConstraintsCompletion : Gtk.EntryCompletion
			{
				public event EventHandler Selected;
				
				
				public XConstraintsCompletion() : base()
				{
				}
				
				protected override bool OnMatchSelected (TreeModel model, TreeIter iter)
				{
					if (this.Selected != null)
						this.Selected(this, EventArgs.Empty);
					
					return base.OnMatchSelected (model, iter);
				}
			}
			
			public event EventHandler ReturnPressed;
			
			private Gdk.Color? standard_color = null;
			private Gdk.Color  error_color;
			
			
			public XConstraintsEntry(Gdk.Color error_color) : base()
			{
				this.error_color = error_color;
				this.Completion = new XConstraintsCompletion();
				this.Completion.Model = new ListStore(typeof(string));
				this.Completion.TextColumn = 0;
				this.UpdateCompletion();
			}
			
			public void UpdateCompletion()
			{
				List<string> constraints = UserInterface.Settings.Current.XConstraints;
				constraints.Reverse();
				ListStore store = (ListStore)this.Completion.Model;
				store.Clear();
				foreach(string constraint in constraints)
				{
					store.AppendValues(constraint);
				}
			}
			
			protected override void OnChanged()
			{
				if (this.standard_color == null)
					this.standard_color = this.Style.Base(StateType.Normal);
			
				if (string.IsNullOrEmpty(this.Text) || DataSet.XConstraints.CreateFromString(this.Text) != null)
				{
					this.ModifyBase(StateType.Normal, (Gdk.Color)this.standard_color);
				}
				else
				{
					this.ModifyBase(StateType.Normal, this.error_color);
				}
				
				base.OnChanged();
			}

			protected override bool OnKeyPressEvent(Gdk.EventKey evnt)
			{
				if ((evnt.Key == Gdk.Key.Return || evnt.Key == Gdk.Key.KP_Enter) && this.ReturnPressed != null)
					this.ReturnPressed(null, EventArgs.Empty);

				return base.OnKeyPressEvent(evnt);
			}
			
			protected override bool OnButtonPressEvent(Gdk.EventButton evnt)
			{
				return base.OnButtonPressEvent (evnt);
			}
			
			public XConstraintsCompletion _XConstraintsCompletion
			{
				get { return this.Completion as XConstraintsCompletion; }
			}
		}
	}
}
