cleaned all trailing white space from source files.
[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, 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
168    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                      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    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(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       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 class MultiLineString : String
772 {
773    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
774    {
775       // Don't show the editbox right away so that the text is highlighted by default
776       char * string = "";
777       EditBox editBox
778       {
779          dataBox, visible = false,
780          borderStyle = 0,
781          hasHorzScroll = true, hasVertScroll = true,
782          modifyVirtualArea = false,
783          autoSize = dataBox.autoSize;
784          anchor = { 0, 0, 0, 0 };
785          multiLine = true;
786
787          void DataBox::NotifyUpdate(EditBox editBox)
788          {
789             Modified();
790             modifiedDocument = true;
791          }
792
793          bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
794          {
795             opacity = active ? 1.0f : parent.opacity;
796             return true;
797          }
798       };
799       editBox.contents = this;
800       editBox.visible = true;
801
802       editBox.Create();
803       if(!dataBox.active)
804          editBox.contents = this;
805       return editBox;
806    }
807
808    bool OnSaveEdit(Window window, void * object)
809    {
810       bool changed = false;
811       EditBox editBox = (EditBox)window;
812       if(editBox.modifiedDocument)
813       {
814          EditLine line;
815          int size = 0;
816          char * string;
817
818          delete this;
819
820          for(line = editBox.firstLine; line; line = line.next)
821             size += line.count+1;
822          this = string = new char[size+1];
823          size = 0;
824          for(line = editBox.firstLine; line; line = line.next)
825          {
826             memcpy(string + size, line.text, line.count);
827             size += line.count;
828             if(line.next)
829             {
830                string[size] = '\n';
831                size++;
832             }
833          }
834          string[size] = '\0';
835
836          changed = true;
837       }
838       return changed;
839    }
840 };
841
842 public struct DataList : OldList
843 {
844    class_data Class type;
845    class_data char * typeName;
846    // class_property Class type { set { class_data(type) = value; } };
847    class_property char * type { set { class_data(typeName) = value; } };
848    class_property Class dataType { get { return class_data(type); } };
849
850    void OnUnserialize(IOChannel channel)
851    {
852       Class type;
853       if(!class_data(type))
854          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
855       type = class_data(type);
856
857       this = { };
858
859       while(true)
860       {
861          bool truth;
862          OldLink link;
863          channel.Unserialize(truth);
864          if(!truth) break;
865          link = OldLink { };
866
867          if(type)
868          {
869             if(type.type == structClass)
870                link.data = new0 byte[type.structSize];
871             ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, (type.type == structClass) ? link.data : &link.data, channel);
872          }
873          Add(link);
874       }
875    }
876
877    void OnSerialize(IOChannel channel)
878    {
879       OldLink node = first;
880       Class type;
881       if(!class_data(type))
882          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
883       type = class_data(type);
884
885       while(true)
886       {
887          bool truth = true;
888          if(node)
889          {
890             channel.Serialize(truth);
891             if(type.type == bitClass || type.type == unitClass || (type.type == systemClass && type.typeSize))
892                ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, &node.data, channel);
893             else
894                ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, node.data, channel);
895             node = node.next;
896          }
897          else
898          {
899             truth = false;
900             channel.Serialize(truth);
901             node = null;
902          }
903          if(!node) break;
904       }
905    }
906
907    int OnCompare(DataList b)
908    {
909       OldLink nodeA = first, nodeB = b.first;
910       for(; nodeA || nodeB; nodeA = nodeA ? nodeA.next : null, nodeB = nodeB ? nodeB.next : null)
911       {
912          int result;
913          if(nodeA && !nodeB) return 1;
914          else if(nodeB && !nodeA) return -1;
915          else
916          {
917             Class type = class_data(type);
918             result = ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type,
919                (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &nodeA.data : (void *)nodeA.data,
920                (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &nodeB.data : (void *)nodeB.data);
921             if(result) return result;
922          }
923       }
924       return 0;
925    }
926
927    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
928    {
929       ListBox list
930       {
931          dataBox,
932          borderStyle = 0,
933          alwaysEdit = true,
934          anchor = { 0, 0, 0, 0 };
935
936          bool OnKeyHit(Key key, unichar ch)
937          {
938             return (key == enter) ? false : ListBox::OnKeyHit(key, ch);
939          }
940
941          bool DataBox::NotifyChanged(ListBox listBox, DataRow row)
942          {
943             Class type = ((subclass(DataList))this.type).dataType;
944             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
945             {
946                String string = row.GetData(null);
947                if(!string || !string[0])
948                {
949                   /*if(row.next)
950                   {
951                      listBox.DeleteRow(row);
952                      listBox.firstChild.Activate();
953                   }*/
954                }
955                else
956                {
957                   if(row == listBox.lastRow)
958                   {
959                      /*row = listBox.AddRow();
960                      row.SetData(null, null);
961                      listBox.scroll.y = listBox.scrollArea.h;*/
962                   }
963                   else
964                   {
965                      row = row.next;
966                   }
967                   listBox.SelectRow(row);
968                }
969                //Modified();
970             }
971             return true;
972          }
973          /*
974          bool DataBox::NotifyModified(ListBox listBox, DataRow row)
975          {
976             Class type = ((subclass(DataList))this.type).dataType;
977             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
978             {
979                String string = row.GetData(null);
980                if(!string || !string[0])
981                {
982                   if(row.next)
983                   {
984                      listBox.DeleteRow(row);
985                      listBox.firstChild.Activate();
986                   }
987                }
988                else
989                {
990                   if(row == listBox.lastRow)
991                   {
992                      row = listBox.AddRow();
993                      row.SetData(null, null);
994                      listBox.scroll.y = listBox.scrollArea.h;
995                   }
996                   else if(row.next == listBox.lastRow)
997                      listBox.scroll.y = listBox.scrollArea.h;
998                }
999                Modified();
1000             }
1001             return true;
1002          }
1003          */
1004          bool DataBox::NotifyEditing(ListBox listBox, DataRow row)
1005          {
1006             Class type = ((subclass(DataList))this.type).dataType;
1007             DataBox editData = (DataBox)listBox.firstChild;
1008             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
1009             {
1010                if(type)
1011                {
1012                   if(type.type == normalClass && !*(void **)editData.data && strcmp(type.dataTypeString, "char *"))
1013                   {
1014                      *(void **)editData.data = eInstance_New(type);
1015                      row.SetData(null, *(void **)editData.data);
1016                   }
1017                }
1018
1019                if(row == listBox.lastRow)
1020                {
1021                   listBox.alwaysEdit = false;
1022                   if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
1023                      listBox.AddRow().SetData(null, null);
1024                   else
1025                      listBox.AddRow().SetData(null, 0);
1026                   listBox.scroll.y = listBox.scrollArea.h;
1027                   listBox.alwaysEdit = true;
1028                }
1029             }
1030             return true;
1031          }
1032
1033          bool DataBox::NotifyEdited(ListBox listBox, DataRow row)
1034          {
1035             listBox.firstChild.Activate();
1036             return true;
1037          }
1038
1039          bool DataBox::NotifyEditDone(ListBox listBox, DataRow row)
1040          {
1041             Class type = ((subclass(DataList))this.type).dataType;
1042             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
1043             if(type)
1044             {
1045                void * data = ((type.type == normalClass || type.type == noHeadClass || type.type == structClass) ? row.GetData(null) : *(uint *)row.GetData(null));
1046                if(!data)
1047                {
1048                   //if(strcmp(type.dataTypeString, char *"))
1049                      //listBox.currentRow = null;
1050                   if(row != listBox.lastRow)
1051                   {
1052                      listBox.alwaysEdit = false;
1053                      listBox.DeleteRow(row);
1054                      listBox.alwaysEdit = true;
1055                   }
1056                }
1057             }
1058             Modified();
1059             return true;
1060          }
1061
1062          void OnDestroy()
1063          {
1064             Class type = firstField.dataType;
1065             // if(type.type != normalClass || strcmp(type.dataTypeString, "char *"))
1066             if(type)
1067             {
1068                if(type.type == normalClass && strcmp(type.dataTypeString, "char *"))
1069                   eInstance_Delete(lastRow.GetData(null));
1070                if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
1071                   lastRow.SetData(null, null);
1072                else
1073                   lastRow.SetData(null, 0);
1074             }
1075          }
1076       };
1077
1078       OldLink node;
1079       DataRow r;
1080       Class type;
1081       if(!class_data(type))
1082          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
1083       type = class_data(type);
1084
1085       list.AddField({ type, editable = true });
1086       for(node = first; node; node = node.next)
1087       {
1088          r = list.AddRow();
1089          if(type)
1090          {
1091             if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
1092                r.SetData(null, CopyString((String)node.data));
1093             else
1094                r.SetData(null, node.data);
1095          }
1096       }
1097       r = list.AddRow();
1098       if(type.type == normalClass || type.type == structClass || type.type == noHeadClass)
1099          r.SetData(null, null);
1100       else
1101          r.SetData(null, 0);
1102       list.Create();
1103       list.modifiedDocument = false;
1104       return list;
1105    }
1106
1107    bool OnSaveEdit(Window window, void * object)
1108    {
1109       ListBox list = (ListBox) window;
1110       if(list.modifiedDocument)
1111       {
1112          Class type = class_data(type);
1113          DataRow r;
1114          if(list.activeChild)
1115             ((DataBox)list.activeChild).SaveData();
1116
1117          if(type.type != normalClass || !strcmp(type.dataTypeString, "char *"))
1118             OnFree();
1119          else if(type.type == structClass)
1120             Free(OldLink::Free);
1121          else
1122             Free(null);
1123
1124          for(r = list.firstRow; r; r = r.next)
1125          {
1126             if(type.type == noHeadClass || type.type == normalClass || type.type == structClass)
1127             {
1128                void * data = r.GetData(null);
1129                if(data)
1130                {
1131                   if(type.type == normalClass && !strcmp(type.dataTypeString, "char *"))
1132                      Add(OldLink { data = CopyString(data) });
1133                   else if(type.type == structClass)
1134                   {
1135                      OldLink link { data = new byte[type.structSize] };
1136                      Add(link);
1137                      memcpy(link.data, data, type.structSize);
1138                   }
1139                   else
1140                      Add(OldLink { data = data });
1141                }
1142             }
1143             else
1144             {
1145                uint i = r.GetData(null);
1146                if(i)
1147                   Add(OldLink { data = (void *)i });
1148             }
1149          }
1150          return true;
1151       }
1152       return false;
1153    }
1154
1155    void OnFree()
1156    {
1157       Class type;
1158       OldLink node;
1159
1160       if(!class_data(type))
1161          class_data(type) = eSystem_FindClass(__thisModule.application, class_data(typeName));
1162       type = class_data(type);
1163       while(node = first)
1164       {
1165          // TO STUDY: ONFREE SHOULD BE USED ONLY FOR LISTBOX?
1166          if(type)
1167          {
1168             if(type.type == normalClass && strcmp(type.dataTypeString, "char *"))
1169                eInstance_Delete(node.data);
1170             else if(type.type == structClass)
1171                delete node.data;
1172             else
1173                ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, node.data);
1174          }
1175          Delete(node);
1176       }
1177    }
1178 };