2008-03-06 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataGridTextBoxColumn.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Author:
23 //      Jordi Mas i Hernandez <jordi@ximian.com>
24 //
25 //
26
27 using System.ComponentModel;
28 using System.Drawing;
29 using System.Globalization;
30 using System.Runtime.InteropServices;
31 using System.Diagnostics;
32
33 namespace System.Windows.Forms
34 {
35         public class DataGridTextBoxColumn : DataGridColumnStyle
36         {
37                 #region Local Variables
38                 private string format;
39                 private IFormatProvider format_provider = null;
40                 private StringFormat string_format =  new StringFormat ();
41                 private DataGridTextBox textbox;
42                 private static readonly int offset_x = 2;
43                 private static readonly int offset_y = 2;
44                 #endregion      // Local Variables
45
46                 #region Constructors
47                 public DataGridTextBoxColumn () : this (null, String.Empty, false)
48                 {
49                 }
50
51                 public DataGridTextBoxColumn (PropertyDescriptor prop) : this (prop, String.Empty, false)
52                 {
53                 }
54                 
55                 public DataGridTextBoxColumn (PropertyDescriptor prop,  bool isDefault) : this (prop, String.Empty, isDefault)
56                 {
57                 }
58
59                 public DataGridTextBoxColumn (PropertyDescriptor prop,  string format) : this (prop, format, false)
60                 {
61                 }
62                 
63                 public DataGridTextBoxColumn (PropertyDescriptor prop,  string format, bool isDefault) : base (prop)
64                 {
65                         Format = format;
66                         is_default = isDefault;
67
68                         textbox = new DataGridTextBox ();
69                         textbox.Multiline = true;
70                         textbox.WordWrap = false;
71                         textbox.BorderStyle = BorderStyle.None;
72                         textbox.Visible = false;
73                 }
74
75                 #endregion
76
77                 #region Public Instance Properties
78                 [Editor("System.Windows.Forms.Design.DataGridColumnStyleFormatEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
79 #if NET_2_0
80                 [DefaultValue (null)]
81 #endif
82                 public string Format {
83                         get { return format; }
84                         set {
85                                 if (value != format) {
86                                         format = value;
87                                         Invalidate ();
88                                 }
89                         }
90                 }
91
92                 [Browsable(false)]
93                 [EditorBrowsable(EditorBrowsableState.Advanced)]
94                 public IFormatProvider FormatInfo {
95                         get { return format_provider; }
96                         set {
97                                 if (value != format_provider) {
98                                         format_provider = value;
99                                 }
100                         }
101                 }
102
103                 [DefaultValue(null)]
104                 public override PropertyDescriptor PropertyDescriptor {
105                         set { base.PropertyDescriptor = value; }
106                 }
107
108                 public override bool ReadOnly {
109                         get { return base.ReadOnly; }
110                         set { base.ReadOnly = value; }
111                 }
112                 
113                 [Browsable(false)]
114                 public virtual TextBox TextBox {
115                         get { return textbox; }
116                 }
117                 #endregion      // Public Instance Properties
118
119                 #region Public Instance Methods
120
121                 protected internal override void Abort (int rowNum)
122                 {
123                         EndEdit ();
124                 }
125                 
126                 protected internal override bool Commit (CurrencyManager dataSource, int rowNum)
127                 {
128                         textbox.Bounds = Rectangle.Empty;
129
130                         /* Do not write data if not editing. */
131                         if (textbox.IsInEditOrNavigateMode)
132                                 return true;
133
134                         try {
135                                 string existing_text = GetFormattedValue (dataSource, rowNum);
136
137                                 if (existing_text != textbox.Text) {
138                                         if (textbox.Text == NullText) {
139                                                 SetColumnValueAtRow (dataSource, rowNum, DBNull.Value);
140                                         } else {
141                                                 object newValue = textbox.Text;
142
143                                                 TypeConverter converter = TypeDescriptor.GetConverter (
144                                                         PropertyDescriptor.PropertyType);
145                                                 if (converter != null && converter.CanConvertFrom (typeof (string))) {
146                                                         newValue = converter.ConvertFrom (null, CultureInfo.CurrentCulture,
147                                                                 textbox.Text);
148                                                         if (converter.CanConvertTo (typeof (string)))
149                                                                 textbox.Text = (string) converter.ConvertTo (null, 
150                                                                         CultureInfo.CurrentCulture, newValue, typeof (string));
151                                                 }
152
153                                                 SetColumnValueAtRow (dataSource, rowNum, newValue);
154                                         }
155                                 }
156                         } catch {
157                                 return false;
158                         }
159                         
160                         EndEdit ();
161                         return true;
162                 }
163
164                 [MonoTODO]
165                 protected internal override void ConcedeFocus ()
166                 {
167                         HideEditBox ();
168                 }
169
170                 protected internal override void Edit (CurrencyManager source, int rowNum,  Rectangle bounds,  bool readOnly, string displayText, bool cellIsVisible)
171                 {
172                         grid.SuspendLayout ();
173
174                         textbox.TextChanged -= new EventHandler (textbox_TextChanged);
175
176                         textbox.TextAlign = alignment;
177                         
178                         bool ro = false;
179
180                         ro = (TableStyleReadOnly || ReadOnly || readOnly);
181
182                         if (!ro && displayText != null) {
183                                 textbox.Text = displayText;
184                                 textbox.IsInEditOrNavigateMode = false;
185                         } else {
186                                 textbox.Text = GetFormattedValue (source, rowNum);
187                         }
188
189                         textbox.TextChanged += new EventHandler (textbox_TextChanged);
190
191                         textbox.ReadOnly = ro;
192                         textbox.Bounds = new Rectangle (new Point (bounds.X + offset_x, bounds.Y + offset_y),
193                                                         new Size (bounds.Width - offset_x, bounds.Height - offset_y));
194                         textbox.Visible = cellIsVisible;
195                         textbox.SelectAll ();
196                         textbox.Focus ();
197                         grid.ResumeLayout (false);
198
199                 }
200
201                 void textbox_TextChanged (object o, EventArgs e)
202                 {
203                         textbox.IsInEditOrNavigateMode = false;
204                 }
205
206                 protected void EndEdit ()
207                 {
208                         textbox.TextChanged -= new EventHandler (textbox_TextChanged);
209                         HideEditBox ();
210                 }
211
212                 protected internal override void EnterNullValue ()
213                 {
214                         textbox.Text = NullText;
215                 }
216
217                 protected internal override int GetMinimumHeight ()
218                 {
219                         return FontHeight + 3;
220                 }
221
222                 protected internal override int GetPreferredHeight (Graphics g, object value)
223                 {
224                         string text = GetFormattedValue (value);
225                         System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex("/\r\n/");
226                         int lines = r.Matches (text).Count;
227                         return this.DataGridTableStyle.DataGrid.Font.Height * (lines+1) + 1;
228                 }
229
230                 protected internal override Size GetPreferredSize (Graphics g, object value)
231                 {
232                         string text = GetFormattedValue (value);
233                         Size s = Size.Ceiling (g.MeasureString (text, this.DataGridTableStyle.DataGrid.Font));
234                         s.Width += 4;
235                         return s;
236                 }
237
238                 [MonoTODO]
239                 protected void HideEditBox ()
240                 {
241                         if (!textbox.Visible)
242                                 return;
243
244                         grid.SuspendLayout ();
245                         textbox.Bounds = Rectangle.Empty;
246                         textbox.Visible = false;
247                         textbox.IsInEditOrNavigateMode = true;
248                         grid.ResumeLayout (false);
249                 }
250
251                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum)
252                 {
253                         Paint (g, bounds, source, rowNum, false);
254                 }
255
256                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, bool alignToRight)
257                 {
258                         Paint (g, bounds, source, rowNum, ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.BackColor),
259                                 ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.ForeColor), alignToRight);
260                 }
261
262                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, Brush backBrush, Brush foreBrush, bool alignToRight)
263                 {
264                         PaintText (g, bounds, GetFormattedValue (source, rowNum),  backBrush, foreBrush, alignToRight);
265                 }
266
267                 protected void PaintText (Graphics g, Rectangle bounds, string text, bool alignToRight)
268                 {
269                         PaintText (g, bounds, text,  ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.BackColor),
270                                 ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.ForeColor), alignToRight);
271                 }
272
273                 protected void PaintText (Graphics g, Rectangle textBounds, string text, Brush backBrush, Brush foreBrush, bool alignToRight)
274                 {
275                         if (alignToRight == true) {
276                                 string_format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
277                         } else {
278                                 string_format.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft;
279                         }
280                         
281                         switch (alignment) {
282                         case HorizontalAlignment.Center:
283                                 string_format.Alignment = StringAlignment.Center;
284                                 break;
285                         case HorizontalAlignment.Right:
286                                 string_format.Alignment = StringAlignment.Far;
287                                 break;
288                         default:
289                                 string_format.Alignment = StringAlignment.Near;
290                                 break;
291                         }
292                         
293                         g.FillRectangle (backBrush, textBounds);
294                         PaintGridLine (g, textBounds);
295
296                         textBounds.X += offset_x;
297                         textBounds.Width -= offset_x;
298
299                         textBounds.Y += offset_y;
300                         textBounds.Height -= offset_y;
301
302                         string_format.FormatFlags |= StringFormatFlags.NoWrap;
303                         g.DrawString (text, DataGridTableStyle.DataGrid.Font, foreBrush, textBounds, string_format);
304                         
305                 }
306                 
307                 protected internal override void ReleaseHostedControl ()
308                 {
309                         if (textbox == null)
310                                 return;
311
312                         grid.SuspendLayout ();
313                         grid.Controls.Remove (textbox);
314                         grid.Invalidate (new Rectangle (textbox.Location, textbox.Size));
315                         textbox.Dispose ();
316                         textbox = null;
317                         grid.ResumeLayout (false);
318                 }
319
320                 protected override void SetDataGridInColumn (DataGrid value)
321                 {
322                         base.SetDataGridInColumn (value);
323
324                         if (value == null)
325                                 return;
326
327                         textbox.SetDataGrid (grid);
328                         grid.SuspendLayout ();
329                         grid.Controls.Add (textbox);
330                         grid.ResumeLayout (false);
331                 }
332                 
333                 protected internal override void UpdateUI (CurrencyManager source, int rowNum, string displayText)
334                 {
335                         if (textbox.Visible // I don't really like this, but it gets DataGridTextBoxColumnTest.TestUpdateUI passing
336                             && textbox.IsInEditOrNavigateMode) {
337                                 textbox.Text = GetFormattedValue (source, rowNum);
338                         } else {
339                                 textbox.Text = displayText;
340                         }
341                 }
342
343                 #endregion      // Public Instance Methods
344
345                 #region Private Instance Methods
346
347                 private string GetFormattedValue (CurrencyManager source, int rowNum)
348                 {
349                         object obj = GetColumnValueAtRow (source, rowNum);
350                         return GetFormattedValue (obj);
351                 }
352
353                 private string GetFormattedValue (object obj)
354                 {
355                         if (DBNull.Value.Equals(obj) || obj == null)
356                                 return NullText;
357
358                         if (format != null && format != String.Empty && obj as IFormattable != null)
359                                 return ((IFormattable) obj).ToString (format, format_provider);
360
361                         TypeConverter converter = TypeDescriptor.GetConverter (
362                                 PropertyDescriptor.PropertyType);
363                         if (converter != null && converter.CanConvertTo (typeof (string)))
364                                 return (string) converter.ConvertTo (null, CultureInfo.CurrentCulture,
365                                         obj, typeof (string));
366
367                         return obj.ToString ();
368
369                 }
370                 #endregion Private Instance Methods
371         }
372 }