[Gtk-sharp-list] DataGrid control, data binding, ObjectViews, Swf, Gtk

Gennadiy Donchyts don at env.com.ua
Tue Dec 13 14:55:43 EST 2005


Skipped content of type multipart/alternative-------------- next part --------------
// Namespace: ME.Common.Forms.GtkSharp.DataGrid, File: DataGrid.cs
// Code lines: 535, Size of file: 13,50 KB
// Author: 
//           Kristian Rietveld <kris at gtk.org>
//           Daniel Morgan <danielmorgan at verizon.net>
//           Gennadiy Donchyts <don at env.com.ua>
// Creation date: 19.11.2005 1:44
// Last modified: 07.12.2005 1:01
//
// (c) 2002 Kristian Rietveld
// (c) 2002-2005 Daniel Morgan
// (c) 2005 Gennadiy Donchyts

#region Using directives
using System;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

using GLib;
using Gtk;
#endregion

namespace ME.Common.Forms.GtkSharp.DataGrid
{
	/// <summary>
	/// Data grid column
	/// </summary>
	public class DataGridColumn
	{
		private string columnName = "";
		private TreeViewColumn treeViewColumn = null;
		internal CellRenderer Renderer = null;
		private Type type = null;
		private bool readOnly = false;

		public bool ReadOnly
		{
			get { return this.readOnly; }
			set { this.readOnly = value; }
		}

		public Type Type 
		{
			get { return this.type; }
			set { this.type = value; }
		}

		public string ColumnName 
		{
			get { return this.columnName; }
			set { this.columnName = value; }
		}

		public TreeViewColumn TreeViewColumn 
		{
			get { return this.treeViewColumn; }
			set { this.treeViewColumn = value; }
		}
	}

	/// <summary>
	/// Data grid
	/// </summary>
	/// <returns>VBox</returns>
	public class DataGrid : VBox 
	{
		private ListStore store;
		private Gtk.TreeView treeView;
		private ArrayList gridColumns; // TODO: make Columns a collection

		private ArrayList bindrows = null;
		private object resolvedDataSource = null;
		private bool editable = true;
		private object dataSource;
		private string dataMember;

		/// <summary>
		/// Create data grid
		/// </summary>
		public DataGrid() : base(false, 4)
		{
			ScrolledWindow sw = new ScrolledWindow();
			this.PackStart(sw, true, true, 0);

			this.treeView = new Gtk.TreeView(this.store);
			this.treeView.HeadersVisible = true;
			//treeView.ModifyFont(Pango.FontDescription.FromString("courier new"));

			this.KeyPressEvent +=new KeyPressEventHandler(OnKeyPressEvent);

			this.gridColumns = new ArrayList(0);

			sw.Add(this.treeView);

			this.store = new ListStore(GLib.GType.String);

			this.treeView.EnableSearch = true;
			this.treeView.HeadersClickable = true;
			this.dataMember = "";
			this.dataSource = null;
		}

		/// <summary>
		/// Selected row
		/// </summary>
		/// <returns>Int</returns>
		public int SelectedRow 
		{
			get 
			{
				TreeIter iter;
				TreeModel model;
				TreeSelection selection = this.treeView.Selection;
				if (selection.GetSelected(out model, out iter)) 
				{
					TreePath[] path = selection.GetSelectedRows(out model);
					return path[0].Indices[0]; // return selected row
				}
				else
				{
					return -1; // not selected
				}
			}
		}

		/// <summary>
		/// Show headers
		/// </summary>
		/// <returns>Bool</returns>
		public bool HeadersVisible
		{
			get { return this.treeView.HeadersVisible; }
			set { this.treeView.HeadersVisible = value; }
		}

		/// <summary>
		/// Selected iter
		/// </summary>
		/// <returns>Tree iter</returns>
		public TreeIter SelectedIter 
		{
			get 
			{
				TreeIter iter;
				TreeModel model;
				TreeSelection selection = this.treeView.Selection;
				if (selection.GetSelected(out model, out iter))
				{
					return iter; // return seelcted iter
				}
				else
				{
					return TreeIter.Zero; // not selected
				}
			}

		}

		/// <summary>
		/// View
		/// </summary>
		/// <returns>Tree view</returns>
		public Gtk.TreeView View
		{
			get { return this.treeView; }
		}

		/// <summary>
		/// Data source
		/// </summary>
		/// <returns>Object</returns>
		public object DataSource
		{
			get { return this.dataSource; }
			set 
			{ 
				this.dataSource = value; 
				DataBind();
			}
		}

		/// <summary>
		/// Data member
		/// </summary>
		/// <returns>String</returns>
		public string DataMember
		{
			get { return dataMember; }
			set { dataMember = value; }
		}

		/// <summary>
		/// Store
		/// </summary>
		/// <returns>List store</returns>
		public ListStore Store
		{
			get { return store; }
		}

		/// <summary>
		/// Columns
		/// </summary>
		/// <returns>Array list</returns>
		public ArrayList Columns
		{
			get { return gridColumns; }
		}

		/// <summary>
		/// TODO: not a good way to see if its editable or not? 
		/// because various columns could be editable and others non-editable
		/// </summary>
		public bool Editable 
		{
			get { return this.editable; }

			set 
			{
				this.editable = value;
				if (value == true) 
				{
					for (int c = 0; c < this.gridColumns.Count; c++) 
					{
						DataGridColumn col = (DataGridColumn) this.gridColumns[c];
						col.TreeViewColumn.Clickable = true;
						col.Renderer.Mode = CellRendererMode.Editable;

						if(col.Renderer is CellRendererText)
						{
							(col.Renderer as CellRendererText).Editable = !col.ReadOnly; // column has higher piority
						}
					}
					this.treeView.RulesHint = true;
					this.treeView.Selection.Mode = SelectionMode.Single;
				}
				else 
				{
					for (int c = 0; c < this.gridColumns.Count; c++) 
					{
						DataGridColumn col = (DataGridColumn) this.gridColumns[c];
						col.Renderer.Mode = CellRendererMode.Inert;
						if(col.Renderer is CellRendererText)
						{
							// TODO: look on the binded data for columns if it is editable
							(col.Renderer as CellRendererText).Editable = false;
							(col.Renderer as CellRendererText).Edited -= new EditedHandler(TextCellEdited);
						}

					}
					this.treeView.RulesHint = false;
					this.treeView.Selection.Mode = SelectionMode.Single;
				}
			}
		}

		/// <summary>
		/// Add new
		/// </summary>
		/// <returns>Int</returns>
		public int AddNew()
		{
			// TODO: need to check if resolved data source is not null

			IBindingList b = (IBindingList) this.resolvedDataSource;

			if (b.AllowNew) 
			{
				object obj = b.AddNew();
				if (obj == null) 
				{
					//Console.Error.WriteLine("obj is null");
				}
				else 
				{
					//Console.Error.WriteLine("Type: " + obj.GetType().ToString());
					this.bindrows.Add(obj);

					TreeIter iter = NewRow();
					for (int i = 0; i < this.gridColumns.Count; i++)
						SetColumnValue(iter, i, String.Empty);

					return this.bindrows.Count - 1;
				}
			}

			return -1;
		}

		/// <summary>
		/// Delete row
		/// </summary>
		/// <param name="row">Row</param>
		/// <returns>Int</returns>
		public int DeleteRow(int row)
		{
			if (row < 0)
			{
				throw new ArgumentOutOfRangeException("row", row, "Row number does not exists");
			}

			TreeIter iter = TreeIter.Zero;
			if (this.store.IterNthChild(out iter, row) == false)
			{
				return -1;
			}

			IBindingList b = (IBindingList) this.resolvedDataSource;
			if (b.AllowRemove) 
			{
				IList list = (IList) this.resolvedDataSource;
				this.bindrows.RemoveAt(row);
				this.store.Remove(ref iter);
				list.RemoveAt(row);

				return row;
			}

			return -1;
		}

		// sets the column count.  beware, it clears
		// use this if you are going to load each column and row yourself
		// instead of using DataBind() or DataLoad()
		public void SetColumnCount(int columnCount)
		{
			Clear();
			this.dataMember = "";
			this.dataSource = null;

			GLib.GType[] theTypes = new GLib.GType[columnCount];
			this.gridColumns = new ArrayList();
			for (int col = 0; col < columnCount; col++)
			{
				theTypes[col] = GLib.GType.String;
				this.gridColumns.Add(new DataGridColumn());
			}
			this.store.ColumnTypes = theTypes;
		}

		// load data from a data table or data set
		public long DataBind()
		{
			long rowsRetrieved = 0;

			Clear();

			System.Object o = null;
			o = GetResolvedDataSource(DataSource, DataMember);
			this.resolvedDataSource = o;
			IEnumerable ie = (IEnumerable) o;
			ITypedList tlist = (ITypedList) o;
			TreeIter iter = new TreeIter();

			PropertyDescriptorCollection pdc = tlist.GetItemProperties(new PropertyDescriptor[0]);
			this.gridColumns = new ArrayList(pdc.Count);

			// define the columns in the treeview store
			// based on the schema of the result
			GLib.GType[] theTypes = new GLib.GType[pdc.Count];
			for (int col = 0; col < pdc.Count; col++) 
			{
				if (pdc[col].PropertyType == typeof(int)) // this is temporary solution, change it to something better
				{
					theTypes[col] = GLib.GType.Int;
				}
				else if (pdc[col].PropertyType == typeof(double)) // this is temporary solution
				{
					theTypes[col] = GLib.GType.String;
				}
				else if (pdc[col].PropertyType == typeof(bool)) // this is temporary solution
				{
					theTypes[col] = GLib.GType.Boolean;
				}
				else
				{
					theTypes[col] = GLib.GType.String;
				}
			}
			this.store.ColumnTypes = theTypes;

			this.bindrows = new ArrayList();

			int colndx = -1;
			foreach (PropertyDescriptor pd in pdc) 
			{
				colndx ++;

				DataGridColumn gridCol = new DataGridColumn();
				gridCol.ColumnName = pd.Name;
				gridCol.Type = pd.PropertyType;
				gridCol.ReadOnly = pd.IsReadOnly;
				this.gridColumns.Add(gridCol);
			}

			this.bindrows = new ArrayList();

			foreach (System.Object obj in ie) 
			{
				ICustomTypeDescriptor custom = (ICustomTypeDescriptor)obj;
				PropertyDescriptorCollection properties = custom.GetProperties();

				this.bindrows.Add(obj);

				rowsRetrieved ++;
				iter = NewRow();
				int cv = 0;
				foreach (PropertyDescriptor property in properties) 
				{
					object oPropValue = property.GetValue(obj);
					// string sPropValue = "";
					if (oPropValue.GetType().ToString().Equals("System.Byte[]"))  
					{
						//sPropValue = SqlSharpGtk.GetHexString((byte[]) oPropValue);
						Console.Error.WriteLine("Byte[]  value");
						// SetColumnValue(iter, cv, sPropValue);
					}
					if (oPropValue.GetType() == typeof(DateTime))  
					{
						SetColumnValue(iter, cv, oPropValue.ToString());
					}
					else // FIXME: some temporary hack to show any type value here, will work only to some limited types
					{
						SetColumnValue(iter, cv, oPropValue);
					}
					cv++;
				}
			}

			this.treeView.Model = store;
			AutoCreateTreeViewColumns();
			return rowsRetrieved;
		}

		// borrowed from Mono's System.Web implementation
		protected IEnumerable GetResolvedDataSource(object source, string member)
		{
			if (source != null && source is IListSource) 
			{
				IListSource src = (IListSource) source;
				IList list = src.GetList();
				if (!src.ContainsListCollection) 
				{
					return list;
				}
				if (list != null && list is ITypedList) 
				{
					ITypedList tlist = (ITypedList) list;
					PropertyDescriptorCollection pdc = tlist.GetItemProperties(new PropertyDescriptor[0]);
					if (pdc != null && pdc.Count > 0) 
					{
						PropertyDescriptor pd = null;
						if (member != null && member.Length > 0) 
						{
							pd = pdc.Find(member, true);
						} 
						else 
						{
							pd = pdc[0];
						}
						if (pd != null) 
						{
							object rv = pd.GetValue(list[0]);
							if (rv != null && rv is IEnumerable) 
							{
								return (IEnumerable)rv;
							}
						}
						throw new Exception("ListSource_Missing_DataMember");
					}
					throw new Exception("ListSource_Without_DataMembers");
				}
			}
			if (source is IEnumerable) 
			{
				return (IEnumerable)source;
			}
			return null;
		}

		public void Clear()
		{
			if (this.store != null)
			{
				this.store.Clear();
				this.store = null;
				this.store = new ListStore(GLib.GType.String);
			}
			else
				this.store = new ListStore(GLib.GType.String);

			if (this.gridColumns != null)
			{
				for (int c = 0; c < this.gridColumns.Count; c++)
				{
					DataGridColumn gridCol = (DataGridColumn) this.gridColumns[c];
					if (gridCol.TreeViewColumn != null)
					{
						this.treeView.RemoveColumn(gridCol.TreeViewColumn);
						gridCol.TreeViewColumn = null;
					}
				}
				this.gridColumns.Clear();
				this.gridColumns = null;
			}
		}

		public TreeIter NewRow()
		{
			return this.store.Append();
		}

		public void AddRow(object[] columnValues)
		{
			TreeIter iter = NewRow();
			for (int col = 0; col < columnValues.Length; col++) 
			{
				SetColumnValue(iter, col, columnValues[col]);
			}
		}

		public void SetColumnValue(TreeIter iter, int column, object v)
		{
			GLib.Value cell;
			
			if(v.GetType() == typeof(double))
			{
				string str = ((double)v).ToString("G");
				cell = new GLib.Value(str);
			}
			else
			{
				cell = new GLib.Value(v);
			}

			this.store.SetValue(iter, column, cell);
		}

		private void AutoCreateTreeViewColumns()
		{
			for (int col = 0; col < this.gridColumns.Count; col++) 
			{
				// escape underscore _ because it is used
				// as the underline in menus and labels
				StringBuilder name = new StringBuilder();
				DataGridColumn dataGridColumn = this.gridColumns[col] as DataGridColumn;
				foreach (char ch in dataGridColumn.ColumnName) 
				{
					if (ch == '_')
						name.Append("__");
					else
						name.Append(ch);
				}
				TreeViewColumn tvc = CreateTreeViewColumn(col, dataGridColumn);
				AppendColumn(tvc);
			}
		}

		public int AppendColumn(TreeViewColumn tvc)
		{
			return this.treeView.AppendColumn(tvc);
		}


		private void SetBindedValue(string editedPath, object v)
		{
			IBindingList b = (IBindingList) resolvedDataSource;
			if (b.AllowEdit) 
			{
				// FIXME: ITypedList may help you figure out how to convert between different data types such as, 
				// how to display numbers, dates, etc...
				TreePath path = new TreePath(editedPath);
				TreeIter iter;
				this.store.GetIter(out iter, path);
				int i = path.Indices[0];

				TreePath cpath;
				object cellValue = v;

				TreeViewColumn tvcolumn;
				this.treeView.GetCursor(out cpath, out tvcolumn);
				int c = 0;
				for (c = 0; c < this.gridColumns.Count; c++) 
				{
					TreeViewColumn tvc = ((DataGridColumn)this.gridColumns[c]).TreeViewColumn;
					if (tvcolumn == tvc) 
					{
						Console.Error.WriteLine("Column clicked:  Column Name: " + tvcolumn.Title);
						Console.Error.WriteLine("	 Ordinal: " + c.ToString());
						break;
					}
				}

				if (c >= this.gridColumns.Count)
					Console.Error.WriteLine("tv col not found");

				ICustomTypeDescriptor custom = (ICustomTypeDescriptor) this.bindrows[i];
				PropertyDescriptorCollection properties = custom.GetProperties();
				PropertyDescriptor pd = properties[c];
				if(pd.PropertyType == typeof(bool))
				{
					cellValue = pd.GetValue(this.bindrows[i]);
					
					if(cellValue == null || cellValue == DBNull.Value)
					{
						cellValue = true;
					}
					else
					{
						cellValue = !(bool)(cellValue); // toggle
					}

					pd.SetValue(this.bindrows[i], cellValue);
				}
				else
				{
					pd.SetValue(this.bindrows[i], cellValue);
				}

				Console.Error.WriteLine("	Row number: " + path.Indices[0].ToString());
				Console.Error.WriteLine("	Cell Value: " + cellValue);

				((IEditableObject)this.bindrows[i]).BeginEdit();
				SetColumnValue(iter, c, cellValue);
				((IEditableObject)this.bindrows[i]).EndEdit();
			}
		}

		private void TextCellEdited(object o, EditedArgs args)
		{
			SetBindedValue(args.Path, args.NewText);
		}


		private void rendererToggle_Toggled(object o, ToggledArgs args)
		{
			/*
			TreePath treepath;
			TreeViewColumn column;

			performingtask = PerformingTask.Renaming;
			text_render.Editable = true;

			treeView.GetCursor (out treepath, out column);
			*/

			/*
			CellRendererToggle cellRendererToggle = o as CellRendererToggle;
			int column = (int) cellRendererToggle.Data["toggled"];
			
			Gtk.TreeIter iter;
			if (store.GetIterFromString (out iter, args.Path))
			{
				bool val = (bool) store.GetValue (iter, column);
				Console.WriteLine ("toggled {0} with value {1}", args.Path, !val);
				store.SetValue (iter, column, !val);
			}
			*/

			SetBindedValue(args.Path, null);
		}

		/// <summary>
		/// Creates tree view column for given cell type using corresponding cell renderer.
		/// </summary>
		/// <param name="position">Position</param>
		/// <param name="name">Name</param>
		/// <param name="type">Type of the values in the column cells.</param>
		/// <returns>Tree view column</returns>
		/// <remarks>
		/// TODO: why it returns TreeViewColumn instead of DataGridColumn?
		/// </remarks>
		public TreeViewColumn CreateTreeViewColumn(int position, DataGridColumn column)
		{
			TreeViewColumn treeColumn = new TreeViewColumn();
			CellRenderer renderer;
			treeColumn.Clickable = true;
			this.treeView.RulesHint = true;

			this.treeView.Selection.Mode = SelectionMode.Single;
			// treeView.Selection.Mode = SelectionMode.Multiple;
			
			if(column.Type == typeof(bool))
			{
				CellRendererToggle rendererToggle = new CellRendererToggle();
				rendererToggle.Xalign = 0.0f;
				rendererToggle.Xpad = 5;
				rendererToggle.Activatable = true;
				rendererToggle.Toggled +=new ToggledHandler(rendererToggle_Toggled);
				renderer = rendererToggle;
				renderer.Mode = column.ReadOnly ? CellRendererMode.Inert : CellRendererMode.Activatable;
				treeColumn.Title = column.ColumnName;
				treeColumn.PackStart(renderer, true);
				treeColumn.AddAttribute(renderer, "active", position);
			}
			else
			{
				CellRendererText rendererText = new CellRendererText();
				rendererText.Editable = !column.ReadOnly;
				rendererText.Edited += new EditedHandler(TextCellEdited);
				renderer = rendererText;
				renderer.Mode = CellRendererMode.Editable;

				treeColumn.Title = column.ColumnName;
				treeColumn.PackStart(renderer, true);
				treeColumn.AddAttribute(renderer, "text", position);
			}
			treeColumn.Resizable = true;
			// treeColumn.SortIndicator = true;

			// Editable, Activatable, Inert
			//renderer.Family = "courier new";

			column.Renderer = renderer;
			column.TreeViewColumn = treeColumn;

			return treeColumn;
		}

		private void OnKeyPressEvent(object o, KeyPressEventArgs args)
		{
			Debug.WriteLine(o.ToString(), args.Event.Key.ToString());
		}
	}
}














-------------- next part --------------
A non-text attachment was scrubbed...
Name: GtkDataGrid.png
Type: image/png
Size: 4025 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/gtk-sharp-list/attachments/20051213/379ac6ca/GtkDataGrid-0001.png


More information about the Gtk-sharp-list mailing list