[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