//
// Copyright (c) 2016, MindFusion LLC - Bulgaria.
//

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;

using MindFusion.Spreadsheet.Charts;

namespace MindFusion.Spreadsheet.WinForms.Samples.CS.Demo
{
	public partial class DemoForm : Form
	{
		public DemoForm()
		{
			InitializeComponent();

			helpFilePath = FindFileLocation(Application.StartupPath, helpFileName);

			languagesFolder = FindDirectoryLocation("Localization");

			using (Graphics graphics = Graphics.FromHwnd(Handle))
				resolution = new { DpiX = graphics.DpiX, DpiY = graphics.DpiY };

			// Set-up form controls
			var fonts = (from FontFamily ff in FontFamily.Families
						 where ff.IsStyleAvailable(FontStyle.Regular)
						 select ff.Name).Distinct();
			fontNameToolStripComboBox.ComboBox.DataSource = fonts.ToList();
			fontSizeToolStripComboBox.ComboBox.DataSource = new int[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72 };

			zoomToolStripComboBox.ComboBox.DataSource = new int[] { 20, 50, 75, 100, 150, 200, 300, 400 };
			zoomToolStripComboBox.ComboBox.Text = "100";

			valignSplitButton.DefaultItem = valignMiddleToolStripMenuItem;

			bordersToolStripSplitButton.DefaultItem = bordersOuterToolStripMenuItem;
			InitColorSplitButtons();

			objectLineStyleToolStripComboBox.ComboBox.DataSource = (new string[] { "Automatic" }.Union(Enum.GetNames(typeof(DashStyle)))).ToList();
			objectLineStyleToolStripComboBox.ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
			objectLineStyleToolStripComboBox.ComboBox.DrawItem += OnStyleComboDrawItem;

			wbview.SelectionChanged += OnWorkbookViewSelectionChanged;
			wbview.CellClicked += OnWorkbookViewCellClicked;
			wbview.ColumnClicked += OnWorkbookViewColumnClicked;
			wbview.RowClicked += OnWorkbookViewRowClicked;
			wbview.ObjectClicked += OnWorkbookViewObjectClicked;
			wbview.InplaceEditEnded += OnWorkbookViewInplaceEditEnded;
			wbview.ActiveCellChanged += OnWorkbookViewActiveCellChanged;
			wbview.ActiveWorksheetChanged += OnWorkbookViewActiveWorksheetChanged;
			wbview.WorksheetTabClicked += OnWorkbookViewWorksheetTabClicked;
			wbview.WorksheetRemoved += OnWorkbookViewWorksheetRemoved;
			wbview.WorksheetRemoving += OnWorkbookViewWorksheetRemoving;
			wbview.WorksheetAdded += OnWorkbookViewWorksheetAdded;
			wbview.HyperlinkClicked += OnHyperlinkClicked;

			// Initialize the workbook.
			InitWorkbook();

			workbook.UndoEnabled = false;
			CreateData();
			workbook.UndoEnabled = true;
			UpdateSelectionLabel();
			UpdateSumLabel();
			UpdateFormHeader();
		}

		#region Methods

		protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
		{
			switch (keyData)
			{
				case Keys.Control | Keys.B:
					boldToolStripButton.PerformClick();
					return true;
				case Keys.Control | Keys.I:
					italicToolStripButton.PerformClick();
					return true;
				case Keys.Control | Keys.U:
					underlineToolStripButton.PerformClick();
					return true;
				case Keys.Apps:
					ProcessContextMenuKey();
					return true;
				case Keys.Control | Keys.C:
				case Keys.Control | Keys.V:
				case Keys.Control | Keys.X:
					return false;
				case Keys.Control | Keys.Z:
				case Keys.Control | Keys.A:
					if (wbview.IsEditing)
						return false;
					break;
			}
			return base.ProcessCmdKey(ref msg, keyData);
		}

		private void ProcessContextMenuKey()
		{
			if (IsSheetSelected)
				ctxSheets.Show(wbview, 0, 0);
			else if (wbview.Selection.Left == 0 && wbview.Selection.Right == 0x400 - 1)
				ctxRows.Show(wbview, 0, 0);
			else if (wbview.Selection.Top == 0 && wbview.Selection.Bottom == 0x100000 - 1)
				ctxColumns.Show(wbview, 0, 0);
			else
				ctxCells.Show(wbview, 0, 0);
		}

		private void OpenHelpLink(string link)
		{
			if (string.IsNullOrEmpty(helpFilePath))
			{
				helpFilePath = FindFileLocation(Application.StartupPath, helpFileName);
				if (string.IsNullOrEmpty(helpFilePath))
				{
					MessageBox.Show("Could not find help file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
					return;
				}
			}
			try
			{
				Help.ShowHelp(this, helpFilePath, HelpNavigator.Topic, link);
			}
			catch
			{
				MessageBox.Show("Could not find help topic.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
			}
		}

		private void InitColorSplitButtons()
		{
			var colors = new Color[] { Color.Empty }.Union(from kc in Enum.GetValues(typeof(KnownColor)).OfType<KnownColor>()
														   select Color.FromKnownColor(kc));

			splits.Add(backgroundToolStripSplitButton, new ListBox() { Tag = Color.Transparent });
			splits[backgroundToolStripSplitButton].LostFocus += (s, e) => { UpdateCellBackgroundColor(); };
			backgroundToolStripSplitButton.ButtonClick += (s, e) => { UpdateCellBackgroundColor(); };
			splits.Add(fontColorToolStripSplitButton, new ListBox() { Tag = Color.Black });
			splits[fontColorToolStripSplitButton].LostFocus += (s, e) => { UpdateCellTextColor(); };
			fontColorToolStripSplitButton.ButtonClick += (s, e) => { UpdateCellTextColor(); };
			splits.Add(objectLineColorToolStripSplitButton, new ListBox() { Tag = Color.Transparent });
			splits[objectLineColorToolStripSplitButton].LostFocus += (s, e) => { UpdateObjectLineColor(); };
			objectLineColorToolStripSplitButton.ButtonClick += (s, e) => { UpdateObjectLineColor(); };
			splits.Add(objectFillColorToolStripSplitButton, new ListBox() { Tag = Color.White });
			splits[objectFillColorToolStripSplitButton].LostFocus += (s, e) => { UpdateObjectFill(); };
			objectFillColorToolStripSplitButton.ButtonClick += (s, e) => { UpdateObjectFill(); };

			foreach (var item in splits)
			{
				ListBox lst = splits[item.Key];
				ToolStripSplitButton btn = item.Key;
				lst.DrawMode = DrawMode.OwnerDrawFixed;
				lst.SelectionMode = SelectionMode.One;
				lst.BorderStyle = BorderStyle.None;
				lst.ItemHeight = 20;
				lst.Items.AddRange(colors.OfType<object>().ToArray());
				lst.DrawItem += OnColorDropDownDrawItem;
				lst.SelectedIndex = 0;
				lst.SelectedIndexChanged += (s, e) => { btn.Invalidate(); };
				btn.DropDownOpening += (s, e) => { OnToolStripDropDownOpening((ToolStripDropDownItem)s, lst); };
				btn.Paint += OnColorSplitButtonPaint;
			}
		}

		private void InitWorkbook()
		{
			// Clean-up
			DatachWorkbook();
			// Create and setup the workbook.
			workbook = new Workbook();
			workbook.PropertyValueChanged += OnWorkbookChanged;
			workbook.Worksheets.CollectionChanged += OnWorkbookWorksheetsCollectionChanged;
			workbook.ActionRedone += OnWorkbookActionRedone;
			workbook.ActionUndone += OnWorkbookActionUndone;
			wbview.Workbook = workbook;
			wbview.ShowTabs = true;
			CreateSheets(3);
			// Reinitialize form controls state.
			workbook.UndoEnabled = true;
			closeToolStripMenuItem.Enabled = saveToolStripMenuItem.Enabled = saveAsToolStripMenuItem.Enabled =
			exportToolStripMenuItem.Enabled = printPreviewToolStripMenuItem.Enabled = printToolStripMenuItem.Enabled = true;
			editToolStripMenuItem.Visible = insertToolStripMenuItem.Visible =
			formatToolStripMenuItem.Visible = viewToolStripMenuItem.Visible = true;
			toolStripContainer1.TopToolStripPanelVisible = true;
			undoToolStripButton.Enabled = workbook.CanUndo;
			undoToolStripMenuItem.Enabled = workbook.CanUndo;
			redoToolStripButton.Enabled = workbook.CanRedo;
			redoToolStripMenuItem.Enabled = workbook.CanRedo;

			UpdateFromActiveCell();
		}

		private void CreateSheets(int count)
		{
			workbook.Worksheets.Clear();
			for (int i = 0; i < count; )
				workbook.Worksheets.Add(string.Format("Sheet{0}", ++i));
		}

		private void DatachWorkbook()
		{
			currentFileName = "";
			if (wbview.Workbook != null)
			{
				wbview.Workbook.Worksheets.Clear();
				wbview.Workbook.PropertyValueChanged -= OnWorkbookChanged;
				wbview.Workbook.Worksheets.CollectionChanged -= OnWorkbookWorksheetsCollectionChanged;
				wbview.Workbook.ActionRedone -= OnWorkbookActionRedone;
				wbview.Workbook.ActionUndone -= OnWorkbookActionUndone;
			}
		}

		private void CloseWorkbook()
		{
			// Clean-up
			DatachWorkbook();
			wbview.ShowTabs = false;
			wbview.Workbook = null;
			// Reinitialize form controls state to reflect that no workbook
			// is present in the view.
			closeToolStripMenuItem.Enabled = saveToolStripMenuItem.Enabled = saveAsToolStripMenuItem.Enabled =
			exportToolStripMenuItem.Enabled = printPreviewToolStripMenuItem.Enabled = printToolStripMenuItem.Enabled = false;
			editToolStripMenuItem.Visible = insertToolStripMenuItem.Visible =
			formatToolStripMenuItem.Visible = viewToolStripMenuItem.Visible =
			dataToolStripMenuItem.Visible = windowToolStripMenuItem.Visible = false;
			toolStripContainer1.TopToolStripPanelVisible = false;

			selectionToolStripStatusLabel.Text = "";
			sumToolStripStatusLabel.Text = "";
		}

		private void UpdateFromActiveCell()
		{
			if (workbook == null/* || wbview.ActiveCell == null*/)
				return;
			ignoreChanges = true;
			fontNameToolStripComboBox.ComboBox.Text = ActiveCell.Style.FontName;
			fontSizeToolStripComboBox.ComboBox.Text = ActiveCell.Style.FontSize.ToString();
			boldToolStripButton.Checked = ActiveCell.Style.FontBold.HasValue && ActiveCell.Style.FontBold.Value;
			italicToolStripButton.Checked = ActiveCell.Style.FontItalic.HasValue && ActiveCell.Style.FontItalic.Value; ;
			underlineToolStripButton.Checked = ActiveCell.Style.FontUnderline.HasValue && ActiveCell.Style.FontUnderline.Value; ;
			leftAlignToolStripButton.Checked = ActiveCell.Style.HorizontalAlignment == HorizontalAlignment.Left;
			centerAlignToolStripButton.Checked = ActiveCell.Style.HorizontalAlignment == HorizontalAlignment.Center;
			rightAlignToolStripButton.Checked = ActiveCell.Style.HorizontalAlignment == HorizontalAlignment.Right;
			currencyToolStripButton.Checked = ActiveCell.Style.Format == GetCurrencyFormat();
			percentToolStripButton.Checked = ActiveCell.Style.Format == workbook.DefaultNumericFormats.PercentFormats[1].Format;
			mergeToolStripButton.Checked = formatMergeCellsToolStripMenuItem.Checked =
				ActiveCell.IsMerged;
			ignoreChanges = false;
		}

		private string GetCurrencyFormat()
		{
			if (workbook == null)
				return string.Empty;
			if (!string.IsNullOrEmpty(cachedCurrencyFormat))
				return cachedCurrencyFormat;
			string code, symbol;
			int lcid = workbook.Locale.LCID;
			RegionInfo info = null;
			try
			{
				info = new RegionInfo(lcid);
			}
			catch { }
			if (info != null)
			{
				code = info.ISOCurrencySymbol;
				symbol = info.CurrencySymbol;
			}
			else
			{
				code = "USD";
				symbol = "$";
			}
			CurrencyCodeInfo cci = new CurrencyCodeInfo(lcid, code, symbol);
			cachedCurrencyFormat = workbook.DefaultNumericFormats.GetCurrencyFormats(cci)[1].Format;
			return cachedCurrencyFormat;
		}

		private void UpdateSelectionLabel()
		{
			if (wbview.Selection.Range == null)
				return;
			string range = wbview.Selection.Range.ToString();
			if (!sheetNameRegex.IsMatch(range))
				range = string.Concat(ActiveSheet.Name, "!", range);
			selectionToolStripStatusLabel.Text = range;

			mergeToolStripButton.Enabled = formatMergeCellsToolStripMenuItem.Enabled =
				wbview.Selection.Left != wbview.Selection.Right || wbview.Selection.Top != wbview.Selection.Bottom;
		}

		private void UpdateSumLabel()
		{
			sumToolStripStatusLabel.Text = string.Format("Sum = {0}",
				SelectedCells.Sum());
		}

		private void UpdateControlsState()
		{
			ignoreChanges = true;
			freezeToolStripMenuItem.Checked = ActiveSheet != null && (
				ActiveSheet.FrozenColumnCount != 0 || ActiveSheet.FrozenRowCount != 0);
			zoomToolStripComboBox.ComboBox.Text = ActiveSheet != null ? ActiveSheet.Zoom.ToString() : "100";
			ignoreChanges = false;
		}

		private void UpdateObjectToolstripVisibility()
		{
			objectPropertiesToolStripMenuItem.Visible = wbview.Selection.Objects.Count > 0;
			tstObjectProperties.Visible = objectPropertiesToolStripMenuItem.Checked && wbview.Selection.Objects.Count > 0;
		}

		private void UpdateCellBackgroundColor()
		{
			if (SelectedCells == null)
				return;
			Color? clr = splits[backgroundToolStripSplitButton].SelectedItem as Color?;
			using (workbook.StartChangeOperation(ActiveSheet))
			{
				if (!clr.HasValue || clr.Value.IsEmpty)
					SelectedCells.Style.Background = null;
				else
					SelectedCells.Style.Background = new MindFusion.Drawing.SolidBrush(clr.Value);
			}
		}

		private void UpdateCellTextColor()
		{
			if (SelectedCells == null)
				return;
			Color? clr = splits[fontColorToolStripSplitButton].SelectedItem as Color?;
			using (workbook.StartChangeOperation(ActiveSheet))
			{
				SelectedCells.Style.TextColor = clr;
			}
		}

		private void UpdateObjectFill()
		{
			if (wbview.Selection.Objects.Count == 0)
				return;
			Color? clr = splits[objectFillColorToolStripSplitButton].SelectedItem as Color?;
			using (workbook.StartChangeOperation(ActiveSheet))
			{
				foreach (InteractiveObject obj in wbview.Selection.Objects)
				{
					if (obj is Chart)
					{
						if (!clr.HasValue || clr.Value.IsEmpty)
							(obj as Chart).Fill = null;
						else
							(obj as Chart).Fill = new MindFusion.Drawing.SolidBrush(clr.Value);
					}
					else if (obj is CellAnnotation)
						(obj as CellAnnotation).BackColor = clr;
				}
			}
		}

		private void UpdateObjectLineColor()
		{
			if (wbview.Selection.Objects.Count == 0)
				return;
			Color? clr = splits[objectLineColorToolStripSplitButton].SelectedItem as Color?;
			using (workbook.StartChangeOperation(ActiveSheet))
			{
				foreach (InteractiveObject obj in wbview.Selection.Objects)
					obj.LineColor = clr;
			}
		}

		private static Measure ParseMeasure(string text, Measure target)
		{
			try
			{
				double value;
				if (double.TryParse(text, out value) && target != null)
					return new Measure(value, target.Unit);
				return new Measure(text);
			}
			catch
			{
				return target;
			}
		}

		static string FindDirectoryLocation(string dirName)
		{
			var dir = new DirectoryInfo(Application.StartupPath);
			return FindDirectoryLocation(dir, dirName);
		}

		static string FindDirectoryLocation(DirectoryInfo dir, string dirName)
		{
			var subdirs = dir.GetDirectories(dirName);
			if (subdirs == null || subdirs.Length == 0)
			{
				var parent = dir.Parent;
				if (parent != null)
					return FindDirectoryLocation(parent, dirName);
				return null;
			}

			return subdirs[0].FullName;
		}

		private static string FindFileLocation(string path, string fileName)
		{
			if (fileName.Contains('*'))
			{
				var chmFiles = Directory.GetFiles(path, "*.chm", SearchOption.TopDirectoryOnly);
				if (chmFiles.Length == 0)
				{
					var di = Directory.GetParent(path);
					if (di == null)
						return null;
					return FindFileLocation(di.FullName, fileName);
				}
				return chmFiles[0];
			}
			else
			{
				if (File.Exists(Path.Combine(path, fileName)))
					return Path.Combine(path, fileName);
				var di = Directory.GetParent(path);
				if (di == null)
					return null;
				return FindFileLocation(di.FullName, fileName);
			}
		}

		private WorkbookPrinter CreatePrinter(string title)
		{
			WorkbookPrinter printer = new WorkbookPrinter();
			printer.DocumentName = title;
			printer.HeaderFormat = "%D, %W\nPage %P";
			return printer;
		}

		private void UpdateFormHeader()
		{
			string name;
			if (string.IsNullOrEmpty(currentFileName))
				name = "Untitled";
			else
			{
				try
				{
					name = new FileInfo(currentFileName).Name;
				}
				catch
				{
					name = "";
				}
			}
			Text = string.Format("MindFusion.Spreadsheet for WinForms: Demo Sample{0}", string.IsNullOrEmpty(name) ? "" : " - " + name);
		}

		private SortOptions FastSortOptions(SortOrder sortOrder)
		{
			var options = new SortOptions()
			{
				CaseSensitive = false,
				Direction = SortDirection.TopToBottom,
			};
			options.Keys.AddRange((
				from c in ActiveSheet.Columns
				where c.Index >= SelectedCells.Left && c.Index <= SelectedCells.Right
				select new SortKey(c.Index)
				{
					Order = sortOrder
				}).ToList<SortKey>());
			return options;
		}

		#endregion

		#region WorkbookView handlers

		private void OnWorkbookViewSelectionChanged(object sender, EventArgs e)
		{
			UpdateSelectionLabel();
			UpdateSumLabel();
			UpdateObjectToolstripVisibility();
		}

		private void OnWorkbookViewCellClicked(object sender, CellMouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right && e.Clicks == 1)
			{
				// Move the selection if the clicked cell 
				// is not already selected.
				if (!wbview.Selection.Contains(e.Cell.Column, e.Cell.Row))
				{
					wbview.Selection.Set(e.Cell.Column, e.Cell.Row);
					wbview.ActiveCell = e.Cell;
				}
				// Show the cell context menu.
				ctxCells.Show(wbview, e.X, e.Y);
			}
		}

		private void OnWorkbookViewColumnClicked(object sender, ColumnMouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right && e.Clicks == 1)
			{
				// Move the selection to the clicked column
				// is not already selected.
				if (!wbview.Selection.InColumn(e.Column.Index) ||
					wbview.Selection.Top != 0 ||
					wbview.Selection.Top == wbview.Selection.Bottom)
				{
					wbview.Selection.SelectColumns(e.Column.Index);
					wbview.ActiveCell = ActiveSheet.Cells[e.Column.Index, 0];
				}
				// Show the column context menu.
				ctxColumns.Show(wbview, e.X, e.Y);
			}
		}

		private void OnWorkbookViewRowClicked(object sender, RowMouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right && e.Clicks == 1)
			{
				// Move the selection to the row column.
				if (!wbview.Selection.InRow(e.Row.Index) ||
					wbview.Selection.Left != 0 ||
					wbview.Selection.Left == wbview.Selection.Right)
				{
					wbview.Selection.SelectRows(e.Row.Index);
					wbview.ActiveCell = ActiveSheet.Cells[0, e.Row.Index];
				}
				// Show the row context menu.
				ctxRows.Show(wbview, e.X, e.Y);
			}
		}

		private void OnWorkbookViewObjectClicked(object sender, ObjectMouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right && e.Clicks == 1)
			{
				if (!wbview.Selection.ContainsObject(e.Object))
				{
					if ((Control.ModifierKeys & Keys.Control) != 0)
						wbview.Selection.Toggle(e.Object);
					else
						wbview.Selection.Change(e.Object);
				}
			}
			ignoreChanges = true;
			UpdateObjectToolstripVisibility();
			objectLineStyleToolStripComboBox.SelectedItem = e.Object.LineStyle.HasValue ? e.Object.LineStyle.Value.ToString() : "Automatic";
			objectLineSizeToolStripTextBox.Text = e.Object.LineSize != null ? e.Object.LineSize.ToString() : "";
			objectAnchorToPageToolStripMenuItem.Checked = e.Object.Anchor == ObjectAnchor.ToPage;
			objectAnchorToCellToolStripMenuItem.Checked = e.Object.Anchor == ObjectAnchor.ToCell;
			objectAnchorToolStripDropDownButton.Enabled = !(e.Object is CellAnnotation);
			ignoreChanges = false;

			if (e.Button == MouseButtons.Left && e.Clicks == 2 && e.Object is Chart)
			{
				using (workbook.StartCompositeOperation())
				using (workbook.StartChangeOperation(ActiveSheet))
					new ChartForm(e.Object as Chart).ShowDialog(this);
			}
			else if (e.Button == MouseButtons.Right && e.Clicks == 1)
			{
				ctxObjects.Show(wbview, e.X, e.Y);
			}
		}

		private void OnWorkbookViewInplaceEditEnded(object sender, InplaceEditEventArgs e)
		{
			if (e.Item == createdAnnotation && annotationCreateCommand != null)
			{
				// Complete the composite undo operation started by
				// creating an annotation object.
				if (e.Accepted)
					workbook.ExecuteCommand(annotationCreateCommand);
				else
					workbook.CancelCompositeOperation();
				createdAnnotation = null;
				annotationCreateCommand = null;
			}
		}

		private void OnWorkbookViewActiveCellChanged(object sender, EventArgs e)
		{
			UpdateFromActiveCell();
		}

		private void OnWorkbookViewActiveWorksheetChanged(object sender, EventArgs e)
		{
			if (wbview.Workbook == null || wbview.Workbook.Worksheets.Count == 0)
				return;

			UpdateControlsState();
			UpdateFromActiveCell();
			UpdateObjectToolstripVisibility();
		}

		private void OnWorkbookViewWorksheetTabClicked(object sender, WorksheetMouseEventArgs e)
		{
			if (e.Clicks == 1 && e.Button == MouseButtons.Right)
			{
				if (ActiveSheet != e.Worksheet)
					ActiveSheet = e.Worksheet;
				ctxSheets.Show(wbview, e.X, e.Y);
			}
			else if (e.Clicks == 1 && e.Button == MouseButtons.Middle)
			{
				if (workbook.Worksheets.Where(w => w.Visible).Count() != 1)
					workbook.Worksheets.Remove(e.Worksheet);
			}
			UpdateSelectionLabel();
			UpdateSumLabel();
			UpdateObjectToolstripVisibility();
		}

		private void OnWorkbookViewWorksheetRemoved(object sender, WorksheetEventArgs e)
		{
			UpdateObjectToolstripVisibility();
			UpdateSelectionLabel();
			UpdateSumLabel();
		}

		private void OnWorkbookViewWorksheetRemoving(object sender, WorksheetValidationEventArgs e)
		{
			if (workbook.Worksheets.Where(w => w.Visible).Count() == 1)
				e.Cancel = true;
		}

		private void OnWorkbookViewWorksheetAdded(object sender, WorksheetEventArgs e)
		{
			UpdateObjectToolstripVisibility();
			UpdateSelectionLabel();
			UpdateSumLabel();
		}

		#endregion

		#region Workbook handlers

		private void OnWorkbookChanged(object sender, PropertyEventArgs e)
		{
			switch (e.PropertyName)
			{
				// Toggle undo buttons
				case "CanUndo":
					undoToolStripMenuItem.Enabled = (bool)e.NewValue;
					undoToolStripButton.Enabled = (bool)e.NewValue;
					break;
				// Toggle redo buttons
				case "CanRedo":
					redoToolStripMenuItem.Enabled = (bool)e.NewValue;
					redoToolStripButton.Enabled = (bool)e.NewValue;
					break;
				// Reset the cached currency format for the current locale.
				case "Locale":
					cachedCurrencyFormat = null;
					break;
			}
		}

		private void OnWorkbookWorksheetsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			if (e.Action == NotifyCollectionChangedAction.Add)
				OnAddWorksheets(e.NewItems.OfType<Worksheet>());
			else if (e.Action == NotifyCollectionChangedAction.Remove)
				OnRemoveWorksheets(e.OldItems.OfType<Worksheet>());
		}

		private void OnAddWorksheets(IEnumerable<Worksheet> collection)
		{
			foreach (Worksheet w in collection)
			{
				w.CellChanged += OnCellChanged;
				w.CellChanging += OnCellChanging;
				w.CellsCleared += OnCellCleared;
				//w.HyperlinkClicked += OnHyperlinkClicked;
			}
		}

		private void OnRemoveWorksheets(IEnumerable<Worksheet> collection)
		{
			foreach (Worksheet w in collection)
			{
				w.CellChanged -= OnCellChanged;
				w.CellChanging -= OnCellChanging;
				w.CellsCleared -= OnCellCleared;
				//w.HyperlinkClicked -= OnHyperlinkClicked;
			}
		}

		private void OnWorkbookActionUndone(object sender, UndoEventArgs e)
		{
			UpdateFromActiveCell();
			UpdateSumLabel();
			UpdateControlsState();
		}

		private void OnWorkbookActionRedone(object sender, UndoEventArgs e)
		{
			UpdateFromActiveCell();
			UpdateSumLabel();
			UpdateControlsState();
		}

		#endregion

		#region Worksheet handlers

		private void OnCellCleared(object sender, EventArgs e)
		{
			UpdateSumLabel();
		}

		private void OnCellChanged(object sender, CellChangedEventArgs e)
		{
			if (e.Cell.Hyperlink == null && e.NewData != null)
			{
				string data = e.NewData.ToString();
				string value = e.Cell.Value.ToString();
				if (urlRegex.IsMatch(data))
				{
					string url = urlRegex.Match(data).Value;
					if (url.Length == data.Length)
					{
						if (url.Contains("@") && !url.Contains("mailto:"))
							url = url.Insert(0, "mailto:");
						else if (!url.Contains("://"))
							url = url.Insert(0, "http://");

						e.Cell.SetHyperlink(url.StartsWith("mailto:") ?
							HyperlinkType.EmailAddress : HyperlinkType.WebAddress,
							url, "");
						e.Cell.Hyperlink.ToolTip = "CTRL + Click to follow link.";
					}
				}
			}
			if (wbview.Selection.Contains(e.Cell.Column, e.Cell.Row))
				UpdateSumLabel();
		}


		private void OnCellChanging(object sender, CellValidationEventArgs e)
		{
			if (e.Cell.Hyperlink != null && !e.Cell.Hyperlink.IsImplicit &&
				e.NewData == null && IsSingleCellSelected)
			{
				using (workbook.StartChangeOperation(ActiveSheet))
					e.Cell.RemoveHyperlink();
				e.Cancel = true;
			}
		}

		private void OnHyperlinkClicked(object sender, CellEventArgs e)
		{
			if ((Control.ModifierKeys & Keys.Control) != 0)
			{
				Hyperlink link = e.Cell.Hyperlink;
				try
				{
					if (link.Type == HyperlinkType.ExistingFile && link.Target == "HelpFile")
					{
						OpenHelpLink(link.SubTarget);
						return;
					}
					if (link.Type != HyperlinkType.CurrentWorkbook)
						Process.Start(link.Target);
					else
					{
						string sheetName = sheetNameRegex.Match(link.Target).Value;
						if (!string.IsNullOrEmpty(sheetName))
							ActiveSheet = workbook.Worksheets[sheetName];
						wbview.Selection.Set(ActiveSheet.CellRanges[link.Target]);

					}
				}
				catch (Exception ex)
				{
					MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
				}
			}
		}

		#endregion

		#region File menu handlers

		private void OnNewWorkbook(object sender, EventArgs e)
		{
			if (wbview.Workbook == null || MessageBox.Show(
				string.Format("This will discard all data in the present workbook.{0}Are you sure you want to continue?", Environment.NewLine),
				"Warning",
				MessageBoxButtons.YesNo,
				MessageBoxIcon.Warning) == DialogResult.Yes)
				InitWorkbook();
			UpdateFormHeader();
		}

		private void OnOpenWorkbook(object sender, EventArgs e)
		{
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.Filter =
				"MindFusion Workbook (*.mwb)|*.mwb|" +
				"XML (*.xml)|*.xml";
			dlg.Title = "Open Workbook";
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				InitWorkbook();
				try
				{
					currentFileName = dlg.FileName;
					if (currentFileName.Substring(currentFileName.LastIndexOf('.')) == ".xml")
						workbook.LoadFromXml(currentFileName);
					else
						workbook.LoadFromFile(currentFileName);
				}
				catch (Exception ex)
				{
					MessageBox.Show(
						string.Format("Load failed.{0}{1}", Environment.NewLine, ex.ToString()),
						"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
				UpdateFormHeader();
				UpdateObjectToolstripVisibility();
			}
		}

		private void OnCloseWorkbook(object sender, EventArgs e)
		{
			CloseWorkbook();
			UpdateFormHeader();
		}

		private void OnSaveWorkbook(object sender, EventArgs e)
		{
			if (string.IsNullOrEmpty(currentFileName))
			{
				OnSaveWorkbookAs(null, EventArgs.Empty);
			}
			else
			{
				try
				{
					if (currentFileName.Substring(currentFileName.LastIndexOf('.')).ToLower() == ".xml")
						workbook.SaveToXml(currentFileName);
					else
						workbook.SaveToFile(currentFileName);
				}
				catch (Exception ex)
				{
					MessageBox.Show(
						string.Format("Save failed.{0}{1}", Environment.NewLine, ex.ToString()),
						"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		private void OnSaveWorkbookAs(object sender, EventArgs e)
		{
			SaveFileDialog dlg = new SaveFileDialog();
			dlg.Filter =
				"Workbook (*.mwb)|*.mwb|" +
				"XML (*.xml)|*.xml";
			dlg.Title = "Save Workbook As";
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				currentFileName = dlg.FileName;
				try
				{
					if (currentFileName.Substring(currentFileName.LastIndexOf('.')).ToLower() == ".xml")
						workbook.SaveToXml(currentFileName);
					else
						workbook.SaveToFile(currentFileName);
				}
				catch (Exception ex)
				{
					MessageBox.Show(
						string.Format("Save failed.{0}{1}", Environment.NewLine, ex.ToString()),
						"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}
				UpdateFormHeader();
			}
		}

		private void OnImportWorkbook(object sender, EventArgs e)
		{
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.Filter =
				"Office Open XML Workbook (*.xlsx)|*.xlsx|" +
				"OpenDocument Spreadsheet (*.ods)|*.ods|" +
				"CSV Text (*.csv)|*.csv";
			dlg.Title = "Import Workbook";
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				InitWorkbook();
				string ext = dlg.FileName.Substring(dlg.FileName.LastIndexOf('.')).ToLowerInvariant();
				try
				{
					if (ext == ".xlsx")
						new ExcelImporter().Import(dlg.FileName, workbook);
					else if (ext == ".ods")
						new CalcImporter().Import(dlg.FileName, workbook);
					else
					{
						using (CsvImportForm frm = new CsvImportForm(workbook, dlg.FileName))
							if (frm.ShowDialog() == DialogResult.OK)
								frm.Import(ActiveSheet);
					}

				}
				catch (Exception ex)
				{
					MessageBox.Show(
						string.Format("Import failed.{0}{1}", Environment.NewLine, ex.ToString()),
						"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		private void OnExportWorkbook(object sender, EventArgs e)
		{
			SaveFileDialog dlg = new SaveFileDialog();
			dlg.Filter =
				"Image (*.png)|*.png|" +
				"PDF (*.pdf)|*.pdf|" +
				"CSV Text (*.csv)|*.csv|" +
				"XHTML File (*.xhtml)|*.xhtml|" +
				"MHTML File (*.mhtml)|*.mhtml|" +
				"Office Open XML Workbook (*.xlsx)|*.xlsx|" +
				"OpenDocument Spreadsheet (*.ods)|*.ods";
			dlg.Title = "Export Active Worksheet";
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				string ext = dlg.FileName.Substring(dlg.FileName.LastIndexOf('.')).ToLowerInvariant();
				try
				{
					if (ext == ".pdf")
						new PdfExporter().Export(ActiveSheet, dlg.FileName);
					else if (ext == ".xlsx")
						new ExcelExporter().Export(wbview.Workbook, dlg.FileName);
					else if (ext == ".ods")
						new CalcExporter().Export(wbview.Workbook, dlg.FileName);
					else if (ext == ".csv")
					{
						using (CsvExportForm frm = new CsvExportForm(workbook, dlg.FileName))
							if (frm.ShowDialog() == DialogResult.OK)
								frm.Export(ActiveSheet);
					}
					else if (ext == ".xhtml")
					{
						new HtmlExporter().Export(wbview.Workbook, dlg.FileName);
					}
					else if (ext == ".mhtml")
					{
						new MhtmlExporter().Export(wbview.Workbook, dlg.FileName);
					}
					else
					{
						new ImageExporter() { EnableZoom = true }.Export(ActiveSheet, dlg.FileName);
					}

				}
				catch (Exception ex)
				{
					MessageBox.Show(
						string.Format("Export failed.{0}{1}", Environment.NewLine, ex.ToString()),
						"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		string GetLocalizationFile(string lang)
		{
			if (!Directory.Exists(languagesFolder))
			{
				if (MessageBox.Show(this, "The localization file could not be found. Would you like to search for it manually?",
					"File not found", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
					return null;

				var dialog = new OpenFileDialog();
				dialog.Filter = "Localization Files (*.xml)|*.xml|All Files|*.*||";
				if (dialog.ShowDialog(this) != DialogResult.OK)
					return null;

				return dialog.FileName;
			}

			return Path.Combine(languagesFolder, string.Format("Localization.{0}.xml", lang));
		}

		void OnEnglish(object sender, EventArgs e)
		{
			var file = GetLocalizationFile("EN");
			if (file != null)
				workbook.SetLocalizationInfo(file);
		}

		void OnGerman(object sender, EventArgs e)
		{
			var file = GetLocalizationFile("DE");
			if (file != null)
				workbook.SetLocalizationInfo(file);
		}

		void OnSpanish(object sender, EventArgs e)
		{
			var file = GetLocalizationFile("ES");
			if (file != null)
				workbook.SetLocalizationInfo(file);
		}

		void OnFrench(object sender, EventArgs e)
		{
			var file = GetLocalizationFile("FR");
			if (file != null)
				workbook.SetLocalizationInfo(file);
		}

		void OnKorean(object sender, EventArgs e)
		{
			var file = GetLocalizationFile("KO");
			if (file != null)
				workbook.SetLocalizationInfo(file);
		}

		void OnPortuguese(object sender, EventArgs e)
		{
			var file = GetLocalizationFile("PT");
			if (file != null)
				workbook.SetLocalizationInfo(file);
		}

		void OnRussian(object sender, EventArgs e)
		{
			var file = GetLocalizationFile("RU");
			if (file != null)
				workbook.SetLocalizationInfo(file);
		}

		void OnChinese(object sender, EventArgs e)
		{
			var file = GetLocalizationFile("ZH");
			if (file != null)
				workbook.SetLocalizationInfo(file);
		}

		private void OnPrintPreview(object sender, EventArgs e)
		{
			CreatePrinter(!string.IsNullOrEmpty(currentFileName) ? currentFileName : "Untitled").
				PrintPreview(workbook);
		}

		private void OnPrint(object sender, EventArgs e)
		{
			CreatePrinter(!string.IsNullOrEmpty(currentFileName) ? currentFileName : "Untitled")
				.Print(workbook);
		}

		private void OnExit(object sender, EventArgs e)
		{
			Application.Exit();
		}

		#endregion

		#region Edit menu handlers

		private void OnEditMenuItemOpening(object sender, EventArgs e)
		{
			deleteSheetToolStripMenuItem.Enabled = workbook.Worksheets.Count > 1;
		}

		private void OnUndo(object sender, EventArgs e)
		{
			workbook.Undo();
		}

		private void OnRedo(object sender, EventArgs e)
		{
			workbook.Redo();
		}

		private void OnSortAscending(object sender, EventArgs e)
		{
			SelectedCells.Sort(FastSortOptions(SortOrder.Ascending));
		}

		private void OnSortDescending(object sender, EventArgs e)
		{
			SelectedCells.Sort(FastSortOptions(SortOrder.Descending));
		}

		private void OnClearUndoHistory(object sender, EventArgs e)
		{
			// Toggling the UndoEnabled property reinitializes 
			// the undo records history of the workbook.
			workbook.UndoEnabled = false;
			workbook.UndoEnabled = true;
		}

		private void OnCut(object sender, EventArgs e)
		{
			// Let the workbook view handle the cut operation.
			SendKeys.Send("^x");
		}

		private void OnCopy(object sender, EventArgs e)
		{
			// Let the workbook view handle the copy operation.
			SendKeys.Send("^c");
		}

		private void OnPaste(object sender, EventArgs e)
		{
			// Let the workbook view handle the paste operation.
			SendKeys.Send("^v");
		}

		private void OnSelectAll(object sender, EventArgs e)
		{
			wbview.Selection.SelectAll();
		}

		private void OnFillDownSeries(object sender, EventArgs e)
		{
			SelectedCells.FillData(FillType.Auto, FillDirection.Down,
				FillDate.Day, 1, null, false);
		}

		private void OnFillAcrossSeries(object sender, EventArgs e)
		{
			SelectedCells.FillData(FillType.Auto, FillDirection.Across,
				FillDate.Day, 1, null, false);
		}

		private void OnFillSeriesShow(object sender, EventArgs e)
		{
			FillSeriesForm dlg = new FillSeriesForm(workbook, SelectedCells);
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				SelectedCells.FillData(dlg.FillType, dlg.FillDirection,
					dlg.FillDate, dlg.FillStep, dlg.FillStop, dlg.FillTrend);
			}
		}

		private void OnClearAll(object sender, EventArgs e)
		{
			using (workbook.StartCompositeOperation())
			{
				SelectedCells.Style.Reset();
				SelectedCells.Clear();

				var cells = SelectedCells.ToList();

				for (int i = cells.Count - 1, l = 0; i >= l; i--)
				{
					Cell cell = cells[i];
					if (cell.Annotation != null)
						cell.RemoveAnnotation();
					if (cell.Hyperlink != null)
						cell.RemoveHyperlink();
				}
			}
		}

		private void OnClearContents(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				SelectedCells.Clear();
		}

		private void OnClearFormats(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				SelectedCells.Style.Reset();
		}

		private void OnClearAnnotations(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
			{
				var cells = SelectedCells.ToList();
				for (int i = cells.Count - 1, l = 0; i >= l; i--)
				{
					Cell cell = cells[i];
					if (cell.Annotation != null)
						cell.RemoveAnnotation();
				}
			}
		}

		private void OnDeleteSheet(object sender, EventArgs e)
		{
			if (workbook.Worksheets.Where(w => w.Visible).Count() > 1)
				workbook.Worksheets.Remove(ActiveSheet);
		}

		private void OnDeleteCells(object sender, EventArgs e)
		{
			DeleteCellsForm dlg = new DeleteCellsForm(workbook);
			if (dlg.ShowDialog() == DialogResult.OK)
			{
				using (var cmd = workbook.StartChangeOperation(ActiveSheet))
				{
					switch (dlg.Result)
					{
						case CellsFormResult.ShiftVertical:
							SelectedCells.Remove(ShiftDirection.Up);
							break;
						case CellsFormResult.ShiftHorizontal:
							SelectedCells.Remove(ShiftDirection.Left);
							break;
						case CellsFormResult.EntireRow:
							ActiveSheet.Rows.Remove(SelectedCells.Top,
								1 + Math.Abs(SelectedCells.Top - SelectedCells.Bottom));
							break;
						case CellsFormResult.EntireColumn:
							ActiveSheet.Columns.Remove(SelectedCells.Left,
								1 + Math.Abs(SelectedCells.Right - SelectedCells.Left));
							break;
					}
				}
			}
		}

		private void OnFind(object sender, EventArgs e)
		{
			ShowFindReplaceForm();
		}

		private void OnReplace(object sender, EventArgs e)
		{
			ShowFindReplaceForm();
		}

		private void ShowFindReplaceForm()
		{
			FindReplaceForm dlg = new FindReplaceForm(workbook, ActiveCell);
			dlg.CellFound += (s1, e1) =>
			{
				if (e1.Cell.Worksheet != ActiveSheet)
					ActiveSheet = e1.Cell.Worksheet;
				ActiveCell = e1.Cell;
				wbview.BringIntoView(e1.Cell);
				((FindReplaceForm)s1).CurrentCell = e1.Cell;
			};
			dlg.CellActivated += (s1, e1) =>
			{
				if (e1.Cell.Worksheet != ActiveSheet)
					ActiveSheet = e1.Cell.Worksheet;
				ActiveCell = e1.Cell;
				wbview.BringIntoView(e1.Cell);
			};
			dlg.ShowDialog(this);
		}

		#endregion

		#region View menu handlers

		private void OnStandardToolbarCheckChanged(object sender, EventArgs e)
		{
			tstStandard.Visible = (sender as ToolStripMenuItem).Checked;
		}

		private void OnFormulaToolBarCheckedChanged(object sender, EventArgs e)
		{
			wbview.ShowFormulaBar = (sender as ToolStripMenuItem).Checked;
		}

		private void OnFormattingToolbarCheckChanged(object sender, EventArgs e)
		{
			tstFormat.Visible = (sender as ToolStripMenuItem).Checked;
		}

		private void OnObjectPropertiesToolbarCheckChanged(object sender, EventArgs e)
		{
			tstObjectProperties.Visible = (sender as ToolStripMenuItem).Checked && wbview.Selection.Objects.Count > 0;
		}

		private void OnStatusToolbarCheckChanged(object sender, EventArgs e)
		{
			stsMain.Visible = (sender as ToolStripMenuItem).Checked;
		}

		private void OnShowHeadersChanged(object sender, EventArgs e)
		{
			wbview.ShowHeaders = columnRowHeadersToolStripMenuItem.Checked;
		}

		private void OnShowGridChanged(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			ignoreChanges = true;
			if (sender == showGridToolStripButton)
			{
				wbview.ShowGridLines = showGridToolStripButton.Checked;
				gridLinesToolStripMenuItem.Checked = showGridToolStripButton.Checked;
			}
			else if (sender == gridLinesToolStripMenuItem)
			{
				wbview.ShowGridLines = gridLinesToolStripMenuItem.Checked;
				showGridToolStripButton.Checked = gridLinesToolStripMenuItem.Checked;
			}
			ignoreChanges = false;
		}

		private void OnViewFilterChanged(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			ignoreChanges = true;
			wbview.ShowAutoFilterRange = viewFilterToolStripMenuItem.Checked;
			ignoreChanges = false;
		}

		#endregion

		#region Insert menu handlers

		private void OnInsertMenuOpening(object sender, EventArgs e)
		{
			columnBreakToolStripMenuItem.Enabled = ActiveCell.Column != 0;
			rowBreakToolStripMenuItem.Enabled = ActiveCell.Row != 0;

			ignoreChanges = true;
			pageBreakToolStripMenuItem.Checked = ActiveSheet.Columns[ActiveCell.Column].PageBreak && ActiveSheet.Rows[ActiveCell.Row].PageBreak;
			columnBreakToolStripMenuItem.Checked = ActiveSheet.Columns[ActiveCell.Column].PageBreak;
			rowBreakToolStripMenuItem.Checked = ActiveSheet.Rows[ActiveCell.Row].PageBreak;
			ignoreChanges = false;

		}

		private void OnInsertCells(object sender, EventArgs e)
		{
			InsertCellsForm dlg = new InsertCellsForm(workbook);
			if (dlg.ShowDialog() == DialogResult.OK)
			{
				using (var cmd = workbook.StartChangeOperation(ActiveSheet))
				{
					try
					{
						switch (dlg.Result)
						{
							case CellsFormResult.ShiftVertical:
								SelectedCells.Insert(PushDirection.Down);
								break;
							case CellsFormResult.ShiftHorizontal:
								SelectedCells.Insert(PushDirection.Right);
								break;
							case CellsFormResult.EntireRow:
								ActiveSheet.Rows.Insert(SelectedCells.Top,
									1 + Math.Abs(SelectedCells.Top - SelectedCells.Bottom));
								break;
							case CellsFormResult.EntireColumn:
								ActiveSheet.Columns.Insert(SelectedCells.Left,
									1 + Math.Abs(SelectedCells.Right - SelectedCells.Left));
								break;
						}
					}
					catch (InvalidOperationException ex)
					{
						MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					}
				}
			}
		}

		private void OnInsertRows(object sender, EventArgs e)
		{
			using (var cmd = workbook.StartChangeOperation(ActiveSheet))
			{
				try
				{
					ActiveSheet.Rows.Insert(SelectedCells.Top,
						1 + Math.Abs(SelectedCells.Top - SelectedCells.Bottom));
				}
				catch (InvalidOperationException ex)
				{
					MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		private void OnInsertColumns(object sender, EventArgs e)
		{
			using (var cmd = workbook.StartChangeOperation(ActiveSheet))
			{
				try
				{
					ActiveSheet.Columns.Insert(SelectedCells.Left,
						1 + Math.Abs(SelectedCells.Right - SelectedCells.Left));
				}
				catch (InvalidOperationException ex)
				{
					MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		private void OnInsertSheet(object sender, EventArgs e)
		{
			InsertWorksheetForm dlg = new InsertWorksheetForm(workbook);
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				Worksheet newSheet = null;
				using (var cmd = workbook.StartCompositeOperation())
				{
					int index = -1;
					switch (dlg.Position)
					{
						case InsertWorksheetPosition.AfterActiveSheet:
							index = workbook.Worksheets.IndexOf(ActiveSheet) + 1;
							break;
						case InsertWorksheetPosition.BeforeActiveSheet:
							index = workbook.Worksheets.IndexOf(ActiveSheet);
							break;
						case InsertWorksheetPosition.Other:
							index = dlg.Index;
							break;
					}
					if (dlg.NumberOfSheets == 1)
						newSheet = workbook.Worksheets.Insert(index, dlg.SheetName);
					else
					{
						for (int i = 0; i < dlg.NumberOfSheets; i++)
							newSheet = workbook.Worksheets.Insert(index++);
					}
				}
				wbview.ActiveWorksheet = newSheet;
			}
		}

		private void OnInsertPageBreak(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			ignoreChanges = true;

			int row = ActiveCell.Row;
			int col = ActiveCell.Column;
			if (ActiveCell.IsMerged)
			{
				var c = ActiveSheet.GetMergedCell(ActiveCell);
				row = c.Bottom;
				col = c.Right;
			}

			if (col == 0 || row == 0)
			{
				pageBreakToolStripMenuItem.Checked = false;
				ignoreChanges = false;
				return;
			}
			ActiveSheet.Columns[col].PageBreak = pageBreakToolStripMenuItem.Checked;
			ActiveSheet.Rows[row].PageBreak = pageBreakToolStripMenuItem.Checked;

			columnBreakToolStripMenuItem.Checked = ActiveSheet.Columns[col].PageBreak;
			rowBreakToolStripMenuItem.Checked = ActiveSheet.Rows[row].PageBreak;
			ignoreChanges = false;
		}

		private void OnInsertColumnBreak(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			ignoreChanges = true;
			if (sender == columnBreakToolStripMenuItem)
				pageBreakColumnsContextItem.Checked = columnBreakToolStripMenuItem.Checked;
			else
				columnBreakToolStripMenuItem.Checked = pageBreakColumnsContextItem.Checked;

			int row = ActiveCell.Row;
			int col = ActiveCell.Column;
			if (ActiveCell.IsMerged)
			{
				var c = ActiveSheet.GetMergedCell(ActiveCell);
				row = c.Bottom;
				col = c.Right;
			}

			ActiveSheet.Columns[col].PageBreak = columnBreakToolStripMenuItem.Checked;
			pageBreakToolStripMenuItem.Checked = ActiveSheet.Columns[col].PageBreak && ActiveSheet.Rows[row].PageBreak;
			ignoreChanges = false;
		}

		private void OnInsertRowBreak(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			ignoreChanges = true;
			if (sender == rowBreakToolStripMenuItem)
				pageBreakRowsContextItem.Checked = rowBreakToolStripMenuItem.Checked;
			else
				rowBreakToolStripMenuItem.Checked = pageBreakRowsContextItem.Checked;

			int row = ActiveCell.Row;
			int col = ActiveCell.Column;
			if (ActiveCell.IsMerged)
			{
				var c = ActiveSheet.GetMergedCell(ActiveCell);
				row = c.Bottom;
				col = c.Right;
			}

			ActiveSheet.Rows[row].PageBreak = rowBreakToolStripMenuItem.Checked;
			pageBreakToolStripMenuItem.Checked = ActiveSheet.Columns[col].PageBreak && ActiveSheet.Rows[row].PageBreak;
			ignoreChanges = false;
		}

		private void OnDefineNamedRange(object sender, EventArgs e)
		{
			DefineNamedRangeForm dlg = new DefineNamedRangeForm(workbook, ActiveSheet,
				"", wbview.Selection.Range.ToString());
			if (dlg.ShowDialog(this) == DialogResult.OK && dlg.NamedRange != null)
			{
				workbook.NamedRanges.Add(dlg.NamedRange);
			}
		}

		private void OnManageNames(object sender, EventArgs e)
		{
			ManageNamedRangesForm dlg = new ManageNamedRangesForm(workbook, wbview.Selection.Range);
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				using (workbook.StartCompositeOperation())
					dlg.Apply(workbook);
			}
		}

		private void OnInsertComment(object sender, EventArgs e)
		{
			// Initiate a composite undo operation which will include both  
			// initialization of the annotation object and
			// setting its content by the user during the inplace edit.
			annotationCreateCommand = workbook.StartCompositeOperation();

			if (ActiveCell.Annotation == null)
			{
				// Create the annotation object and associate it with 
				// the active cell.
				using (workbook.StartChangeOperation(ActiveSheet))
					ActiveCell.SetAnnotation("");

				createdAnnotation = ActiveCell.Annotation;

				// Initiate inplace edit for the newly created annotation.
				wbview.BeginEdit(ActiveCell.Annotation);
			}
			else
			{
				createdAnnotation = ActiveCell.Annotation;

				// Initiate inplace edit for the newly created annotation.
				wbview.BeginEdit(ActiveCell.Annotation);
			}
		}

		private void OnInsertHyperlink(object sender, EventArgs e)
		{
			HyperlinkForm dlg = new HyperlinkForm(workbook, ActiveCell.Hyperlink);
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				using (workbook.StartChangeOperation(ActiveSheet))
				{
					if (string.IsNullOrEmpty(dlg.Target))
					{
						ActiveCell.RemoveHyperlink();
						return;
					}
					if (ActiveCell.Hyperlink != null)
					{
						ActiveCell.Hyperlink.Type = dlg.Type;
						ActiveCell.Hyperlink.Target = dlg.Target;
						ActiveCell.Hyperlink.SubTarget = dlg.SubTarget;
					}
					else
						ActiveCell.SetHyperlink(dlg.Type, dlg.Target, dlg.SubTarget);

					ActiveCell.Hyperlink.ToolTip = dlg.ToolTip;
				}
			}
		}

		private void OnInsertPicture(object sender, EventArgs e)
		{
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.Filter = "images|*.png;*.bmp;*.jpg";
			dlg.Title = "Insert Picture";
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				ActiveSheet.Drawing.AddPicture(dlg.FileName,
					ActiveCell.Column, ActiveCell.Row);
			}
		}

		private void OnInsertChart(object sender, EventArgs e)
		{
			using (workbook.StartCompositeOperation())
			{
				bool edit = false;
				if (wbview.Selection.Objects.Count > 0)
				{
					Chart chart = wbview.Selection.Objects.OfType<Chart>().FirstOrDefault();
					if (chart != null)
					{
						new ChartForm(chart).ShowDialog(this);
						edit = true;
					}
				}
				if (!edit)
					new ChartForm(ActiveSheet, SelectedCells.ToString(),
						MindFusion.Spreadsheet.Charts.PlotBy.Column,
						SelectedCells.Right + 1, SelectedCells.Top, null, null).ShowDialog(this);
			}
		}

		#endregion

		#region Format menu handlers

		private void OnClearFormatting(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				SelectedCells.Style.Reset();
		}

		private void OnFormatCells(object sender, EventArgs e)
		{
			// Show the formatting form and apply styles 
			// and locale information to the range.
			FormatForm dlg = new FormatForm(workbook, /*ActiveCell.Style*/SelectedCells.Style, workbook.Locale);
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				using (workbook.StartChangeOperation(ActiveSheet))
				{
					dlg.Apply(SelectedCells.Style);
				}
				UpdateFromActiveCell();
			}
		}

		private void OnHeaderSize(object sender, EventArgs e)
		{
			Measure m = null;
			if (sender == rowHeightToolStripMenuItem ||
				sender == heightRowContextItem)
			{
				for (int r = wbview.Selection.Top; r <= wbview.Selection.Bottom; r++)
				{
					Row row = ActiveSheet.Rows[r];
					if (row.IsHidden)
						continue;
					if (m == null)
						m = row.Height;
					else if (m != row.Height)
					{
						m = ActiveSheet.DefaultRowHeight;
						break;
					}
				}
				HeaderSizeForm dlg = new HeaderSizeForm(workbook, "Row Height", "Height", m);
				if (dlg.ShowDialog(this) == DialogResult.OK)
				{
					using (workbook.StartChangeOperation(ActiveSheet))
						ActiveSheet.Rows[wbview.Selection.Top, wbview.Selection.Bottom].Height = dlg.HeaderSize;
				}
			}
			else if (sender == columnWidthToolStripMenuItem ||
				sender == widthColumnsContextItem)
			{
				for (int c = wbview.Selection.Left; c <= wbview.Selection.Right; c++)
				{
					Column col = ActiveSheet.Columns[c];
					if (col.IsHidden)
						continue;
					if (m == null)
						m = col.Width;
					else if (m != col.Width)
					{
						m = ActiveSheet.DefaultColumnWidth;
						break;
					}
				}
				HeaderSizeForm dlg = new HeaderSizeForm(workbook, "Column Width", "Width", m);
				if (dlg.ShowDialog(this) == DialogResult.OK)
				{
					using (workbook.StartChangeOperation(ActiveSheet))
						ActiveSheet.Columns[wbview.Selection.Left, wbview.Selection.Right].Width = dlg.HeaderSize;
				}
			}
		}

		private void OnFitRows(object sender, EventArgs e)
		{
			wbview.ResizeRowsToFit(wbview.Selection.Top, wbview.Selection.Bottom);
		}

		private void OnHideRows(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				ActiveSheet.Rows[wbview.Selection.Top, wbview.Selection.Bottom].IsHidden = true;
		}

		private void OnUnhideRows(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				ActiveSheet.Rows[wbview.Selection.Top, wbview.Selection.Bottom].IsHidden = false;
		}

		private void OnFitColumns(object sender, EventArgs e)
		{
			wbview.ResizeColumnsToFit(wbview.Selection.Left, wbview.Selection.Right);
		}

		private void OnHideColums(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				ActiveSheet.Columns[wbview.Selection.Left, wbview.Selection.Right].IsHidden = true;
		}

		private void OnUnhideColums(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				ActiveSheet.Columns[wbview.Selection.Left, wbview.Selection.Right].IsHidden = false;
		}

		private void OnFormatSheetMenuOpening(object sender, EventArgs e)
		{
			sheetUnhideToolStripMenuItem.Enabled = workbook.Worksheets.Where(w => !w.Visible).Count() > 0;
		}

		private void OnRenameSheet(object sender, EventArgs e)
		{
			WorksheetRenameForm dlg = new WorksheetRenameForm(workbook, ActiveSheet.Name);
			if (dlg.ShowDialog(this) == DialogResult.OK)
				using (workbook.StartChangeOperation(ActiveSheet))
					ActiveSheet.Name = dlg.WorksheetName;
		}

		private void OnHideSheet(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				ActiveSheet.Visible = false;
		}

		private void OnUnhideSheet(object sender, EventArgs e)
		{
			UnhideSheetsForm frm = new UnhideSheetsForm(workbook);
			if (frm.ShowDialog() == DialogResult.OK)
				frm.Apply();
		}

		private void OnMergreCells(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			ignoreChanges = true;
			if (sender == mergeToolStripButton)
				formatMergeCellsToolStripMenuItem.Checked = mergeToolStripButton.Checked;
			else if (sender == formatMergeCellsToolStripMenuItem)
				mergeToolStripButton.Checked = formatMergeCellsToolStripMenuItem.Checked;
			ignoreChanges = false;

			if (ActiveCell.IsMerged)
				SelectedCells.Unmerge();
			else
			{
				if (!SelectedCells.Merge())
				{
					MessageBox.Show("Cells could not be merged.", "Merge failed", MessageBoxButtons.OK, MessageBoxIcon.Warning);
					ignoreChanges = true;
					formatMergeCellsToolStripMenuItem.Checked = false;
					mergeToolStripButton.Checked = false;
					ignoreChanges = false;
				}
			}
		}

		private void OnConditionalFormat(object sender, EventArgs e)
		{
			ConditionalFormatForm dlg = new ConditionalFormatForm(workbook, ActiveCell.Style);
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				using (workbook.StartChangeOperation(ActiveSheet))
					dlg.Apply(SelectedCells.Style);
			}
		}

		#endregion

		#region Data menu handlers

		private void OnSort(object sender, EventArgs e)
		{
			SortForm dlg = new SortForm(ActiveSheet, SelectedCells);
			if (dlg.ShowDialog(this) == DialogResult.OK)
				dlg.Sort();
		}

		private void OnDataMenuOpening(object sender, EventArgs e)
		{
			if (ActiveSheet == null)
			{
				filterToolStripMenuItem.Enabled = false;
				applyFilterToolStripMenuItem.Enabled = false;
				clearFilterToolStripMenuItem.Enabled = false;
				return;
			}

			filterToolStripMenuItem.Enabled = true;
			filterToolStripMenuItem.Checked = ActiveSheet.AutoFilterMode;
			filterParentToolStripMenuItem.Checked = ActiveSheet.AutoFilterMode;

			if (!ActiveSheet.AutoFilterMode || !ActiveSheet.AutoFilter.On)
			{
				applyFilterToolStripMenuItem.Enabled = false;
				clearFilterToolStripMenuItem.Enabled = false;
			}
			else
			{
				applyFilterToolStripMenuItem.Enabled = true;
				clearFilterToolStripMenuItem.Enabled = true;
			}
		}

		private void OnFilter(object sender, EventArgs e)
		{
			if (ActiveSheet == null)
				return;

			if (ActiveSheet.AutoFilterMode)
			{
				using (workbook.StartChangeOperation(ActiveSheet))
					ActiveSheet.AutoFilterMode = false;
			}
			else
			{
				if (!wbview.Selection.Range.AutoFilter())
				{
					MessageBox.Show(this, "Unable to apply autofiltering to the selected range.",
						"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		private void OnFilterClear(object sender, EventArgs e)
		{
			if (ActiveSheet == null)
				return;

			ActiveSheet.AutoFilter.ShowAllData();
		}

		private void OnFilterApply(object sender, EventArgs e)
		{
			if (ActiveSheet == null)
				return;

			ActiveSheet.AutoFilter.ApplyFilter();
		}

		private void OnValidation(object sender, EventArgs e)
		{
			ValidationForm dlg = new ValidationForm(workbook, ActiveCell.Style.Validation);
			if (dlg.ShowDialog(this) == DialogResult.OK)
			{
				using (workbook.StartChangeOperation(ActiveSheet))
					dlg.Apply(SelectedCells.Validation);
			}
		}

		private void OnOutlineDropDownOpening(object sender, EventArgs e)
		{
			// Update the Group/Ungroup submenus
			var range = wbview.Selection.Range;
			if (range.Top == 0 && range.Bottom == ActiveSheet.Rows.Count - 1 ||
				range.Left == 0 && range.Right == ActiveSheet.Columns.Count - 1)
			{
				// Entire column or columns
				groupToolStripMenuItem.Text = "&Group";
				ungroupToolStripMenuItem.Text = "&Ungroup";
			}
			else
			{
				// Unspecified
				groupToolStripMenuItem.Text = "&Group...";
				ungroupToolStripMenuItem.Text = "&Ungroup...";
			}
		}

		private void OnOutlineGroup(object sender, EventArgs e)
		{
			var range = wbview.Selection.Range;
			bool isColumn = false;
			if (range.Top == 0 && range.Bottom == ActiveSheet.Rows.Count - 1)
			{
				isColumn = true;
			}
			else if (!(range.Left == 0 && range.Right == ActiveSheet.Columns.Count - 1))
			{
				// Ask the user
				GroupForm form = new GroupForm();
				if (form.ShowDialog() != DialogResult.OK)
					return;

				isColumn = form.IsColumn;
			}

			using (workbook.StartChangeOperation(ActiveSheet))
			{
				if (isColumn)
					ActiveSheet.Columns[range.Left, range.Right].Group();
				else
					ActiveSheet.Rows[range.Top, range.Bottom].Group();
			}
		}

		private void OnOutlineUngroup(object sender, EventArgs e)
		{
			var range = wbview.Selection.Range;
			bool isColumn = false;
			if (range.Top == 0 && range.Bottom == ActiveSheet.Rows.Count - 1)
			{
				isColumn = true;
			}
			else if (!(range.Left == 0 && range.Right == ActiveSheet.Columns.Count - 1))
			{
				// Ask the user
				GroupForm form = new GroupForm(true);
				if (form.ShowDialog() != DialogResult.OK)
					return;

				isColumn = form.IsColumn;
			}

			using (workbook.StartChangeOperation(ActiveSheet))
			{
				if (isColumn)
					ActiveSheet.Columns[range.Left, range.Right].Ungroup();
				else
					ActiveSheet.Rows[range.Top, range.Bottom].Ungroup();
			}
		}

		private void OnOutlineClear(object sender, EventArgs e)
		{
			ActiveSheet.Columns[0, ActiveSheet.Columns.Count - 1].OutlineLevel = null;
			ActiveSheet.Rows[0, ActiveSheet.Rows.Count - 1].OutlineLevel = null;
		}

		#endregion

		#region Window menu handlers

		private void OnFreeze(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			bool freeze = freezeToolStripMenuItem.Checked;

			if (freeze)
			{
				using (workbook.StartChangeOperation(ActiveSheet))
				{
					ActiveSheet.FrozenRowCount = Math.Min(ActiveCell.Row, 20);
					ActiveSheet.FrozenColumnCount = Math.Min(ActiveCell.Column, 20);
				}
			}
			else
			{
				using (workbook.StartChangeOperation(ActiveSheet))
				{
					ActiveSheet.FrozenRowCount = 0;
					ActiveSheet.FrozenColumnCount = 0;
				}
			}
		}

		#endregion

		#region Help menu handlers

		private void OnAbout(object sender, EventArgs e)
		{
			new AboutForm().ShowDialog(this);
		}

		private void OnHelp(object sender, EventArgs e)
		{
			OpenHelpLink("/Introduction_0.htm");
		}

		private void OnOpenSample(object sender, EventArgs e)
		{
			if (wbview.Workbook != null)
			{
				if (MessageBox.Show("This will discard all data in the present workbook.\nAre you sure you want to continue?",
					"Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
				{
					CloseWorkbook();
				}
				else
					return;
			}
			// Initialize the workbook.
			InitWorkbook();

			workbook.UndoEnabled = false;
			CreateData();
			workbook.UndoEnabled = true;
			UpdateSelectionLabel();
			UpdateSumLabel();
			UpdateFormHeader();
		}

		#endregion

		#region Cell context menu handlers

		private void OnCellContextOpening(object sender, CancelEventArgs e)
		{
			if (ActiveCell.Annotation != null)
			{
				insertCmntCellContextItem.Text = "Edit Comment";
				deleteCmntCellContextItem.Visible = true;
				showCmntCellContextItem.Visible = true;
				showCmntCellContextItem.Checked = ActiveCell.Annotation.ShowAlways;
			}
			else
			{
				insertCmntCellContextItem.Text = "Insert Comment";
				deleteCmntCellContextItem.Visible = false;
				showCmntCellContextItem.Visible = false;
			}

			deleteHypCellContextItem.Visible = ActiveCell.Hyperlink != null;
		}

		private void OnRemoveComment(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				ActiveCell.RemoveAnnotation();
		}

		private void OnShowComment(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				ActiveCell.Annotation.ShowAlways = showCmntCellContextItem.Checked;
		}

		private void OnDeleteHyperlink(object sender, EventArgs e)
		{
			using (workbook.StartChangeOperation(ActiveSheet))
				ActiveCell.RemoveHyperlink();
		}

		#endregion

		#region Columns context menu handlers

		private void OnColumnContextOpening(object sender, CancelEventArgs e)
		{
			pageBreakColumnsContextItem.Enabled = ActiveCell.Column != 0;
			ignoreChanges = true;
			pageBreakColumnsContextItem.Checked = ActiveSheet.Columns[ActiveCell.Column].PageBreak;
			ignoreChanges = false;
		}

		private void OnDeleteColumns(object sender, EventArgs e)
		{
			using (var cmd = workbook.StartChangeOperation(ActiveSheet))
			{
				ActiveSheet.Columns.Remove(SelectedCells.Left,
					1 + Math.Abs(SelectedCells.Right - SelectedCells.Left));
			}
		}

		#endregion

		#region Rows context menu handlers

		private void OnRowContextOpening(object sender, CancelEventArgs e)
		{
			pageBreakRowsContextItem.Enabled = ActiveCell.Row != 0;
			ignoreChanges = true;
			pageBreakRowsContextItem.Checked = ActiveSheet.Rows[ActiveCell.Row].PageBreak;
			ignoreChanges = false;
		}

		private void OnDeleteRows(object sender, EventArgs e)
		{
			using (var cmd = workbook.StartChangeOperation(ActiveSheet))
			{
				ActiveSheet.Rows.Remove(SelectedCells.Top,
					1 + Math.Abs(SelectedCells.Bottom - SelectedCells.Top));
			}
		}

		#endregion

		#region Sheet context menu hanlders

		private void OnSheetContextOpening(object sender, CancelEventArgs e)
		{
			deleteSheetContextItem.Enabled = workbook.Worksheets.Where(w => w.Visible).Count() > 1;
			hideSheetContextItem.Enabled = workbook.Worksheets.Where(w => w.Visible).Count() > 1;
			unhideSheetContextItem.Enabled = workbook.Worksheets.Where(w => !w.Visible).Count() > 0;
		}

		#endregion

		#region Object context menu handlers

		private void OnObjectContextOpening(object sender, CancelEventArgs e)
		{
			chartPropertiesObjectContextItem.Visible = wbview.Selection.Objects.Count == 1 && wbview.Selection.Objects[0] is Chart;
		}

		private void OnChartProperties(object sender, EventArgs e)
		{
			if (wbview.Selection.Objects.Count != 1 || !(wbview.Selection.Objects[0] is Chart))
				return;
			Chart chart = wbview.Selection.Objects[0] as Chart;
			using (workbook.StartCompositeOperation())
			using (workbook.StartChangeOperation(ActiveSheet))
				new ChartForm(chart).ShowDialog(this);
		}

		private void OnDeleteObject(object sender, EventArgs e)
		{
			if (wbview.Selection.Objects.Count == 0)
				return;

			using (workbook.StartCompositeOperation())
				for (int i = wbview.Selection.Objects.Count - 1, l = 0; i >= l; i--)
				{
					InteractiveObject obj = wbview.Selection.Objects[i];
					if (obj is CellAnnotation)
						using (workbook.StartChangeOperation(ActiveSheet))
							(obj as CellAnnotation).Parent.Remove();
					else
						ActiveSheet.Drawing.Remove(obj);
				}
		}

		#endregion

		#region Standard toolstrip handlers

		private void OnFontNameChanged(object sender, EventArgs e)
		{
			if (workbook == null || ignoreChanges)
				return;
			if (SelectedCells.Style.FontName != fontNameToolStripComboBox.Text &&
				fontNameToolStripComboBox.Items.Contains(fontNameToolStripComboBox.Text))
				using (workbook.StartChangeOperation(ActiveSheet))
					SelectedCells.Style.FontName = fontNameToolStripComboBox.Text;
		}

		private void OnFontSizeChanged(object sender, EventArgs e)
		{
			if (workbook == null || ignoreChanges)
				return;
			using (workbook.StartChangeOperation(ActiveSheet))
			{
				double value;
				if (double.TryParse(fontSizeToolStripComboBox.Text, out value) &&
					SelectedCells.Style.FontSize != value)
					SelectedCells.Style.FontSize = value;
			}
		}

		private void OnBoldChecked(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			using (workbook.StartChangeOperation(ActiveSheet))
				SelectedCells.Style.FontBold = boldToolStripButton.Checked;
		}

		private void OnItalicChecked(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			using (workbook.StartChangeOperation(ActiveSheet))
				SelectedCells.Style.FontItalic = italicToolStripButton.Checked;
		}

		private void OnUnderlineChecked(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			using (workbook.StartChangeOperation(ActiveSheet))
				SelectedCells.Style.FontUnderline = underlineToolStripButton.Checked;
		}

		private void OnZoomChanged(object sender, EventArgs e)
		{
			ApplyZoom();
		}

		private void OnZoomKeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Return)
				ApplyZoom();
		}

		void ApplyZoom()
		{
			if (workbook == null || ActiveSheet == null || ignoreChanges)
				return;

			int value;
			if (int.TryParse(zoomToolStripComboBox.ComboBox.Text, out value))
			{
				ActiveSheet.Zoom = value;
				zoomToolStripComboBox.ComboBox.Text = ActiveSheet.Zoom.ToString();
				zoomToolStripComboBox.ComboBox.SelectAll();
			}
		}

		private void OnAlignChanged(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			ignoreChanges = true;
			if (sender == leftAlignToolStripButton)
			{
				centerAlignToolStripButton.Checked = false;
				rightAlignToolStripButton.Checked = false;
				using (workbook.StartChangeOperation(ActiveSheet))
					SelectedCells.Style.HorizontalAlignment =
						leftAlignToolStripButton.Checked ?
						HorizontalAlignment.Left : HorizontalAlignment.Default;
			}
			else if (sender == centerAlignToolStripButton)
			{
				leftAlignToolStripButton.Checked = false;
				rightAlignToolStripButton.Checked = false;
				using (workbook.StartChangeOperation(ActiveSheet))
					SelectedCells.Style.HorizontalAlignment =
						centerAlignToolStripButton.Checked ?
						HorizontalAlignment.Center : HorizontalAlignment.Default;
			}
			else if (sender == rightAlignToolStripButton)
			{
				leftAlignToolStripButton.Checked = false;
				centerAlignToolStripButton.Checked = false;
				using (workbook.StartChangeOperation(ActiveSheet))
					SelectedCells.Style.HorizontalAlignment =
						rightAlignToolStripButton.Checked ?
						HorizontalAlignment.Right : HorizontalAlignment.Default;
			}
			ignoreChanges = false;
		}

		private void OnVAlignClicked(object sender, EventArgs e)
		{
			valignSplitButton.DefaultItem = sender as ToolStripItem;
			valignSplitButton.Image = (sender as ToolStripItem).Image;

			using (workbook.StartChangeOperation(ActiveSheet))
			{
				IStyle st = SelectedCells.Style;
				if (sender == valignTopToolStripMenuItem)
					st.VerticalAlignment = VerticalAlignment.Top;
				else if (sender == valignMiddleToolStripMenuItem)
					st.VerticalAlignment = VerticalAlignment.Middle;
				else if (sender == valignBottomToolStripMenuItem)
					st.VerticalAlignment = VerticalAlignment.Bottom;
			}
		}

		private void OnQuickFormatChanged(object sender, EventArgs e)
		{
			if (ignoreChanges)
				return;
			ignoreChanges = true;

			if (sender == currencyToolStripButton)
			{
				percentToolStripButton.Checked = false;
				using (workbook.StartChangeOperation(ActiveSheet))
					SelectedCells.Style.Format = currencyToolStripButton.Checked ?
						GetCurrencyFormat() : "General";
			}
			else if (sender == percentToolStripButton)
			{
				currencyToolStripButton.Checked = false;
				using (workbook.StartChangeOperation(ActiveSheet))
					SelectedCells.Style.Format = percentToolStripButton.Checked ?
						workbook.DefaultNumericFormats.PercentFormats[1].Format : "General";
			}
			ignoreChanges = false;
		}

		private void OnDecreaseIndent(object sender, EventArgs e)
		{
			double value = new Measure(5, MeasureUnit.Pixel).ConvertTo(
				SelectedCells.Style.Indent.Unit, resolution).Amount;
			using (workbook.StartChangeOperation(ActiveSheet))
			{
				SelectedCells.Style.Indent -= value;
			}
		}

		private void OnIncreaseIndent(object sender, EventArgs e)
		{
			double value = new Measure(5, MeasureUnit.Pixel).ConvertTo(
				SelectedCells.Style.Indent.Unit, resolution).Amount;
			using (workbook.StartChangeOperation(ActiveSheet))
			{
				SelectedCells.Style.Indent += value;
			}
		}

		private void OnBordersClick(object sender, EventArgs e)
		{
			bordersToolStripSplitButton.DefaultItem = sender as ToolStripItem;
			bordersToolStripSplitButton.Image = (sender as ToolStripItem).Image;

			using (workbook.StartChangeOperation(ActiveSheet))
			{
				IStyle st = SelectedCells.Style;
				// no borders
				if (sender == bordersNoneToolStripMenuItem)
				{
					st.BorderBottomColor = st.BorderLeftColor =
						st.BorderRightColor = st.BorderTopColor =
						st.PrimaryDiagonalColor = st.SecondaryDiagonalColor = null;
					st.BorderBottomStyle = st.BorderLeftStyle =
						st.BorderRightStyle = st.BorderTopStyle =
						st.PrimaryDiagonalStyle = st.SecondaryDiagonalStyle = null;
					st.BorderBottomSize = st.BorderLeftSize =
						st.BorderRightSize = st.BorderTopSize =
						st.PrimaryDiagonalSize = st.SecondaryDiagonalSize = null;
				}
				// outer borders
				else if (sender == bordersOuterToolStripMenuItem)
				{
					st.BorderBottomColor = st.BorderLeftColor =
						st.BorderRightColor = st.BorderTopColor = Color.Black;
					st.PrimaryDiagonalColor = st.SecondaryDiagonalColor = null;
					st.BorderBottomStyle = st.BorderLeftStyle =
						st.BorderRightStyle = st.BorderTopStyle = DashStyle.Solid;
					st.PrimaryDiagonalStyle = st.SecondaryDiagonalStyle = null;
					st.BorderBottomSize = st.BorderLeftSize =
						st.BorderRightSize = st.BorderTopSize = new Measure(1);
					st.PrimaryDiagonalSize = st.SecondaryDiagonalSize = null;
				}
				// diagonals
				else if (sender == bordersDiagonalsToolStripMenuItem)
				{
					st.BorderBottomColor = st.BorderLeftColor =
						st.BorderRightColor = st.BorderTopColor = null;
					st.PrimaryDiagonalColor = st.SecondaryDiagonalColor = Color.Black;
					st.BorderBottomStyle = st.BorderLeftStyle =
						st.BorderRightStyle = st.BorderTopStyle = null;
					st.PrimaryDiagonalStyle = st.SecondaryDiagonalStyle = DashStyle.Solid;
					st.BorderBottomSize = st.BorderLeftSize =
						st.BorderRightSize = st.BorderTopSize = null;
					st.PrimaryDiagonalSize = st.SecondaryDiagonalSize = new Measure(1);
				}
				// left border
				else if (sender == bordersLeftToolStripMenuItem)
				{
					st.BorderLeftColor = Color.Black;
					st.BorderLeftStyle = DashStyle.Solid;
					st.BorderLeftSize = new Measure(1);
				}
				// top border
				else if (sender == bordersTopToolStripMenuItem)
				{
					st.BorderTopColor = Color.Black;
					st.BorderTopStyle = DashStyle.Solid;
					st.BorderTopSize = new Measure(1);
				}
				// right border
				else if (sender == bordersRightToolStripMenuItem)
				{
					st.BorderRightColor = Color.Black;
					st.BorderRightStyle = DashStyle.Solid;
					st.BorderRightSize = new Measure(1);
				}
				// bottom border
				else if (sender == bordersBottomToolStripMenuItem)
				{
					st.BorderBottomColor = Color.Black;
					st.BorderBottomStyle = DashStyle.Solid;
					st.BorderBottomSize = new Measure(1);
				}
				// all borders
				else if (sender == bordersAllToolStripMenuItem)
				{
					st.BorderBottomColor = st.BorderLeftColor =
						st.BorderRightColor = st.BorderTopColor =
						st.PrimaryDiagonalColor = st.SecondaryDiagonalColor = Color.Black;
					st.BorderBottomStyle = st.BorderLeftStyle =
						st.BorderRightStyle = st.BorderTopStyle =
						st.PrimaryDiagonalStyle = st.SecondaryDiagonalStyle = DashStyle.Solid;
					st.BorderBottomSize = st.BorderLeftSize =
						st.BorderRightSize = st.BorderTopSize =
						st.PrimaryDiagonalSize = st.SecondaryDiagonalSize = new Measure(1);
				}


			}
		}

		private void OnColorSplitButtonPaint(object sender, PaintEventArgs e)
		{
			ListBox lst = splits[sender as ToolStripSplitButton];
			if (lst.SelectedItem == null)
				return;

			Color clr = (Color)lst.SelectedItem;
			if (clr.IsEmpty)
				clr = (Color)lst.Tag;

			Rectangle bounds = new Rectangle(2, 15, 16, 4);
			using (Brush b = new SolidBrush(clr))
				e.Graphics.FillRectangle(b, bounds);
		}

		private void OnToolStripDropDownOpening(ToolStripDropDownItem btn, ListBox lst)
		{
			Panel pnl = new Panel();
			pnl.Size = new Size(210, 440);
			pnl.Padding = new Padding(0);
			pnl.Margin = new Padding(0);
			pnl.BorderStyle = BorderStyle.FixedSingle;
			lst.Size = pnl.Size;
			ToolStripControlHost host = new ToolStripControlHost(pnl);
			host.Size = pnl.Size;
			host.Margin = pnl.Margin;
			ToolStripDropDown dropDown = new ToolStripDropDown();
			dropDown.Padding = pnl.Padding;
			dropDown.Items.Add(host);
			pnl.Controls.Add(lst);

			lst.Click += (s, e) => { dropDown.Close(ToolStripDropDownCloseReason.ItemClicked); };

			dropDown.Show(this, new Point(btn.Bounds.Left + btn.Owner.Left, btn.Bounds.Bottom + btn.Owner.Top + btn.Height));
		}

		private void OnColorDropDownDrawItem(object sender, DrawItemEventArgs e)
		{
			if (e.Index == -1)
				return;
			ListBox lst = sender as ListBox;
			e.DrawBackground();
			e.DrawFocusRectangle();
			Brush backBrush;
			Brush foreBrush;
			if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled)
			{
				backBrush = new SolidBrush(SystemColors.Control);
				foreBrush = new SolidBrush(SystemColors.ControlDark);
			}
			else if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
			{
				backBrush = new SolidBrush(SystemColors.Highlight);
				foreBrush = new SolidBrush(SystemColors.HighlightText);
			}
			else
			{
				backBrush = new SolidBrush(lst.BackColor);
				foreBrush = new SolidBrush(lst.ForeColor);
			}
			e.Graphics.FillRectangle(backBrush, e.Bounds);
			Color item = (Color)lst.Items[e.Index];
			Rectangle colorBox = new Rectangle(e.Bounds.X + 2, e.Bounds.Y + 2, 20, e.Bounds.Height - 4);
			if (!item.IsEmpty)
				using (var b = new System.Drawing.SolidBrush(item))
					e.Graphics.FillRectangle(b, colorBox);
			else
				using (var b = new System.Drawing.SolidBrush((Color)lst.Tag))
					e.Graphics.FillRectangle(b, colorBox);
			e.Graphics.DrawRectangle(Pens.Black, colorBox);
			e.Graphics.DrawString(item.IsEmpty ? "Automatic" : item.Name, Font, foreBrush, colorBox.Right + 5, e.Bounds.Top + 4);
			foreBrush.Dispose();
			backBrush.Dispose();
		}

		#endregion

		#region Object properties toolstrip handlers

		private void OnStyleComboDrawItem(object sender, DrawItemEventArgs e)
		{
			if (e.Index == -1)
				return;
			ComboBox cmb = sender as ComboBox;
			e.DrawBackground();
			e.DrawFocusRectangle();
			Brush backBrush;
			Brush foreBrush;
			if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled)
			{
				backBrush = new SolidBrush(SystemColors.Control);
				foreBrush = new SolidBrush(SystemColors.ControlDark);
			}
			else if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
			{
				backBrush = new SolidBrush(SystemColors.Highlight);
				foreBrush = new SolidBrush(SystemColors.HighlightText);
			}
			else
			{
				backBrush = new SolidBrush(cmb.BackColor);
				foreBrush = new SolidBrush(cmb.ForeColor);
			}
			e.Graphics.FillRectangle(backBrush, e.Bounds);
			if (e.Index == 0)
				e.Graphics.DrawString("Automatic", Font, foreBrush, e.Bounds.Left, e.Bounds.Top + 3);
			else
			{
				DashStyle ds = (DashStyle)Enum.Parse(typeof(DashStyle), cmb.Items[e.Index].ToString());
				using (var p = new Pen(foreBrush, 2f))
				{
					p.DashStyle = ds;
					e.Graphics.DrawLine(p, e.Bounds.Left + 5, e.Bounds.Top + 10, e.Bounds.Right - 5, e.Bounds.Top + 10);
				}
			}
			foreBrush.Dispose();
			backBrush.Dispose();
		}

		private void OnLineStyleChanged(object sender, EventArgs e)
		{
			if (wbview.Selection.Objects.Count == 0)
				return;
			using (workbook.StartChangeOperation(ActiveSheet))
				foreach (InteractiveObject obj in wbview.Selection.Objects)
				{
					if (objectLineStyleToolStripComboBox.SelectedIndex == 0)
						obj.LineStyle = null;
					else
						obj.LineStyle = (DashStyle)Enum.Parse(typeof(DashStyle), objectLineStyleToolStripComboBox.Text);
				}
		}

		private void OnLineSizeChanged(object sender, EventArgs e)
		{
			if (wbview.Selection.Objects.Count == 0)
				return;
			using (workbook.StartChangeOperation(ActiveSheet))
				foreach (InteractiveObject obj in wbview.Selection.Objects)
					obj.LineSize = ParseMeasure(objectLineSizeToolStripTextBox.Text, obj.LineSize);
		}

		private void OnLineSizeTextBoxLeave(object sender, EventArgs e)
		{
			if (wbview.Selection.Objects.Count == 0)
				return;
			Measure lsize = wbview.Selection.Objects[wbview.Selection.Objects.Count - 1].LineSize;
			objectLineSizeToolStripTextBox.Text = lsize != null ? lsize.ToString() : "";
		}

		private void OnObjectAnchorChecked(object sender, EventArgs e)
		{
			if (wbview.Selection.Objects.Count == 0 || ignoreChanges)
				return;
			ignoreChanges = true;
			if (wbview.Selection.Objects[0] is CellAnnotation)
			{
				objectAnchorToCellToolStripMenuItem.Checked = true;
				objectAnchorToPageToolStripMenuItem.Checked = false;
				ignoreChanges = false;
				return;
			}
			if (sender == objectAnchorToCellToolStripMenuItem)
				objectAnchorToPageToolStripMenuItem.Checked = !objectAnchorToCellToolStripMenuItem.Checked;
			else
				objectAnchorToCellToolStripMenuItem.Checked = !objectAnchorToPageToolStripMenuItem.Checked;
			ObjectAnchor anchor = (sender == objectAnchorToCellToolStripMenuItem ? ObjectAnchor.ToCell : ObjectAnchor.ToPage);
			using (workbook.StartChangeOperation(ActiveSheet))
				foreach (InteractiveObject obj in wbview.Selection.Objects)
				{
					if (obj.Anchor == anchor)
						continue;
					if (anchor == ObjectAnchor.ToCell)
					{
						var cell = wbview.GetCellAt(obj.HorizontalOffset, obj.VerticalOffset);
						var hoff = wbview.ToLocalX(obj.HorizontalOffset, cell.Column, cell.Row);
						var voff = wbview.ToLocalY(obj.VerticalOffset, cell.Column, cell.Row);
						obj.FromColumn = cell.Column;
						obj.FromRow = cell.Row;
						obj.HorizontalOffset = hoff;
						obj.VerticalOffset = voff;
					}
					else if (anchor == ObjectAnchor.ToPage)
					{
						var hoff = wbview.ToGlobalX(obj.HorizontalOffset, obj.FromColumn, obj.FromRow);
						var voff = wbview.ToGlobalY(obj.VerticalOffset, obj.FromColumn, obj.FromRow);
						obj.HorizontalOffset = hoff;
						obj.VerticalOffset = voff;
					}
					obj.Anchor = anchor;
				}
			ignoreChanges = false;
		}

		private void OnObjectOrder(object sender, EventArgs e)
		{
			if (wbview.Selection.Objects.Count == 0)
				return;

			using (workbook.StartChangeOperation(ActiveSheet))
				foreach (InteractiveObject obj in wbview.Selection.Objects.ToList())
				{
					if (sender == objectForwardToolStripButton)
						obj.BringForward();
					else if (sender == objectBackwardsToolStripButton)
						obj.SendBackward();
					else if (sender == objectToFrontToolStripButton)
						obj.BringToFront();
					else if (sender == objectToBackToolStripButton)
						obj.SendToBack();
				}
		}

		#endregion

		#region Properties

		public Worksheet ActiveSheet
		{
			get { return wbview.ActiveWorksheet; }
			set { wbview.ActiveWorksheet = value; }
		}

		public Cell ActiveCell
		{
			get { return wbview.ActiveCell; }
			set { wbview.ActiveCell = value; }
		}

		public CellRange SelectedCells
		{
			get
			{
				if (ActiveSheet == null)
					return null;
				return wbview.Selection.Range;
			}
		}

		public bool IsSheetSelected
		{
			get
			{
				return wbview.Selection.Left == 0 && wbview.Selection.Right == 0x400 - 1
					&& wbview.Selection.Top == 0 && wbview.Selection.Bottom == 0x100000 - 1;
			}
		}

		public bool IsSingleCellSelected
		{
			get
			{
				return wbview.Selection.Left == wbview.Selection.Right &&
					wbview.Selection.Top == wbview.Selection.Bottom;
			}
		}

		#endregion

		#region Fields

		private Workbook workbook = null;
		private string currentFileName = "";
		Annotation createdAnnotation;
		Command annotationCreateCommand;
		private bool ignoreChanges = false;
		private string cachedCurrencyFormat;
		private static readonly Regex urlRegex = new Regex(@"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)");
		private static readonly Regex sheetNameRegex = new Regex(@".*(?=[!\.])");
		private readonly object resolution;
		private Dictionary<ToolStripSplitButton, ListBox> splits = new Dictionary<ToolStripSplitButton, ListBox>();
		private string helpFilePath;
		string languagesFolder;
		private static readonly string helpFileName = "*.chm";

		#endregion
	}
}


