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