sdk: const correctness
[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       TableDropBox dropBox = dataBox.keepEditor ? (TableDropBox)dataBox.editor /*obsolete*/ : null;
45       if(!dropBox)
46       {
47 /*
48          if(eClass_IsDerived(dataBox._class, class(FieldDropBox)))
49          {
50             FieldDropBox fieldDropBox = (FieldDropBox)dataBox;
51
52          }
53          else if(eClass_IsDerived(dataBox._class, class(FieldBox)))
54          {
55             FieldBox fieldBox = (FieldBox)dataBox;
56
57          }
58 */
59
60          dropBox = TableDropBox
61          {
62             dataBox, borderStyle = 0, anchor = { 0, 0, 0, 0 },
63             modifyVirtualArea = false, activeStipple = false;
64             showNone = true;
65             nameField = class_data(nameField) ? *class_data(nameField) : null;
66             table = class_data(table) ? *class_data(table) : null;
67
68             bool DataBox::NotifySelect(DropBox control, DataRow row, Modifiers mods)
69             {
70                // TOFIX: Id is still 32 bit
71                uint id = (uint)(row ? row.tag : 0);
72                SetData(&id, mods.closingDropDown);
73                return true;
74             }
75
76             bool DataBox::NotifyTextEntry(DropBox _dropBox, const 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                         const 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
168    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
169    {
170       if(&this)
171       {
172          // FIXME
173          Table tbl = class_data(table) ? *class_data(table) : null;
174          if(tbl)
175          {
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                      const 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 = ((char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, (void *)&data, tempString, null, null);
212                      else
213                         name = ((char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, (void *)data, tempString, null, null);
214
215                      if(name && name != tempString)
216                         strcpy(tempString, name ? name : "");
217                      if(!(type.type == systemClass || type.type == unitClass || type.type == bitClass || type.type == enumClass))
218                         ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)data);
219                   }
220                   else
221                   {
222                      PrintLn("Id::OnGetString -- data type"/*, this._class.name, */" has no class_data(nameField)");
223                   }
224                }
225                else
226                   sprintf(tempString, "(Invalid %s entry: %d)", tbl.name, this);
227             }
228             else
229             {
230                sprintf(tempString, $"(Click to add a new %s...)", $"item"/*class_data(addText)*/);
231             }
232             // delete r;
233             idRowCacheMutex.Release();
234          }
235          else
236          {
237             uint id = this;
238             id.OnGetString(tempString, null, null);
239          }
240       }
241       return tempString;
242    }
243 }
244
245 public class IdList
246 {
247 public:
248    int count;
249    Id * ids;
250    class_data Class type;
251    class_property Class type
252    {
253       set {  class_data(type) = value; }
254       get { return class_data(type); }
255    };
256
257    void Clear()
258    {
259       if(this)
260       {
261          delete ids;
262          count = 0;
263       }
264    }
265
266    bool Includes(Id id)
267    {
268       if(this)
269       {
270          int c;
271          for(c = 0; c < count; c++)
272             if(ids[c] == id)
273                return true;
274       }
275       return false;
276    }
277
278    bool Add(Id id)
279    {
280       int c;
281       for(c = 0; c < count; c++)
282          if(ids[c] == id) break;
283       if(c == count)
284       {
285          ids = renew ids Id[count + 1];
286          ids[count] = id;
287          count++;
288          return true;
289       }
290       return false;
291    }
292
293    bool Delete(Id id)
294    {
295       int c;
296       for(c = 0; c < count; c++)
297          if(ids[c] == id)
298          {
299             if(c < count - 1)
300                memcpy(ids + c, ids + c + 1, (count - 1 - c) * sizeof(Id));
301             ids = renew ids Id[count - 1];
302             count--;
303             return true;
304          }
305       return false;
306    }
307
308    void OnUnserialize(IOChannel channel)
309    {
310       int c, count;
311
312       this = null;
313
314       channel.Unserialize(count);
315       if(count != MAXDWORD)
316       {
317          IdList idList = eInstance_New(_class); //IdList { };
318          idList.count = count;
319          idList.ids = new Id[count];
320          for(c = 0; c < count; c++)
321          {
322             Id id;
323             channel.Unserialize(id);
324             //Add(id);
325             idList.ids[c] = id;
326          }
327          this = idList;
328       }
329    }
330
331    void OnSerialize(IOChannel channel)
332    {
333       if(this)
334       {
335          int c;
336          channel.Serialize(count);
337          for(c = 0; c < count; c++)
338             channel.Serialize(ids[c]);
339       }
340       else
341       {
342          Id none = MAXDWORD;
343          channel.Serialize(none);
344       }
345    }
346    /*
347    void OnDisplay(Surface surface, int x, int y, int width, void * fieldData, Alignment alignment, DataDisplayFlags displayFlags)
348    {
349
350    }
351    */
352
353    const char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
354    {
355       stringOutput[0] = 0;
356       if(this)
357       {
358          int c;
359          for(c = 0; c<count; c++)
360          {
361             char tempString[256];
362             Class type = class_data(type);
363             String s;
364             if(c) strcat(stringOutput, ", ");
365
366             if(type)
367                s = ((char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &ids[c], tempString, null, null);
368             // strcatf(stringOutput, "%d", ids[c]);
369             strcat(stringOutput, s);
370          }
371       }
372       return stringOutput;
373    }
374
375    bool OnGetDataFromString(const char * string)
376    {
377       char value[256];
378       this = IdList { };
379       while(GetAlNum(&string, value, sizeof(value)))
380          if(isdigit(value[0]))
381             Add(atoi(value));
382       return true;
383    }
384
385    int OnCompare(IdList b)
386    {
387       if(!this && !b) return 0;
388       else if(this && !b) return 1;
389       else if(!this && b) return -1;
390       else if(count > b.count) return 1;
391       else if(count < b.count) return -1;
392       else
393       {
394          int c;
395          for(c = 0; c<count; c++)
396          {
397             int idA = ids[c], idB = b.ids[c];
398             if(idA > idB) return 1;
399             else if(idA < idB) return -1;
400          }
401       }
402       return 0;
403    }
404
405    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
406    {
407       ListBox list
408       {
409          dataBox,
410          borderStyle = 0,
411          alwaysEdit = true,
412          anchor = { 0, 0, 0, 0 };
413
414          bool DataBox::NotifyChanged(ListBox listBox, DataRow row)
415          {
416             Id id = row.GetData(null);
417             if(!id)
418             {
419                if(row.next)
420                   listBox.DeleteRow(row);
421             }
422             else
423             {
424                if(row == listBox.lastRow)
425                {
426                   row = listBox.AddRow();
427                   row.SetData(null, 0);
428                   listBox.scroll.y = listBox.scrollArea.h;
429                }
430                else if(row.next == listBox.lastRow)
431                   listBox.scroll.y = listBox.scrollArea.h;
432             }
433             Modified();
434             return true;
435          }
436       };
437
438       int c;
439       DataRow r;
440       /*if(!this)
441          this = eInstance_New(_class);
442          */
443       {
444          Class type = class_data(type);
445          list.AddField({ type, editable = true });
446       }
447       for(c = 0; c < (this ? count : 0); c++)
448       {
449          r = list.AddRow();
450          r.SetData(null, ids[c]);
451       }
452       r = list.AddRow();
453       r.SetData(null, 0);
454       list.Create();
455       list.modifiedDocument = false;
456       return list;
457    }
458
459    bool OnSaveEdit(Window window, void * object)
460    {
461       ListBox list = (ListBox) window;
462       if(list.modifiedDocument)
463       {
464          DataRow r;
465          if(!this)
466             this = eInstance_New(_class);
467          Clear();
468          for(r = list.firstRow; r; r = r.next)
469          {
470             Id id = r.GetData(null);
471             if(id)
472                Add(id);
473          }
474          return true;
475       }
476       return false;
477    }
478
479    ~IdList()
480    {
481       delete ids;
482    }
483 }
484
485 static void FreeString(String string)
486 {
487    delete string;
488 }
489
490 public class StringList
491 {
492    StringBinaryTree strings
493    {
494       CompareKey = (void *)BinaryTree::CompareString;
495       FreeKey = (void *)FreeString;
496    };
497
498    void Clear()
499    {
500       strings.Free();
501    }
502
503    bool Includes(String string)
504    {
505       return strings.FindString(string) != null;
506    }
507
508    bool Add(String string)
509    {
510       BTNode node { key = (uintptr)CopyString(string) };
511       if(strings.Add(node))
512          return true;
513       else
514       {
515          FreeString((String)node.key);
516          delete node;
517       }
518       return false;
519    }
520
521    bool Delete(String string)
522    {
523       BTNode node = strings.FindString(string);
524       if(node)
525       {
526          strings.Delete(node);
527          return true;
528       }
529       return false;
530    }
531
532    void _OnUnserialize(IOChannel channel)
533    {
534       channel.Get(strings);
535    }
536
537    void OnUnserialize(IOChannel channel)
538    {
539       this = eInstance_New(class(StringList));
540       _OnUnserialize(channel);
541    }
542
543    void OnSerialize(IOChannel channel)
544    {
545       channel.Put(strings);
546    }
547
548    int OnCompare(StringList b)
549    {
550       BTNode nodeA = strings.first, nodeB = b.strings.first;
551       for(; nodeA || nodeB; nodeA = nodeA ? nodeA.next : null, nodeB = nodeB ? nodeB.next : null)
552       {
553          int result;
554          if(nodeA && !nodeB) return 1;
555          else if(nodeB && !nodeA) return -1;
556          else
557          {
558             result = strcmp((char *)nodeA.key, (char *)nodeB.key);
559             if(result) return result;
560          }
561       }
562       return 0;
563    }
564
565    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
566    {
567       ListBox list
568       {
569          dataBox,
570          borderStyle = 0,
571          alwaysEdit = true,
572          anchor = { 0, 0, 0, 0 };
573
574          bool OnKeyHit(Key key, unichar ch)
575          {
576             return (key == enter) ? false : ListBox::OnKeyHit(key, ch);
577          }
578
579          bool DataBox::NotifyChanged(ListBox listBox, DataRow row)
580          {
581             String string = row.GetData(null);
582             if(!string || !string[0])
583             {
584                if(row.next)
585                {
586                   listBox.DeleteRow(row);
587                   listBox.firstChild.Activate();
588                }
589             }
590             else
591             {
592                if(row == listBox.lastRow)
593                {
594                   row = listBox.AddRow();
595                   row.SetData(null, null);
596                   listBox.scroll.y = listBox.scrollArea.h;
597                }
598                else
599                {
600                   row = row.next;
601                   /*
602                   if(row.next == listBox.lastRow)
603                      listBox.scroll.y = listBox.scrollArea.h;
604                   */
605                }
606                listBox.SelectRow(row);
607             }
608             Modified();
609             return true;
610          }
611
612          bool DataBox::NotifyEdited(ListBox listBox, DataRow row)
613          {
614             listBox.firstChild.Activate();
615             return true;
616          }
617
618          bool DataBox::NotifyModified(ListBox listBox, DataRow row)
619          {
620             String string = row.GetData(null);
621             if(!string || !string[0])
622             {
623                if(row.next)
624                {
625                   listBox.DeleteRow(row);
626                   listBox.firstChild.Activate();
627                }
628             }
629             else
630             {
631                if(row == listBox.lastRow)
632                {
633                   row = listBox.AddRow();
634                   row.SetData(null, null);
635                   listBox.scroll.y = listBox.scrollArea.h;
636                }
637                else if(row.next == listBox.lastRow)
638                   listBox.scroll.y = listBox.scrollArea.h;
639             }
640             Modified();
641             return true;
642          }
643       };
644
645       BTNode node;
646       DataRow r;
647
648       /*
649       {
650          if(!this)
651             this = eInstance_New(_class);
652       }
653       */
654
655       list.AddField({ class(char *), editable = true });
656       for(node = strings.first; node; node = node.next)
657       {
658          r = list.AddRow();
659          r.SetData(null, (String)node.key);
660       }
661       r = list.AddRow();
662       r.SetData(null, null);
663       list.Create();
664       list.modifiedDocument = false;
665       return list;
666    }
667
668    bool OnSaveEdit(Window window, void * object)
669    {
670       ListBox list = (ListBox) window;
671       if(list.modifiedDocument)
672       {
673
674          DataRow r;
675          if(list.activeChild)
676             ((DataBox)list.activeChild).SaveData();
677
678          if(!this)
679             this = eInstance_New(_class);
680
681          // TODO: Fix how to get the data box...
682          Clear();
683          for(r = list.firstRow; r; r = r.next)
684          {
685             String string = r.GetData(null);
686             if(string)
687             {
688                Add(string);
689             }
690          }
691          return true;
692       }
693       return false;
694    }
695
696    ~StringList()
697    {
698       strings.Free();
699    }
700 }
701
702 public class FixedMultiLineString : String
703 {
704    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
705    {
706       // Don't show the editbox right away so that the text is highlighted by default
707       const char * string = "";
708       EditBox editBox
709       {
710          dataBox, visible = false,
711          borderStyle = 0,
712          textHorzScroll = true,
713          modifyVirtualArea = false,
714          anchor = { 0, 0, 0, 0 };
715          multiLine = true;
716
717          void DataBox::NotifyUpdate(EditBox editBox)
718          {
719             Modified();
720             modifiedDocument = true;
721          }
722       };
723       editBox.contents = this;
724       editBox.visible = true;
725
726       editBox.Create();
727       if(!dataBox.active)
728          editBox.contents = this;
729       return editBox;
730    }
731
732    bool OnSaveEdit(Window window, void * object)
733    {
734       bool changed = false;
735       EditBox editBox = (EditBox)window;
736       if(editBox.modifiedDocument)
737       {
738          EditLine line;
739          int size = 0;
740          char * string;
741
742          delete this;
743
744          for(line = editBox.firstLine; line; line = line.next)
745             size += line.count+1;
746          this = string = new char[size+1];
747          size = 0;
748          for(line = editBox.firstLine; line; line = line.next)
749          {
750             memcpy(string + size, line.text, line.count);
751             size += line.count;
752             if(line.next)
753             {
754                string[size] = '\n';
755                size++;
756             }
757          }
758          string[size] = '\0';
759
760          changed = true;
761       }
762       return changed;
763    }
764 };
765
766 public class CIString : String
767 {
768
769 }
770
771 public struct DataList : OldList
772 {
773    class_data Class type;
774    class_data char * typeName;
775    // class_property Class type { set { class_data(type) = value; } };
776    class_property char * type { set { class_data(typeName) = value; } };
777    class_property Class dataType { get { return class_data(type); } };
778
779    void OnUnserialize(IOChannel channel)
780    {
781       Class type;
782       if(!class_data(type))
783          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
784       type = class_data(type);
785
786       this = { };
787
788       while(true)
789       {
790          bool truth;
791          OldLink link;
792          channel.Unserialize(truth);
793          if(!truth) break;
794          link = OldLink { };
795
796          if(type)
797          {
798             if(type.type == structClass)
799                link.data = new0 byte[type.structSize];
800             ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, (type.type == structClass) ? link.data : &link.data, channel);
801          }
802          Add(link);
803       }
804    }
805
806    void OnSerialize(IOChannel channel)
807    {
808       OldLink node = first;
809       Class type;
810       if(!class_data(type))
811          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
812       type = class_data(type);
813
814       while(true)
815       {
816          bool truth = true;
817          if(node)
818          {
819             channel.Serialize(truth);
820             if(type.type == bitClass || type.type == unitClass || (type.type == systemClass && type.typeSize))
821                ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, &node.data, channel);
822             else
823                ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, node.data, channel);
824             node = node.next;
825          }
826          else
827          {
828             truth = false;
829             channel.Serialize(truth);
830             node = null;
831          }
832          if(!node) break;
833       }
834    }
835
836    int OnCompare(DataList b)
837    {
838       OldLink nodeA = first, nodeB = b.first;
839       for(; nodeA || nodeB; nodeA = nodeA ? nodeA.next : null, nodeB = nodeB ? nodeB.next : null)
840       {
841          int result;
842          if(nodeA && !nodeB) return 1;
843          else if(nodeB && !nodeA) return -1;
844          else
845          {
846             Class type = class_data(type);
847             result = ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type,
848                (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &nodeA.data : (void *)nodeA.data,
849                (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &nodeB.data : (void *)nodeB.data);
850             if(result) return result;
851          }
852       }
853       return 0;
854    }
855
856    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
857    {
858       ListBox list
859       {
860          dataBox,
861          borderStyle = 0,
862          alwaysEdit = true,
863          anchor = { 0, 0, 0, 0 };
864
865          bool OnKeyHit(Key key, unichar ch)
866          {
867             return (key == enter) ? false : ListBox::OnKeyHit(key, ch);
868          }
869
870          bool DataBox::NotifyChanged(ListBox listBox, DataRow row)
871          {
872             Class type = ((subclass(DataList))this.type).dataType;
873             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
874             {
875                String string = row.GetData(null);
876                if(!string || !string[0])
877                {
878                   /*if(row.next)
879                   {
880                      listBox.DeleteRow(row);
881                      listBox.firstChild.Activate();
882                   }*/
883                }
884                else
885                {
886                   if(row == listBox.lastRow)
887                   {
888                      /*row = listBox.AddRow();
889                      row.SetData(null, null);
890                      listBox.scroll.y = listBox.scrollArea.h;*/
891                   }
892                   else
893                   {
894                      row = row.next;
895                   }
896                   listBox.SelectRow(row);
897                }
898                //Modified();
899             }
900             return true;
901          }
902          /*
903          bool DataBox::NotifyModified(ListBox listBox, DataRow row)
904          {
905             Class type = ((subclass(DataList))this.type).dataType;
906             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
907             {
908                String string = row.GetData(null);
909                if(!string || !string[0])
910                {
911                   if(row.next)
912                   {
913                      listBox.DeleteRow(row);
914                      listBox.firstChild.Activate();
915                   }
916                }
917                else
918                {
919                   if(row == listBox.lastRow)
920                   {
921                      row = listBox.AddRow();
922                      row.SetData(null, null);
923                      listBox.scroll.y = listBox.scrollArea.h;
924                   }
925                   else if(row.next == listBox.lastRow)
926                      listBox.scroll.y = listBox.scrollArea.h;
927                }
928                Modified();
929             }
930             return true;
931          }
932          */
933          bool DataBox::NotifyEditing(ListBox listBox, DataRow row)
934          {
935             Class type = ((subclass(DataList))this.type).dataType;
936             DataBox editData = (DataBox)listBox.firstChild;
937             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
938             {
939                if(type)
940                {
941                   if(type.type == normalClass && !*(void **)editData.data && strcmp(type.dataTypeString, "char *"))
942                   {
943                      *(void **)editData.data = eInstance_New(type);
944                      row.SetData(null, *(void **)editData.data);
945                   }
946                }
947
948                if(row == listBox.lastRow)
949                {
950                   listBox.alwaysEdit = false;
951                   if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
952                      listBox.AddRow().SetData(null, null);
953                   else
954                      listBox.AddRow().SetData(null, 0);
955                   listBox.scroll.y = listBox.scrollArea.h;
956                   listBox.alwaysEdit = true;
957                }
958             }
959             return true;
960          }
961
962          bool DataBox::NotifyEdited(ListBox listBox, DataRow row)
963          {
964             listBox.firstChild.Activate();
965             return true;
966          }
967
968          bool DataBox::NotifyEditDone(ListBox listBox, DataRow row)
969          {
970             Class type = ((subclass(DataList))this.type).dataType;
971             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
972             if(type)
973             {
974                void * data = ((type.type == normalClass || type.type == noHeadClass || type.type == structClass) ? row.GetData(null) : *(uint *)row.GetData(null));
975                if(!data)
976                {
977                   //if(strcmp(type.dataTypeString, char *"))
978                      //listBox.currentRow = null;
979                   if(row != listBox.lastRow)
980                   {
981                      listBox.alwaysEdit = false;
982                      listBox.DeleteRow(row);
983                      listBox.alwaysEdit = true;
984                   }
985                }
986             }
987             Modified();
988             return true;
989          }
990
991          void OnDestroy()
992          {
993             Class type = firstField.dataType;
994             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
995             if(type)
996             {
997                if(type.type == normalClass && strcmp(type.dataTypeString, "char *"))
998                   eInstance_Delete(lastRow.GetData(null));
999                if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
1000                   lastRow.SetData(null, null);
1001                else
1002                   lastRow.SetData(null, 0);
1003             }
1004          }
1005       };
1006
1007       OldLink node;
1008       DataRow r;
1009       Class type;
1010       if(!class_data(type))
1011          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
1012       type = class_data(type);
1013
1014       list.AddField({ type, editable = true });
1015       for(node = first; node; node = node.next)
1016       {
1017          r = list.AddRow();
1018          if(type)
1019          {
1020             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
1021                r.SetData(null, CopyString((String)node.data));
1022             else
1023                r.SetData(null, node.data);
1024          }
1025       }
1026       r = list.AddRow();
1027       if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
1028          r.SetData(null, null);
1029       else
1030          r.SetData(null, 0);
1031       list.Create();
1032       list.modifiedDocument = false;
1033       return list;
1034    }
1035
1036    bool OnSaveEdit(Window window, void * object)
1037    {
1038       ListBox list = (ListBox) window;
1039       if(list.modifiedDocument)
1040       {
1041          Class type = class_data(type);
1042          DataRow r;
1043          if(list.activeChild)
1044             ((DataBox)list.activeChild).SaveData();
1045
1046          if(type.type != normalClass || !strcmp(type.dataTypeString, "char *"))
1047             OnFree();
1048          else if(type.type == structClass)
1049             Free(OldLink::Free);
1050          else
1051             Free(null);
1052
1053          for(r = list.firstRow; r; r = r.next)
1054          {
1055             if(type.type == noHeadClass || type.type == normalClass || type.type == structClass)
1056             {
1057                void * data = r.GetData(null);
1058                if(data)
1059                {
1060                   if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
1061                      Add(OldLink { data = CopyString(data) });
1062                   else if(type.type == structClass)
1063                   {
1064                      OldLink link { data = new byte[type.structSize] };
1065                      Add(link);
1066                      memcpy(link.data, data, type.structSize);
1067                   }
1068                   else
1069                      Add(OldLink { data = data });
1070                }
1071             }
1072             else
1073             {
1074                uint i = r.GetData(null);
1075                if(i)
1076                   Add(OldLink { data = (void *)i });
1077             }
1078          }
1079          return true;
1080       }
1081       return false;
1082    }
1083
1084    void OnFree()
1085    {
1086       Class type;
1087       OldLink node;
1088
1089       if(!class_data(type))
1090          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
1091       type = class_data(type);
1092       while(node = first)
1093       {
1094          // TO STUDY: ONFREE SHOULD BE USED ONLY FOR LISTBOX?
1095          if(type)
1096          {
1097             if(type.type == normalClass && strcmp(type.dataTypeString, "char *"))
1098                eInstance_Delete(node.data);
1099             else if(type.type == structClass)
1100                delete node.data;
1101             else
1102                ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, node.data);
1103          }
1104          Delete(node);
1105       }
1106    }
1107 };