Implemented Servlet session management. Servlet hosting moved to Mainsoft.Web package
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DomainUpDown.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.
21 //
22 // Authors:
23 //      Jonathan Gilbert        <logic@deltaq.org>
24 //
25 // Integration into MWF:
26 //      Peter Bartok            <pbartok@novell.com>
27 //
28
29 using System;
30 using System.Collections;
31 using System.ComponentModel;
32 using System.Drawing;
33 using System.Reflection;
34 using System.Runtime.InteropServices;
35 using System.Windows.Forms;
36
37 namespace System.Windows.Forms
38 {
39         [DefaultProperty("Items")]
40         [DefaultEvent("SelectedItemChanged")]
41 #if NET_2_0
42         [DefaultBindingProperty ("SelectedItem")]
43         [ClassInterface (ClassInterfaceType.AutoDispatch)]
44         [ComVisible (true)]
45 #endif
46         public class DomainUpDown : UpDownBase {
47                 #region Local Variables
48                 private DomainUpDownItemCollection      items;
49                 private int                             selected_index = -1;
50                 private bool                            sorted;
51                 private bool                            wrap;
52                 private int                             typed_to_index = -1;
53                 #endregion      // Local Variables
54
55                 #region DomainUpDownAccessibleObject sub-class
56                 [ComVisible(true)]
57                 public class DomainItemAccessibleObject : AccessibleObject {
58                         #region DomainItemAccessibleObject Local Variables
59                         private AccessibleObject parent;
60                         #endregion      // DomainItemAccessibleObject Local Variables
61
62                         #region DomainItemAccessibleObject Constructors
63                         public DomainItemAccessibleObject(string name, AccessibleObject parent) {
64                                 this.name = name;
65                                 this.parent = parent;
66                         }
67                         #endregion      // DomainItemAccessibleObject Constructors
68
69                         #region DomainItemAccessibleObject Properties
70                         public override string Name {
71                                 get {
72                                         return base.Name;
73                                 }
74
75                                 set {
76                                         base.Name = value;
77                                 }
78                         }
79
80                         public override AccessibleObject Parent {
81                                 get {
82                                         return parent;
83                                 }
84                         }
85
86                         public override AccessibleRole Role {
87                                 get {
88                                         return base.Role;
89                                 }
90                         }
91
92                         public override AccessibleStates State {
93                                 get {
94                                         return base.State;
95                                 }
96                         }
97
98                         public override string Value {
99                                 get {
100                                         return base.Value;
101                                 }
102                         }
103                         #endregion      // DomainItemAccessibleObject Properties
104                 }
105                 #endregion      // DomainItemAccessibleObject sub-class
106
107                 #region DomainUpDownAccessibleObject sub-class
108                 [ComVisible(true)]
109                 public class DomainUpDownAccessibleObject : ControlAccessibleObject {
110                         #region DomainUpDownAccessibleObject Local Variables
111                         //private Control       owner;
112                         #endregion      // DomainUpDownAccessibleObject Local Variables
113
114                         #region DomainUpDownAccessibleObject Constructors
115                         public DomainUpDownAccessibleObject(Control owner) : base(owner)
116                         {
117                                 //this.owner = owner;
118                         }
119                         #endregion      // DomainUpDownAccessibleObject Constructors
120
121                         #region DomainUpDownAccessibleObject Properties
122                         public override AccessibleRole Role {
123                                 get {
124                                         return base.Role;
125                                 }
126                         }
127                         #endregion      // DomainUpDownAccessibleObject Properties
128
129                         #region DomainUpDownAccessibleObject Methods
130                         public override AccessibleObject GetChild(int index) {
131                                 return base.GetChild (index);
132                         }
133
134                         public override int GetChildCount() {
135                                 return base.GetChildCount ();
136                         }
137                         #endregion      // DomainUpDownAccessibleObject Methods
138                 }
139                 #endregion      // DomainUpDownAccessibleObject sub-class
140
141                 #region DomainUpDownItemCollection sub-class
142                 public class DomainUpDownItemCollection : ArrayList {
143                         internal ArrayList string_cache = new ArrayList();
144
145                         #region Local Variables
146                         #endregion      // Local Variables
147
148                         #region Constructors
149                         internal DomainUpDownItemCollection() {}
150                         #endregion      // Constructors
151
152                         #region Public Instance Properties
153                         [Browsable(false)]
154                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
155                         public override object this[int index] {
156                                 get {
157                                         return base[index];
158                                 }
159
160                                 set {
161                                         if (value == null) {
162                                                 throw new ArgumentNullException("value", "Cannot add null values to a DomainUpDownItemCollection");
163                                         }
164
165                                         base[index] = value;
166                                         string_cache[index] = value.ToString();
167                                         OnCollectionChanged(index, 0);
168                                 }
169                         }
170                         #endregion      // Public Instance Properties
171
172                         #region Public Instance Methods
173                         public override int Add(object value) {
174                                 if (value == null)
175                                         throw new ArgumentNullException("value", "Cannot add null values to a DomainUpDownItemCollection");
176
177                                 int ret = base.Add(value);
178                                 string_cache.Add(value.ToString());
179                                 OnCollectionChanged(Count - 1, +1);
180                                 return ret;
181                         }
182
183                         public override void Insert(int index, object value) {
184                                 if (value == null)
185                                         throw new ArgumentNullException("value", "Cannot add null values to a DomainUpDownItemCollection");
186
187                                 base.Insert(index, value);
188                                 string_cache.Insert(index, value.ToString());
189                                 OnCollectionChanged(index, +1);
190                         }
191
192                         public override void Remove(object obj) {
193                                 int index = IndexOf(obj);
194
195                                 if (index >= 0)
196                                         RemoveAt(index);
197                         }
198
199                         public override void RemoveAt(int index) {
200                                 base.RemoveAt(index);
201                                 string_cache.RemoveAt(index);
202                                 OnCollectionChanged(index, -1);
203                         }
204                         #endregion      // Public Instance Methods
205
206                         #region Internal Methods and Events
207                         internal void OnCollectionChanged(int index, int size_delta) {
208                                 CollectionChangedEventHandler handler = CollectionChanged;
209
210                                 if (handler != null) {
211                                         handler(index, size_delta);
212                                 }
213                         }
214
215                         internal void PrivSort() {
216                                 PrivSort(0, Count, Comparer.Default);
217                         }
218
219                         internal void PrivSort(int index, int count, IComparer comparer) {
220                                 object[] base_items = null; // this will refer to the base ArrayList private _items member
221                                 object[] string_cache_items = null; // and this will refer to that of the string_cache
222
223                                 FieldInfo items_field = null;
224         
225                                 try {
226                                         items_field = typeof(ArrayList).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance);
227                                 }
228                                 catch {} // security exceptions, perhaps...
229
230                                 if (items_field != null) {
231                                         base_items = items_field.GetValue(this) as object[];
232                                         string_cache_items = items_field.GetValue(string_cache) as object[];
233                                 }
234
235                                 if ((base_items == null) || (string_cache_items == null)) {
236                                         // oh poop =/ guess we have to completely repopulate the string cache
237                                         base.Sort(index, count, comparer);
238
239                                         for (int i=0; i < count; i++)
240                                                 string_cache[i + index] = base[i + index].ToString();
241                                 }
242                                 else {
243                                         // yay, this will be much faster than creating a whole bunch more items
244                                         Array.Sort(string_cache_items, base_items, index, count, comparer);
245
246                                         OnCollectionChanged(-1, 0);
247                                 }
248                         }
249
250                         internal void PrivSort(IComparer comparer) {
251                                 PrivSort(0, Count, comparer);
252                         }
253
254                         internal event CollectionChangedEventHandler CollectionChanged;
255                         #endregion      // Internal Methods and Events
256                 }
257                 #endregion      // DomainUpDownItemCollection sub-class
258
259                 #region Private Methods
260                 // normally I'd use an EventArgs class, but I don't want to create spurious objects here
261                 internal delegate void  CollectionChangedEventHandler(int index, int size_delta);
262
263                 internal void items_CollectionChanged(int index, int size_delta) {
264                         bool new_item = false;
265
266                         if ((index == selected_index) && (size_delta <= 0))
267                                 new_item = true;
268                         else if (index <= selected_index)
269                                 selected_index += size_delta;
270
271                         if (sorted && (index >= 0)) // index < 0 means it is already sorting
272                                 items.PrivSort();
273
274                         UpdateEditText();
275
276                         if (new_item) {
277                                 OnSelectedItemChanged(this, EventArgs.Empty);
278                         }
279                 }
280
281                 void go_to_user_input() {
282                         UserEdit = false;
283
284                         if (typed_to_index >= 0) {
285                                 selected_index = typed_to_index;
286                                 OnSelectedItemChanged(this, EventArgs.Empty);
287                         }
288                 }
289
290                 private void TextBoxLostFocus(object source, EventArgs e) {
291                         Select(base.txtView.SelectionStart + base.txtView.SelectionLength, 0);
292                 }
293
294                 private void TextBoxKeyDown(object source, KeyPressEventArgs e) {
295                         if (!UserEdit) {
296                                 base.txtView.SelectionLength = 0;
297                                 typed_to_index = -1;
298                         }
299
300                         if (base.txtView.SelectionLength == 0) {
301                                 base.txtView.SelectionStart = 0;
302                         }
303
304                         if (base.txtView.SelectionStart != 0) {
305                                 return;
306                         }
307
308                         if (e.KeyChar == '\b') { // backspace
309                                 if (base.txtView.SelectionLength > 0) {
310                                         string prefix = base.txtView.SelectedText.Substring(0, base.txtView.SelectionLength - 1);
311
312                                         bool found = false;
313
314                                         if (typed_to_index < 0) {
315                                                 typed_to_index = 0;
316                                         }
317
318                                         if (sorted) {
319                                                 for (int i=typed_to_index; i >= 0; i--) {
320                                                         int difference = string.Compare(prefix, 0, items.string_cache[i].ToString(), 0, prefix.Length, true);
321
322                                                         if (difference == 0) {
323                                                                 found = true;
324                                                                 typed_to_index = i;
325                                                         }
326
327                                                         if (difference > 0) { // since it is sorted, no strings after this point will match
328                                                                 break;
329                                                         }
330                                                 }
331                                         } else {
332                                                 for (int i=0; i < items.Count; i++) {
333                                                         if (0 == string.Compare(prefix, 0, items.string_cache[i].ToString(), 0, prefix.Length, true)) {
334                                                                 found = true;
335                                                                 typed_to_index = i;
336                                                                 break;
337                                                         }
338                                                 }
339                                         }
340
341                                         ChangingText = true;
342
343                                         if (found)
344                                                 Text = items.string_cache[typed_to_index].ToString();
345                                         else
346                                                 Text = prefix;
347
348                                         Select(0, prefix.Length);
349
350                                         UserEdit = true;
351
352                                         e.Handled = true;
353                                 }
354                         }
355                         else {
356                                 char key_char = e.KeyChar;
357
358                                 if (char.IsLetterOrDigit(key_char)
359                                         || char.IsNumber(key_char)
360                                         || char.IsPunctuation(key_char)
361                                         || char.IsSymbol(key_char)
362                                         || char.IsWhiteSpace(key_char)) {
363                                         string prefix = base.txtView.SelectedText + key_char;
364
365                                         bool found = false;
366
367                                         if (typed_to_index < 0) {
368                                                 typed_to_index = 0;
369                                         }
370
371                                         if (sorted) {
372                                                 for (int i=typed_to_index; i < items.Count; i++) {
373                                                         int difference = string.Compare(prefix, 0, items.string_cache[i].ToString(), 0, prefix.Length, true);
374
375                                                         if (difference == 0) {
376                                                                 found = true;
377                                                                 typed_to_index = i;
378                                                         }
379
380                                                         if (difference <= 0) { // since it is sorted, no strings after this point will match
381                                                                 break;
382                                                         }
383                                                 }
384                                         } else {
385                                                 for (int i=0; i < items.Count; i++) {
386                                                         if (0 == string.Compare(prefix, 0, items.string_cache[i].ToString(), 0, prefix.Length, true)) {
387                                                                 found = true;
388                                                                 typed_to_index = i;
389                                                                 break;
390                                                         }
391                                                 }
392                                         }
393
394                                         ChangingText = true;
395
396                                         if (found) {
397                                                 Text = items.string_cache[typed_to_index].ToString();
398                                         } else {
399                                                 Text = prefix;
400                                         }
401
402                                         Select(0, prefix.Length);
403
404                                         UserEdit = true;
405
406                                         e.Handled = true;
407                                 }
408                         }
409                 }
410                 #endregion      // Private Methods
411
412                 #region Public Constructors
413                 public DomainUpDown() {
414                         selected_index = -1;
415                         sorted = false;
416                         wrap = false;
417                         typed_to_index = -1;
418
419                         items = new DomainUpDownItemCollection();
420                         items.CollectionChanged += new CollectionChangedEventHandler(items_CollectionChanged);
421
422                         this.txtView.LostFocus +=new EventHandler(TextBoxLostFocus);
423                         this.txtView.KeyPress += new KeyPressEventHandler(TextBoxKeyDown);
424                 }
425                 #endregion      // Public Constructors
426
427                 #region Public Instance Properties
428                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
429                 [Editor("System.Windows.Forms.Design.StringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
430                 [Localizable(true)]
431                 public DomainUpDownItemCollection Items {
432                         get {
433                                 return items;
434                         }
435                 }
436
437                 [Browsable(false)]
438                 [DefaultValue(-1)]
439                 public int SelectedIndex {
440                         get {
441                                 return selected_index;
442                         }
443                         set {
444                                 object before = (selected_index >= 0) ? items[selected_index] : null;
445
446                                 selected_index = value;
447                                 UpdateEditText();
448
449                                 object after = (selected_index >= 0) ? items[selected_index] : null;
450
451                                 if (!ReferenceEquals(before, after)) {
452                                         OnSelectedItemChanged(this, EventArgs.Empty);
453                                 }
454                         }
455                 }
456
457                 [Browsable(false)]
458                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
459                 public object SelectedItem {
460                         get {
461                                 if (selected_index >= 0) {
462                                         return items[selected_index];
463                                 } else {
464                                         return null;
465                                 }
466                         }
467
468                         set {
469                                 SelectedIndex = items.IndexOf(value);
470                         }
471                 }
472
473                 [DefaultValue(false)]
474                 public bool Sorted {
475                         get {
476                                 return sorted;
477                         }
478                         set {
479                                 sorted = value;
480
481                                 if (sorted)
482                                         items.PrivSort();
483                         }
484                 }
485
486                 [DefaultValue(false)]
487                 [Localizable(true)]
488                 public bool Wrap {
489                         get {
490                                 return wrap;
491                         }
492                         set {
493                                 wrap = value;
494                         }
495                 }
496                 #endregion      // Public Instance Properties
497
498                 #region Public Instance Methods
499                 public override void DownButton() {
500                         if (UserEdit)
501                                 go_to_user_input();
502
503                         int new_index = selected_index + 1;
504
505                         if (new_index >= items.Count) {
506                                 if (!wrap)
507                                         return;
508
509                                 new_index = 0;
510                         }
511
512                         SelectedIndex = new_index;
513                 }
514
515                 public override string ToString() {
516                         return base.ToString() + ", Items.Count: " + items.Count + ", SelectedIndex: " + selected_index;
517                 }
518
519                 public override void UpButton() {
520                         if (UserEdit)
521                                 go_to_user_input();
522
523                         int new_index = selected_index - 1;
524
525                         if (new_index < 0) {
526                                 if (!wrap) {
527                                         return;
528                                 }
529
530                                 new_index = items.Count - 1;
531                         }
532
533                         SelectedIndex = new_index;
534                 }
535                 #endregion      // Public Instance Methods
536
537                 #region Protected Instance Methods
538                 protected override AccessibleObject CreateAccessibilityInstance() {
539                         AccessibleObject        acc;
540
541                         acc = new AccessibleObject(this);
542                         acc.role = AccessibleRole.SpinButton;
543
544                         return acc;
545                 }
546
547                 protected override void OnChanged(object source, EventArgs e) {
548                         base.OnChanged (source, e);
549                 }
550
551                 protected void OnSelectedItemChanged(object source, EventArgs e) {
552                         EventHandler eh = (EventHandler)(Events [SelectedItemChangedEvent]);
553                         if (eh != null)
554                                 eh (this, e);
555                 }
556
557                 protected override void UpdateEditText() {
558                         if ((selected_index >= 0) && (selected_index < items.Count)) {
559                                 ChangingText = true;
560                                 Text = items.string_cache[selected_index].ToString();
561                         }
562                 }
563
564                 protected override void OnTextBoxKeyDown(object source, KeyEventArgs e) {
565                         base.OnTextBoxKeyDown (source, e);
566                 }
567
568                 #endregion      // Protected Instance Methods
569
570                 #region Events
571                 static object SelectedItemChangedEvent = new object ();
572                 public event EventHandler SelectedItemChanged {
573                         add { Events.AddHandler (SelectedItemChangedEvent, value); }
574                         remove { Events.RemoveHandler (SelectedItemChangedEvent, value); }
575                 }
576                 #endregion      // Events
577         }
578 }