9da121d984f39507f5a61b21385dc342f523aa68
[sdk] / eda / libeda / src / idList.ec
1 #ifdef ECERE_STATIC
2 public import static "ecere"
3 #else
4 public import "ecere"
5 #endif
6
7 import "EDA.ec"
8 import "gui"
9
10 default:
11 extern int __ecereVMethodID_class_OnGetString;
12 extern int __ecereVMethodID_class_OnCompare;
13 extern int __ecereVMethodID_class_OnUnserialize;
14 extern int __ecereVMethodID_class_OnSerialize;
15 extern int __ecereVMethodID_class_OnFree;
16
17 static void UnusedFunction()
18 {
19    int a;
20    a.OnGetString(0,0,0);
21    a.OnFree();
22    a.OnCopy(null);
23    a.OnCompare(null);
24    a.OnSaveEdit(null,0);
25    a.OnEdit(null,null,0,0,0,0,0);
26    a.OnDisplay(null,0,0,0,0,0,0);
27    a.OnGetDataFromString(null);
28    a.OnUnserialize(null);
29    a.OnSerialize(null);
30 }
31 private:
32
33 public class Id : uint
34 {
35    class_data Table * table;     class_property Table * table     { set { class_data(table) = value; } get { return class_data(table); } };
36    //class_data Field * idField; class_property Field * idField { set { class_data(nameField) = value; } get { return class_data(idField); } };
37    //class_data Field * displayField; class_property Field * displayField { set { class_data(displayField) = value; } get { return class_data(displayField); } };
38    class_data Field * nameField; class_property Field * nameField { set { class_data(nameField) = value; } get { return class_data(nameField); } };
39    class_data char * addText;   class_property char * addText  { set { class_data(addText) = value; } };
40    class_data void * Refill;    class_property void * Refill   { set { class_data(Refill) = value; } };
41
42    Window OnEdit(DataBox dataBox, void * obsolete, int x, int y, int w, int h, void * userData)
43    {
44       if(this || !this) {     // FIXME
45          TableDropBox dropBox = dataBox.keepEditor ? (TableDropBox)dataBox.editor /*obsolete*/ : null;
46          if(!dropBox)
47          {
48 /*
49             if(eClass_IsDerived(dataBox._class, class(FieldDropBox)))
50             {
51                FieldDropBox fieldDropBox = (FieldDropBox)dataBox;
52
53             }
54             else if(eClass_IsDerived(dataBox._class, class(FieldBox)))
55             {
56                FieldBox fieldBox = (FieldBox)dataBox;
57
58             }
59 */
60
61             dropBox = TableDropBox
62             {
63                dataBox, borderStyle = 0, anchor = { 0, 0, 0, 0 }, 
64                modifyVirtualArea = false, activeStipple = false;
65                showNone = true;
66                nameField = *class_data(nameField);
67                table = *class_data(table);
68
69                bool DataBox::NotifySelect(DropBox control, DataRow row, Modifiers mods)
70                {
71                   uint id = row ? row.tag : 0;
72                   SetData(&id, mods.closingDropDown);
73                   return true;
74                }
75
76                bool DataBox::NotifyTextEntry(DropBox _dropBox, char * string, bool confirmed)
77                {
78                   TableDropBox dropBox = (TableDropBox)_dropBox;
79                   //Table tbl = dropBox.table.db.OpenTable(dropBox.table.name, { tableRows });
80                   //if(tbl)
81                   {
82                      /*FieldIndex indexedFields[1];
83                      Row r { };*/
84                      char * trimmed = new char[strlen(string) + 1];
85                      /*indexedFields[0] = { dropBox.nameField };
86                      tbl.GenerateIndex(1, indexedFields, false);
87                      r.tbl = tbl;*/
88                      DataRow row = null;
89
90                      TrimLSpaces(string, trimmed);
91                      TrimRSpaces(trimmed, trimmed);
92
93                      /*if(r.Find(dropBox.nameField, middle, nil, trimmed))
94                      {
95                         if(dropBox.filterField)
96                         {
97                            // TODO: Improve this... Multi field?
98                            while(true)
99                            {
100                               DataRow row;
101                               Id id = 0;
102                               Field fldId = dropBox.table.FindField(defaultIdField);
103                               r.GetData(fldId, id);
104                               row = dropBox.FindSubRow(id);
105                               if(row)
106                               {
107                                  dropBox.SelectRow(row);
108                                  break;
109                               }
110                               //if(!r.Find(dropBox.nameField, next, nil, trimmed))
111                               if(!r.Next())
112                                  break;
113                            }
114                         }
115                         else
116                         {
117                            Id id = 0;
118                            Field fldId = dropBox.table.FindField(defaultIdField);
119                            r.GetData(fldId, id);
120                            dropBox.SelectRow(dropBox.FindSubRow(id));
121                         }
122                      }
123                      */
124
125                      {
126                         for(row = dropBox.firstRow; row; row = row.next)
127                         {
128                            char * string = row.string;
129                            if(string && !strcmp(trimmed, string))
130                               break;
131                         }
132                      }
133                      if(row)
134                      {
135                         dropBox.SelectRow(row);
136                      }
137                      else
138                      {
139                         dropBox.changeContents = false;
140                         dropBox.contents = trimmed;
141                         dropBox.SelectRow(null);
142                         dropBox.changeContents = true;
143                      }
144                      //delete r;
145                   }
146                   return true;
147                }
148             };
149             if(class_data(Refill))
150                dropBox.Refill = class_data(Refill);
151
152             // dropBox.Refill();
153          }
154          dataBox.OnConfigure(dropBox);
155          dropBox.Create();
156          dropBox.currentRow = dropBox.FindSubRow(this);
157          if(!dropBox.currentRow && this)
158             dataBox.SetData((uint *)&this, false);
159          {
160             DataRow r = dropBox.currentRow;
161             if(r)
162                for(r = r.parent; r; r = r.parent)
163                   r.collapsed = false;
164          }
165          return dropBox;
166       }
167       return null;
168    }
169
170    char * OnGetString(char * tempString, void * fieldData, bool * needClass)
171    {
172       if(&this)
173       {
174          // FIXME
175          Table tbl = *class_data(table);
176          Field idField = tbl.FindField(defaultIdField);
177          Row r;
178          idRowCacheMutex.Wait();
179          if(!tbl.cachedIdRow)
180          {
181             tbl.cachedIdRow = Row { tbl };
182             incref tbl.cachedIdRow;
183          }
184          r = tbl.cachedIdRow;
185
186          if(this)
187          {
188             if(r.Find(idField, middle, nil, this))
189             {
190                String name = null;
191                Field * nameField = class_data(nameField);
192                if(nameField)
193                {
194 #ifdef _DEBUG
195                   char * fn = nameField->name;
196 #endif
197                   // Get name data from row
198                   int64 data = 0;
199                   Class type = nameField->type;
200                   if(type.type == unitClass && !type.typeSize)
201                   {
202                      Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
203                      if(dataType)
204                         type = dataType;
205                   }
206                   if(type.type == structClass)
207                      data = (int64)new0 byte[type.structSize];
208                   ((bool (*)())(void *)r.GetData)(r, *nameField, type, (type.type == structClass) ? (void *)data : &data);
209
210                   if(type.type == systemClass || type.type == unitClass || type.type == bitClass || type.type == enumClass)
211                      name = (String)type._vTbl[__ecereVMethodID_class_OnGetString](type, (void *)&data, tempString, null, null);
212                   else
213                      name = (String)type._vTbl[__ecereVMethodID_class_OnGetString](type, (void *)data, tempString, null, null);
214
215                   strcpy(tempString, name ? name : "");
216                   if(!(type.type == systemClass || type.type == unitClass || type.type == bitClass || type.type == enumClass))
217                      type._vTbl[__ecereVMethodID_class_OnFree](type, data);
218                }
219                else
220                {
221                   PrintLn("Id::OnGetString -- data type"/*, this._class.name, */" has no class_data(nameField)");
222                }
223             }
224             else
225                sprintf(tempString, "(Invalid %s entry: %d)", tbl.name, this);
226          }
227          else
228          {
229             sprintf(tempString, $"(Click to add a new %s...)", $"item"/*class_data(addText)*/);
230          }
231          // delete r;
232          idRowCacheMutex.Release();
233       }
234       return tempString;
235    }
236 }
237
238 public class IdList
239 {
240 public:
241    int count;
242    Id * ids;
243    class_data Class type;
244    class_property Class type
245    {
246       set {  class_data(type) = value; }
247       get { return class_data(type); }
248    };
249
250    public void Clear()
251    {
252       if(this)
253       {
254          delete ids;
255          count = 0;
256       }
257    }
258    
259    public bool Includes(Id id)
260    {
261       if(this)
262       {
263          int c;
264          for(c = 0; c < count; c++)
265             if(ids[c] == id) 
266                return true;
267       }
268       return false;
269    }
270
271    public bool Add(Id id)
272    {
273       int c;
274       for(c = 0; c < count; c++)
275          if(ids[c] == id) break;
276       if(c == count)
277       {
278          ids = renew ids Id[count + 1];
279          ids[count] = id;
280          count++;
281          return true;
282       }
283       return false;
284    }
285
286    public bool Delete(Id id)
287    {
288       int c;
289       for(c = 0; c < count; c++)
290          if(ids[c] == id)
291          {
292             if(c < count - 1)
293                memcpy(ids + c, ids + c + 1, (count - 1 - c) * sizeof(Id));
294             ids = renew ids Id[count - 1];
295             count--;
296             return true;
297          }
298       return false;
299    }
300
301    void OnUnserialize(IOChannel channel)
302    {
303       int c, count;
304
305       this = null;
306
307       channel.Unserialize(count);
308       if(count != MAXDWORD)
309       {
310          IdList idList = eInstance_New(_class); //IdList { };
311          idList.count = count;
312          idList.ids = new Id[count];
313          for(c = 0; c < count; c++)
314          {
315             Id id;
316             channel.Unserialize(id);
317             //Add(id);
318             idList.ids[c] = id;
319          }
320          this = idList;
321       }
322    }
323
324    void OnSerialize(IOChannel channel)
325    {
326       if(this)
327       {
328          int c;
329          channel.Serialize(count);
330          for(c = 0; c < count; c++)
331             channel.Serialize(ids[c]);
332       }
333       else
334       {
335          Id none = MAXDWORD;
336          channel.Serialize(none);
337       }
338    }
339    /*
340    void OnDisplay(Surface surface, int x, int y, int width, void * fieldData, Alignment alignment, DataDisplayFlags displayFlags)
341    {
342
343    }
344    */
345    
346    char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
347    {
348       stringOutput[0] = 0;
349       if(this)
350       {
351          int c;
352          for(c = 0; c<count; c++)
353          {
354             char tempString[256];
355             Class type = class_data(type);
356             if(c) strcat(stringOutput, ", ");
357
358             if(type)
359                type._vTbl[__ecereVMethodID_class_OnGetString](type, &ids[c], tempString, null, null);
360             // strcatf(stringOutput, "%d", ids[c]);
361             strcat(stringOutput, tempString);
362          }
363       }
364       return stringOutput;
365    }
366
367    bool OnGetDataFromString(char * string)
368    {
369       char value[256];
370       this = IdList { };
371       while(GetAlNum(&string, value, sizeof(value)))
372          if(isdigit(value[0]))
373             Add(atoi(value));
374       return true;
375    }
376
377    int OnCompare(IdList b)
378    {
379       if(!this && !b) return 0;
380       else if(this && !b) return 1;
381       else if(!this && b) return -1;
382       else if(count > b.count) return 1;
383       else if(count < b.count) return -1;
384       else
385       {
386          int c;
387          for(c = 0; c<count; c++)
388          {
389             int idA = ids[c], idB = b.ids[c];
390             if(idA > idB) return 1;
391             else if(idA < idB) return -1;
392          }         
393       }
394       return 0;
395    }
396
397    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
398    {
399       ListBox list
400       {
401          dataBox,
402          borderStyle = 0,
403          alwaysEdit = true,
404          anchor = { 0, 0, 0, 0 };
405
406          bool DataBox::NotifyChanged(ListBox listBox, DataRow row)
407          {
408             Id id = row.GetData(null);
409             if(!id)
410             {
411                if(row.next)
412                   listBox.DeleteRow(row);
413             }            
414             else
415             {
416                if(row == listBox.lastRow)
417                {
418                   row = listBox.AddRow();
419                   row.SetData(null, 0);
420                   listBox.scroll.y = listBox.scrollArea.h;
421                }
422                else if(row.next == listBox.lastRow)
423                   listBox.scroll.y = listBox.scrollArea.h;
424             }
425             Modified();
426             return true;
427          }
428       };
429
430       int c;
431       DataRow r;
432       /*if(!this)
433          this = eInstance_New(_class);
434          */
435       if(this || !this)    // FIXME
436       {
437          Class type = class_data(type);
438          list.AddField({ type, editable = true });
439       }
440       for(c = 0; c < (this ? count : 0); c++)
441       {
442          r = list.AddRow();
443          r.SetData(null, ids[c]);
444       }
445       r = list.AddRow();
446       r.SetData(null, 0);
447       list.Create();
448       list.modifiedDocument = false;
449       return list;
450    }
451
452    bool OnSaveEdit(Window window, void * object)
453    {
454       ListBox list = (ListBox) window;
455       if(list.modifiedDocument)
456       {
457          DataRow r;
458          if(!this)
459             this = eInstance_New(_class);
460          Clear();
461          for(r = list.firstRow; r; r = r.next)
462          {
463             Id id = r.GetData(null);
464             if(id)
465                Add(id);         
466          }
467          return true;
468       }
469       return false;
470    }
471    
472    ~IdList()
473    {
474       delete ids;
475    }
476 }
477
478 static void FreeString(String string)
479 {
480    delete string;
481 }
482
483 public class StringList
484 {
485    StringBinaryTree strings
486    {  
487       CompareKey = (void *)BinaryTree::CompareString;
488       FreeKey = (void *)FreeString;
489    };
490
491    void Clear()
492    {
493       strings.Free();
494    }
495    
496    bool Includes(String string)
497    {
498       return strings.FindString(string) != null;
499    }
500
501    bool Add(String string)
502    {
503       BTNode node { key = (uintptr)CopyString(string) };
504       if(strings.Add(node))
505          return true;
506       else
507       {
508          FreeString((String)node.key);
509          delete node;
510       }
511       return false;
512    }
513
514    bool Delete(String string)
515    {
516       BTNode node = strings.FindString(string);
517       if(node)
518       {
519          strings.Delete(node);
520          return true;
521       }
522       return false;
523    }
524
525    void _OnUnserialize(IOChannel channel)
526    {
527       channel.Get(strings);
528    }
529    
530    void OnUnserialize(IOChannel channel)
531    {
532       this = eInstance_New(class(StringList));
533       _OnUnserialize(channel);
534    }
535
536    void OnSerialize(IOChannel channel)
537    {
538       channel.Put(strings);
539    }
540
541    int OnCompare(StringList b)
542    {
543       BTNode nodeA = strings.first, nodeB = b.strings.first;
544       for(; nodeA || nodeB; nodeA = nodeA ? nodeA.next : null, nodeB = nodeB ? nodeB.next : null)
545       {
546          int result;
547          if(nodeA && !nodeB) return 1;
548          else if(nodeB && !nodeA) return -1;
549          else
550          {
551             result = strcmp((char *)nodeA.key, (char *)nodeB.key);
552             if(result) return result;
553          }
554       }         
555       return 0;
556    }
557
558    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
559    {
560       ListBox list
561       {
562          dataBox,
563          borderStyle = 0,
564          alwaysEdit = true,
565          anchor = { 0, 0, 0, 0 };
566
567          bool OnKeyHit(Key key, unichar ch)
568          {
569             return (key == enter) ? false : ListBox::OnKeyHit(key, ch);
570          }
571          
572          bool DataBox::NotifyChanged(ListBox listBox, DataRow row)
573          {
574             String string = row.GetData(null);
575             if(!string || !string[0])
576             {
577                if(row.next)
578                {
579                   listBox.DeleteRow(row);
580                   listBox.firstChild.Activate();
581                }
582             }            
583             else
584             {
585                if(row == listBox.lastRow)
586                {
587                   row = listBox.AddRow();
588                   row.SetData(null, null);
589                   listBox.scroll.y = listBox.scrollArea.h;
590                }
591                else
592                {
593                   row = row.next;
594                   /*
595                   if(row.next == listBox.lastRow)
596                      listBox.scroll.y = listBox.scrollArea.h;
597                   */
598                }
599                listBox.SelectRow(row);
600             }
601             Modified();
602             return true;
603          }
604
605          bool DataBox::NotifyEdited(ListBox listBox, DataRow row)
606          {
607             listBox.firstChild.Activate();
608             return true;
609          }
610
611          bool DataBox::NotifyModified(ListBox listBox, DataRow row)
612          {
613             String string = row.GetData(null);
614             if(!string || !string[0])
615             {
616                if(row.next)
617                {
618                   listBox.DeleteRow(row);
619                   listBox.firstChild.Activate();
620                }
621             }            
622             else
623             {
624                if(row == listBox.lastRow)
625                {
626                   row = listBox.AddRow();
627                   row.SetData(null, null);
628                   listBox.scroll.y = listBox.scrollArea.h;
629                }
630                else if(row.next == listBox.lastRow)
631                   listBox.scroll.y = listBox.scrollArea.h;
632             }
633             Modified();
634             return true;
635          }
636       };
637
638       BTNode node;
639       DataRow r;
640       
641       /*
642       {
643          if(!this)
644             this = eInstance_New(_class);
645       }
646       */
647
648       if(this || !this)    // FIXME
649       {
650       list.AddField({ class(char *), editable = true });
651       }
652       for(node = strings.first; node; node = node.next)
653       {
654          r = list.AddRow();
655          r.SetData(null, (String)node.key);
656       }
657       r = list.AddRow();
658       r.SetData(null, null);
659       list.Create();
660       list.modifiedDocument = false;
661       return list;
662    }
663
664    bool OnSaveEdit(Window window, void * object)
665    {
666       ListBox list = (ListBox) window;
667       if(list.modifiedDocument)
668       {
669          
670          DataRow r;
671          if(list.activeChild)
672             ((DataBox)list.activeChild).SaveData();
673
674          if(!this)
675             this = eInstance_New(_class);
676
677          // TODO: Fix how to get the data box...
678          Clear();
679          for(r = list.firstRow; r; r = r.next)
680          {
681             String string = r.GetData(null);
682             if(string)
683             {
684                Add(string);
685             }
686          }
687          return true;
688       }
689       return false;
690    }
691    
692    ~StringList()
693    {
694       strings.Free();
695    }
696 }
697
698 public class FixedMultiLineString : String
699 {
700    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
701    {
702       // Don't show the editbox right away so that the text is highlighted by default
703       char * string = "";
704       EditBox editBox
705       {
706          dataBox, visible = false,
707          borderStyle = 0,
708          textHorzScroll = true,
709          modifyVirtualArea = false,
710          anchor = { 0, 0, 0, 0 };
711          multiLine = true;
712
713          void DataBox::NotifyUpdate(EditBox editBox)
714          {
715             Modified();          
716             modifiedDocument = true;
717          }
718       };
719       editBox.contents = this;
720       editBox.visible = true;
721
722       editBox.Create();
723       if(!dataBox.active)
724          editBox.contents = this;
725       return editBox;
726    }
727
728    bool OnSaveEdit(Window window, void * object)
729    {
730       bool changed = false;
731       EditBox editBox = (EditBox)window;
732       if(editBox.modifiedDocument)
733       {
734          EditLine line;
735          int size = 0;
736          char * string;
737
738          delete this;
739
740          for(line = editBox.firstLine; line; line = line.next)
741             size += line.count+1;
742          this = string = new char[size+1];
743          size = 0;
744          for(line = editBox.firstLine; line; line = line.next)
745          {
746             memcpy(string + size, line.text, line.count);
747             size += line.count;
748             if(line.next)
749             {
750                string[size] = '\n';
751                size++;
752             }
753          }
754          string[size] = '\0';
755
756          changed = true;
757       }
758       return changed;
759    }
760 };
761
762 public class CIString : String
763 {
764    
765 }
766
767 public class MultiLineString : String
768 {
769    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
770    {
771       // Don't show the editbox right away so that the text is highlighted by default
772       char * string = "";
773       EditBox editBox
774       {
775          dataBox, visible = false,
776          borderStyle = 0,
777          hasHorzScroll = true, hasVertScroll = true,
778          modifyVirtualArea = false,
779          autoSize = dataBox.autoSize;
780          anchor = { 0, 0, 0, 0 };
781          multiLine = true;
782
783          void DataBox::NotifyUpdate(EditBox editBox)
784          {
785             Modified();
786             modifiedDocument = true;
787          }
788
789          bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
790          {
791             opacity = active ? 1.0f : parent.opacity;
792             return true;
793          }
794       };
795       editBox.contents = this;
796       editBox.visible = true;
797
798       editBox.Create();
799       if(!dataBox.active)
800          editBox.contents = this;
801       return editBox;
802    }
803
804    bool OnSaveEdit(Window window, void * object)
805    {
806       bool changed = false;
807       EditBox editBox = (EditBox)window;
808       if(editBox.modifiedDocument)
809       {
810          EditLine line;
811          int size = 0;
812          char * string;
813
814          delete this;
815
816          for(line = editBox.firstLine; line; line = line.next)
817             size += line.count+1;
818          this = string = new char[size+1];
819          size = 0;
820          for(line = editBox.firstLine; line; line = line.next)
821          {
822             memcpy(string + size, line.text, line.count);
823             size += line.count;
824             if(line.next)
825             {
826                string[size] = '\n';
827                size++;
828             }
829          }
830          string[size] = '\0';
831
832          changed = true;
833       }
834       return changed;
835    }
836 };
837
838 public struct DataList : OldList
839 {
840    class_data Class type;
841    class_data char * typeName;
842    // class_property Class type { set { class_data(type) = value; } };
843    class_property char * type { set { class_data(typeName) = value; } };
844    class_property Class dataType { get { return class_data(type); } };
845
846    void OnUnserialize(IOChannel channel)
847    {
848       Class type;
849       if(!class_data(type))
850          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
851       type = class_data(type);
852       
853       this = { };
854
855       while(true)
856       {
857          bool truth;
858          OldLink link;
859          channel.Unserialize(truth);
860          if(!truth) break;
861          link = OldLink { };
862
863          if(type)
864          {
865             if(type.type == structClass)
866                link.data = new0 byte[type.structSize];
867             type._vTbl[__ecereVMethodID_class_OnUnserialize](type, (type.type == structClass) ? link.data : &link.data, channel);
868          }
869          Add(link);
870       }
871    }
872
873    void OnSerialize(IOChannel channel)
874    {
875       OldLink node = first;
876       Class type;
877       if(!class_data(type))
878          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
879       type = class_data(type);
880
881       while(true)
882       {
883          bool truth = true;
884          if(node)
885          {
886             channel.Serialize(truth);
887             if(type.type == bitClass || type.type == unitClass || (type.type == systemClass && type.typeSize))
888                type._vTbl[__ecereVMethodID_class_OnSerialize](type, &node.data, channel);
889             else
890                type._vTbl[__ecereVMethodID_class_OnSerialize](type, node.data, channel);
891             node = node.next;
892          }
893          else
894          {
895             truth = false;
896             channel.Serialize(truth);
897             node = null;
898          }
899          if(!node) break;
900       }
901    }
902
903    int OnCompare(DataList b)
904    {
905       OldLink nodeA = first, nodeB = b.first;
906       for(; nodeA || nodeB; nodeA = nodeA ? nodeA.next : null, nodeB = nodeB ? nodeB.next : null)
907       {
908          int result;
909          if(nodeA && !nodeB) return 1;
910          else if(nodeB && !nodeA) return -1;
911          else
912          {
913             Class type = class_data(type);
914             result = type._vTbl[__ecereVMethodID_class_OnCompare](type, 
915                (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &nodeA.data : (void *)nodeA.data,
916                (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &nodeB.data : (void *)nodeB.data);
917             if(result) return result;
918          }
919       }         
920       return 0;
921    }
922
923    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
924    {
925       ListBox list
926       {
927          dataBox,
928          borderStyle = 0,
929          alwaysEdit = true,
930          anchor = { 0, 0, 0, 0 };
931
932          bool OnKeyHit(Key key, unichar ch)
933          {
934             return (key == enter) ? false : ListBox::OnKeyHit(key, ch);
935          }
936          
937          bool DataBox::NotifyChanged(ListBox listBox, DataRow row)
938          {
939             Class type = ((subclass(DataList))this.type).dataType;
940             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
941             {
942                String string = row.GetData(null);
943                if(!string || !string[0])
944                {
945                   /*if(row.next)
946                   {
947                      listBox.DeleteRow(row);
948                      listBox.firstChild.Activate();
949                   }*/
950                }            
951                else
952                {
953                   if(row == listBox.lastRow)
954                   {
955                      /*row = listBox.AddRow();
956                      row.SetData(null, null);
957                      listBox.scroll.y = listBox.scrollArea.h;*/
958                   }
959                   else
960                   {
961                      row = row.next;
962                   }
963                   listBox.SelectRow(row);
964                }
965                //Modified();
966             }
967             return true;
968          }
969          /*
970          bool DataBox::NotifyModified(ListBox listBox, DataRow row)
971          {
972             Class type = ((subclass(DataList))this.type).dataType;
973             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
974             {
975                String string = row.GetData(null);
976                if(!string || !string[0])
977                {
978                   if(row.next)
979                   {
980                      listBox.DeleteRow(row);
981                      listBox.firstChild.Activate();
982                   }
983                }            
984                else
985                {
986                   if(row == listBox.lastRow)
987                   {
988                      row = listBox.AddRow();
989                      row.SetData(null, null);
990                      listBox.scroll.y = listBox.scrollArea.h;
991                   }
992                   else if(row.next == listBox.lastRow)
993                      listBox.scroll.y = listBox.scrollArea.h;
994                }
995                Modified();
996             }
997             return true;
998          }
999          */
1000          bool DataBox::NotifyEditing(ListBox listBox, DataRow row)
1001          {
1002             Class type = ((subclass(DataList))this.type).dataType;
1003             DataBox editData = (DataBox)listBox.firstChild;
1004             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
1005             {
1006                if(type)
1007                {
1008                   if(type.type == normalClass && !*(void **)editData.data && strcmp(type.dataTypeString, "char *"))
1009                   {
1010                      *(void **)editData.data = eInstance_New(type);
1011                      row.SetData(null, *(void **)editData.data);
1012                   }
1013                }
1014
1015                if(row == listBox.lastRow)
1016                {
1017                   listBox.alwaysEdit = false;
1018                   if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
1019                      listBox.AddRow().SetData(null, null);
1020                   else
1021                      listBox.AddRow().SetData(null, 0);
1022                   listBox.scroll.y = listBox.scrollArea.h;
1023                   listBox.alwaysEdit = true;
1024                }
1025             }            
1026             return true;
1027          }
1028
1029          bool DataBox::NotifyEdited(ListBox listBox, DataRow row)
1030          {
1031             listBox.firstChild.Activate();
1032             return true;
1033          }
1034
1035          bool DataBox::NotifyEditDone(ListBox listBox, DataRow row)
1036          {
1037             Class type = ((subclass(DataList))this.type).dataType;
1038             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
1039             if(type)
1040             {
1041                void * data = ((type.type == normalClass || type.type == noHeadClass || type.type == structClass) ? row.GetData(null) : *(uint *)row.GetData(null));
1042                if(!data)
1043                {
1044                   //if(strcmp(type.dataTypeString, char *"))
1045                      //listBox.currentRow = null;
1046                   if(row != listBox.lastRow)
1047                   {
1048                      listBox.alwaysEdit = false;
1049                      listBox.DeleteRow(row);
1050                      listBox.alwaysEdit = true;
1051                   }
1052                }
1053             }
1054             Modified();
1055             return true;
1056          }
1057    
1058          void OnDestroy()
1059          {
1060             Class type = firstField.dataType;
1061             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
1062             if(type)
1063             {
1064                if(type.type == normalClass && strcmp(type.dataTypeString, "char *"))
1065                   eInstance_Delete(lastRow.GetData(null));
1066                if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
1067                   lastRow.SetData(null, null);
1068                else
1069                   lastRow.SetData(null, 0);
1070             }
1071          }
1072       };
1073
1074       OldLink node;
1075       DataRow r;
1076       Class type;
1077       if(!class_data(type))
1078          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
1079       type = class_data(type);
1080       
1081       list.AddField({ type, editable = true });
1082       for(node = first; node; node = node.next)
1083       {
1084          r = list.AddRow();
1085          if(type)
1086          {
1087             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
1088                r.SetData(null, CopyString((String)node.data));
1089             else
1090                r.SetData(null, node.data);
1091          }
1092       }
1093       r = list.AddRow();
1094       if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
1095          r.SetData(null, null);
1096       else
1097          r.SetData(null, 0);
1098       list.Create();
1099       list.modifiedDocument = false;
1100       return list;
1101    }
1102
1103    bool OnSaveEdit(Window window, void * object)
1104    {
1105       ListBox list = (ListBox) window;
1106       if(list.modifiedDocument)
1107       {
1108          Class type = class_data(type);
1109          DataRow r;
1110          if(list.activeChild)
1111             ((DataBox)list.activeChild).SaveData();
1112
1113          if(type.type != normalClass || !strcmp(type.dataTypeString, "char *"))
1114             OnFree();
1115          else if(type.type == structClass)
1116             Free(OldLink::Free);
1117          else
1118             Free(null);
1119
1120          for(r = list.firstRow; r; r = r.next)
1121          {
1122             if(type.type == noHeadClass || type.type == normalClass || type.type == structClass)
1123             {
1124                void * data = r.GetData(null);
1125                if(data)
1126                {
1127                   if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
1128                      Add(OldLink { data = CopyString(data) });
1129                   else if(type.type == structClass)
1130                   {
1131                      OldLink link { data = new byte[type.structSize] };
1132                      Add(link);
1133                      memcpy(link.data, data, type.structSize);
1134                   }
1135                   else
1136                      Add(OldLink { data = data });
1137                }
1138             }
1139             else
1140             {
1141                uint i = r.GetData(null);
1142                if(i)
1143                   Add(OldLink { data = (void *)i });
1144             }
1145          }
1146          return true;
1147       }
1148       return false;
1149    }
1150
1151    void OnFree()
1152    {  
1153       Class type;
1154       OldLink node;
1155
1156       if(!class_data(type))
1157          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
1158       type = class_data(type);
1159       while(node = first)
1160       {
1161          // TO STUDY: ONFREE SHOULD BE USED ONLY FOR LISTBOX?
1162          if(type)
1163          {
1164             if(type.type == normalClass && strcmp(type.dataTypeString, "char *"))
1165                eInstance_Delete(node.data);
1166             else if(type.type == structClass)
1167                delete node.data;
1168             else
1169                type._vTbl[__ecereVMethodID_class_OnFree](type, node.data);
1170          }
1171          Delete(node);
1172       }
1173    }
1174 };