e7f0e496ee59fdf5e95c7807c040a612d05c5b5a
[mono.git] / mcs / class / System.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                 [DefaultValue (null)]
80                 public string Format {
81                         get { return format; }
82                         set {
83                                 if (value != format) {
84                                         format = value;
85                                         Invalidate ();
86                                 }
87                         }
88                 }
89
90                 [Browsable(false)]
91                 [EditorBrowsable(EditorBrowsableState.Advanced)]
92                 public IFormatProvider FormatInfo {
93                         get { return format_provider; }
94                         set {
95                                 if (value != format_provider) {
96                                         format_provider = value;
97                                 }
98                         }
99                 }
100
101                 [DefaultValue(null)]
102                 public override PropertyDescriptor PropertyDescriptor {
103                         set { base.PropertyDescriptor = value; }
104                 }
105
106                 public override bool ReadOnly {
107                         get { return base.ReadOnly; }
108                         set { base.ReadOnly = value; }
109                 }
110                 
111                 [Browsable(false)]
112                 public virtual TextBox TextBox {
113                         get { return textbox; }
114                 }
115                 #endregion      // Public Instance Properties
116
117                 #region Public Instance Methods
118
119                 protected internal override void Abort (int rowNum)
120                 {
121                         EndEdit ();
122                 }
123                 
124                 protected internal override bool Commit (CurrencyManager dataSource, int rowNum)
125                 {
126                         textbox.Bounds = Rectangle.Empty;
127
128                         /* Do not write data if not editing. */
129                         if (textbox.IsInEditOrNavigateMode)
130                                 return true;
131
132                         try {
133                                 string existing_text = GetFormattedValue (dataSource, rowNum);
134
135                                 if (existing_text != textbox.Text) {
136                                         if (textbox.Text == NullText) {
137                                                 SetColumnValueAtRow (dataSource, rowNum, DBNull.Value);
138                                         } else {
139                                                 object newValue = textbox.Text;
140
141                                                 TypeConverter converter = TypeDescriptor.GetConverter (
142                                                         PropertyDescriptor.PropertyType);
143                                                 if (converter != null && converter.CanConvertFrom (typeof (string))) {
144                                                         newValue = converter.ConvertFrom (null, CultureInfo.CurrentCulture,
145                                                                 textbox.Text);
146                                                         if (converter.CanConvertTo (typeof (string)))
147                                                                 textbox.Text = (string) converter.ConvertTo (null, 
148                                                                         CultureInfo.CurrentCulture, newValue, typeof (string));
149                                                 }
150
151                                                 SetColumnValueAtRow (dataSource, rowNum, newValue);
152                                         }
153                                 }
154                         } catch {
155                                 return false;
156                         }
157                         
158                         EndEdit ();
159                         return true;
160                 }
161
162                 protected internal override void ConcedeFocus ()
163                 {
164                         HideEditBox ();
165                 }
166
167                 protected internal override void Edit (CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string displayText, bool cellIsVisible)
168                 {
169                         string instantText = displayText;
170                         grid.SuspendLayout ();
171
172                         textbox.TextChanged -= new EventHandler (textbox_TextChanged);
173
174                         textbox.TextAlign = alignment;
175                         
176                         bool ro = false;
177
178                         ro = (TableStyleReadOnly || ReadOnly || readOnly);
179
180                         if (!ro && instantText != null) {
181                                 textbox.Text = instantText;
182                                 textbox.IsInEditOrNavigateMode = false;
183                         } else {
184                                 textbox.Text = GetFormattedValue (source, rowNum);
185                         }
186
187                         textbox.TextChanged += new EventHandler (textbox_TextChanged);
188
189                         textbox.ReadOnly = ro;
190                         textbox.Bounds = new Rectangle (new Point (bounds.X + offset_x, bounds.Y + offset_y),
191                                                         new Size (bounds.Width - offset_x - 1, bounds.Height - offset_y - 1));
192
193                         textbox.Visible = cellIsVisible;
194                         textbox.SelectAll ();
195                         textbox.Focus ();
196                         grid.ResumeLayout (false);
197
198                 }
199
200                 void textbox_TextChanged (object o, EventArgs e)
201                 {
202                         textbox.IsInEditOrNavigateMode = false;
203                         grid.EditRowChanged (this);
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                 protected void HideEditBox ()
239                 {
240                         if (!textbox.Visible)
241                                 return;
242
243                         grid.SuspendLayout ();
244                         textbox.Bounds = Rectangle.Empty;
245                         textbox.Visible = false;
246                         textbox.IsInEditOrNavigateMode = true;
247                         grid.ResumeLayout (false);
248                 }
249
250                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum)
251                 {
252                         Paint (g, bounds, source, rowNum, false);
253                 }
254
255                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, bool alignToRight)
256                 {
257                         Paint (g, bounds, source, rowNum, ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.BackColor),
258                                 ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.ForeColor), alignToRight);
259                 }
260
261                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, Brush backBrush, Brush foreBrush, bool alignToRight)
262                 {
263                         PaintText (g, bounds, GetFormattedValue (source, rowNum),  backBrush, foreBrush, alignToRight);
264                 }
265
266                 protected void PaintText (Graphics g, Rectangle bounds, string text, bool alignToRight)
267                 {
268                         PaintText (g, bounds, text,  ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.BackColor),
269                                 ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.ForeColor), alignToRight);
270                 }
271
272                 protected void PaintText (Graphics g, Rectangle textBounds, string text, Brush backBrush, Brush foreBrush, bool alignToRight)
273                 {
274                         if (alignToRight == true) {
275                                 string_format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
276                         } else {
277                                 string_format.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft;
278                         }
279                         
280                         switch (alignment) {
281                         case HorizontalAlignment.Center:
282                                 string_format.Alignment = StringAlignment.Center;
283                                 break;
284                         case HorizontalAlignment.Right:
285                                 string_format.Alignment = StringAlignment.Far;
286                                 break;
287                         default:
288                                 string_format.Alignment = StringAlignment.Near;
289                                 break;
290                         }
291                         
292                         g.FillRectangle (backBrush, textBounds);
293                         PaintGridLine (g, textBounds);
294
295                         textBounds.X += offset_x;
296                         textBounds.Width -= offset_x;
297
298                         textBounds.Y += offset_y;
299                         textBounds.Height -= offset_y;
300
301                         string_format.FormatFlags |= StringFormatFlags.NoWrap;
302                         g.DrawString (text, DataGridTableStyle.DataGrid.Font, foreBrush, textBounds, string_format);
303                         
304                 }
305                 
306                 protected internal override void ReleaseHostedControl ()
307                 {
308                         if (textbox == null)
309                                 return;
310
311                         grid.SuspendLayout ();
312                         grid.Controls.Remove (textbox);
313                         grid.Invalidate (new Rectangle (textbox.Location, textbox.Size));
314                         textbox.Dispose ();
315                         textbox = null;
316                         grid.ResumeLayout (false);
317                 }
318
319                 protected override void SetDataGridInColumn (DataGrid value)
320                 {
321                         base.SetDataGridInColumn (value);
322
323                         if (value == null)
324                                 return;
325
326                         textbox.SetDataGrid (grid);
327                         grid.SuspendLayout ();
328                         grid.Controls.Add (textbox);
329                         grid.ResumeLayout (false);
330                 }
331
332                 protected internal override void UpdateUI (CurrencyManager source, int rowNum, string displayText)
333                 {
334                         string instantText = displayText;
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 = instantText;
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 }