Fix #8062 - fix new file node selection issue
[roobuilder] / src / JsRender / NodeProp.vala
1 /**
2
3 This is a replacement for our key/value 
4 events and properties
5
6  
7 */ 
8 public enum JsRender.NodePropType 
9 {
10         
11         NONE, // fake value - used in popoveraddprop.
12         CTOR, // not used exetp getProperties for?
13         
14         
15         // these are all stored as properties, and should not overlap.
16         PROP,
17         
18         RAW,
19         METHOD,
20         SIGNAL,
21                 
22         // in theory we could have user defined properties that overlap - but probably not a good idea.
23         USER,
24
25
26         
27         // specials - these should be in a seperate list?
28         SPECIAL,
29
30
31         
32         // listerens can definatly overlap as they are stored in a seperate list. << no need to use this for listeners?
33         LISTENER;
34         
35
36         
37         public static string to_abbr(NodePropType intype)
38         {
39                 switch(intype) {
40                         case PROP: return  "";
41                         case RAW: return "$";
42                         case METHOD : return  "|";      
43                         case SIGNAL : return  "@"; // vala signal
44                         case USER : return  "#"; // user defined.
45                         case SPECIAL : return  "*"; // * prop| args | ctor | init
46                         case LISTENER : return  "";  // always raw...
47                         // not used
48                         case NONE:
49                         case CTOR:
50                                  return "";
51                         
52                 }
53                 return "??";
54         }
55         
56         // only usefull for reall values.
57         public static NodePropType from_string(string str)
58         {
59                 switch(str) {
60                         //case "" : return PROP;
61                         case "$": return  RAW;
62                         case "|": return METHOD;
63                         case "@": return  SIGNAL;
64                         case "#": return USER;
65                         case "*": return SPECIAL;
66                         //case "": return case LISTENER : return  ""  // always raw...
67                 }
68                 return PROP;
69         
70         }
71         public string to_name()
72         {
73                 switch (this) {
74                         case RAW:               return "Raw Property (not quoted or escaped)";
75                         case METHOD :   return "User Defined Method";   
76                         case SIGNAL :   return  "Vala Signal"; // vala signal
77                         case USER :     return  "User Defined Property"; // user defined.
78                         case SPECIAL : return  "Special Property (eg. prop / arg / ctor / init)"; // * prop| args | ctor | init
79                         case LISTENER : return  "Listener / Signal Handler";  // always raw...
80                         // not used
81                         case NONE:  return "None??";
82                         case CTOR:  return "Constructor?";
83                         case PROP:  return "Gtk/Roo Property";
84                         default: return "oops";
85                 
86                 }
87         }
88         
89         public static NodePropType[] alltypes()
90         {
91                 return {
92                         PROP,
93                         USER,
94                         RAW,                    
95                         METHOD,
96                         SIGNAL,
97
98                         SPECIAL,
99                         LISTENER
100                 //      CTOR,
101                         
102                 };
103         }
104         public bool can_have_opt_list()
105         {
106                 switch (this) {
107                         case RAW:               
108                         case METHOD : 
109                         case SIGNAL :   
110                         case SPECIAL :
111                         case LISTENER :
112                         case NONE:  
113                         case CTOR:   
114                                 return false;
115                         case USER :     
116                         case PROP: 
117                                 return true;
118                         default: 
119                                 return false;
120                 }
121                 
122         
123         }
124         
125         public static NodePropType nameToType(string str)
126         {
127                 foreach(var np in alltypes()) {
128                         if (np.to_name() == str) {
129                                 return np;
130                         }
131                 }
132                 return NONE;
133         
134         }
135         public static string[] get_pulldown_list()
136         {
137                 // eventually it needs to be smarter.... - but i did not have internet so could not use listmodels for the dropdown
138                  
139                 string[] ret = {};
140                 foreach(var np in alltypes()) {
141                         ret += np.to_name();
142                 }
143                 return ret;
144         
145         }
146         
147         
148 }
149
150
151
152 public class JsRender.NodeProp : Object {
153
154
155
156
157
158
159         private string _name = "";
160         public string name { 
161                 get {
162                         return this._name;  
163                 }
164                 set {
165                         if (this._name == value) {
166                                 return;
167                         }
168                         this._name = value;
169                  
170                         this.updated_count++;
171                         if (this.parent != null) {
172                                 // causes props/ listeners array to get updated.
173                                 this.parent.updated_count++;
174                         }
175                 }
176          }  // can not be updated... ?? you have to remove / replace?
177         private NodePropType  _ptype;
178          
179         public NodePropType  ptype {            
180                 get {
181                         return this._ptype;  
182                 }
183                 set {
184                         if (this._ptype == value) {
185                                 return;
186                         }
187                         this._ptype = value;
188                         if (this.parent != null) {
189                                 // causes props/ listeners array to get updated.
190                                 this.parent.updated_count++;
191                         }
192                 }
193         }
194         private string _rtype = "";
195         public string rtype { 
196                 get { 
197                         return this._rtype; 
198                 }
199                 set { 
200                         if (this._rtype == value) {
201                                 return;
202                         }
203                         this._rtype = value; 
204                         if (this.parent != null) {
205                                 this.parent.updated_count++;
206                         }
207                          
208                         this.updated_count++;
209                 }
210          } // return or type
211         
212         private string _val = "";
213         public string val { 
214                 get {
215                         return this._val;
216                 }
217                 set {
218                         if (this._val == value) {
219                                 return;
220                         }
221                         this._val = value;
222                         
223                         if (this.parent != null) {
224                                 this.parent.updated_count++;
225                         }
226                         this.updated_count++;
227                 }
228         }
229
230
231         private int _updated_count = 0;
232         public int updated_count { 
233                 get {
234                         return this._updated_count; 
235                 }
236                 set  {
237  
238                         // set things that are used to display values.
239                         this.to_display_name_prop = value.to_string();
240                         this.to_tooltip_name_prop = value.to_string();
241                                         
242                         this.val_short =  value.to_string();
243                         this.val_tooltip =  value.to_string();  
244                         this._updated_count = value;
245                 }
246  
247         } // changes to this trigger updates on the tree..
248         
249         public string sort_name {
250                 owned get {
251                         if (this.add_node == null) {
252                                 return this.name;
253                         }
254                         return this.name + " " + this.add_node.fqn();
255                 }
256                 set {}
257         
258         }
259         
260         private  string last_ptype_check = "";
261         public bool is_invalid_ptype {
262                   get;
263                   private set ;
264                   default = false;
265         }
266         
267         public bool update_is_valid_ptype(Project.Project project) 
268         {
269                  
270                 if (this.parent == null) {
271                         return false;
272                 }
273                 // what types are we interested in checking?
274                 // raw/ prop / user
275                 if (this.ptype != NodePropType.PROP && this.ptype != NodePropType.USER) {
276                         return false;
277                 }
278                 if (this.name == "xtype" || this.name == "xns"  || this.name == "id" ) { // flaky..
279                         return false;
280                 }
281                 if (this.name == this.last_ptype_check) {
282                         return this.is_invalid_ptype;
283                 }
284                 if (project.xtype != "Gtk") { // js not handled?
285                         return false;
286                 }
287                 this.last_ptype_check = this.name;
288                 
289                 var cls = Palete.Gir.factoryFqn(project, this.parent.fqn());
290                 if (cls == null) {
291                         this.is_invalid_ptype = false;
292                         return false;
293                 }
294                 var is_native = cls.props.has_key(this.name);
295                 if ( is_native && this.ptype == NodePropType.PROP ) {
296                         this.is_invalid_ptype = false;
297                         return false;
298                 }
299                 if ( !is_native && this.ptype == NodePropType.USER ) {
300                         this.is_invalid_ptype = false;
301                         return false;
302                 }
303
304                 this.is_invalid_ptype = true;
305                 return true;
306                 
307                  
308         
309         }
310         
311         public Node? parent; // the parent node.
312
313         
314         public int start_line = 0;
315         public int end_line = 0;
316         
317         // used by display list..
318         public GLib.ListStore  childstore; // WILL BE USED FOR properties with mutliple types 
319         public Node? add_node = null; // used when we list potentional nodes for properties in add list.
320
321         public string propertyof { get;   set; }
322         
323         
324         public NodeProp(string name, NodePropType ptype, string rtype, string val) {
325                 this.name = name;
326                 this.ptype = ptype;
327                 this.rtype = rtype;
328                 this.val = val;
329                 this.childstore = new GLib.ListStore( typeof(NodeProp));
330                  
331         }
332         public string ptype_as_string {
333                 get { return this.ptype.to_string(); }
334                 private set {}
335         }
336         
337         
338         public bool equals(NodeProp p) 
339         {
340                 return this.name == p.name 
341                                 && 
342                                 this.ptype == p.ptype 
343                                 && 
344                                 this.rtype == p.rtype 
345                                 && 
346                                 this.val == p.val;
347         }
348         
349         public NodeProp dupe()
350         {
351                 return new NodeProp(this.name, this.ptype, this.rtype,  this.val);
352         }
353         
354         
355         public NodeProp.from_json(string key, string inval)
356         {
357                 this.val = inval;
358                 var kkv = key.strip().split(" ");
359                 string[] kk = {};
360                 for (var i = 0; i < kkv.length; i++) {
361                         if (kkv[i].length > 0 ) {
362                                 kk += kkv[i];
363                         }
364                 }
365                 
366                 switch(kk.length) {
367                         case 1: 
368                                 this.name = kk[0];
369                                 this.ptype = NodePropType.PROP;
370                                 this.rtype = "";                
371                                 return;
372                         case 2: 
373                                 this.name = kk[1];
374                                 if (kk[0].length > 1) {
375                                         // void fred (no type)
376                                         this.rtype = kk[0];
377                                         this.ptype = NodePropType.PROP;
378                                 } else {
379                                         // has a ptype.
380                                         
381                                         this.rtype = ""; // no return type, only a ptype indicator.
382                                         this.ptype = NodePropType.from_string(kk[0]);
383                                 }
384                                 return;
385                         default: // 3 or more... (ignores spaces..)
386                         case 3:
387                                 this.name =  kk[2];
388                                 this.ptype = NodePropType.from_string(kk[0]);
389                                 this.rtype = kk[1];
390                                 return;
391                         
392                 }
393                 
394         }
395         public string  to_json_key()
396         {
397                 
398                 if (this.rtype == null) { // not sure why this happens.!?
399                         this.rtype = "";
400                 }
401                 var ortype = this.rtype +  (this.rtype.length > 0 ? " " : "");
402                 var oabbr = NodePropType.to_abbr(this.ptype);
403                 if (oabbr.length > 0) {
404                         oabbr += " ";
405                 }
406                 switch(this.ptype) {
407                         
408
409                         case NodePropType.LISTENER : 
410                                 return this.name; 
411                                 
412                         case NodePropType.PROP:
413                                 return ortype + this.name;                      
414                         
415                         case NodePropType.RAW:
416                         case NodePropType.METHOD:
417                         case NodePropType.SIGNAL:                       
418                         case NodePropType.USER :                        
419                                 return oabbr + ortype + this.name;                      
420                                 
421
422
423                         case NodePropType.SPECIAL:                      
424                                 return oabbr +   this.name;
425                         case NodePropType.NONE: // not used
426                         case NodePropType.CTOR:
427                                  return "";
428                          
429                 }
430                 return this.name;
431         }
432          
433         
434         public string  to_index_key()
435         {
436                 switch(this.ptype) {
437                         case NodePropType.PROP:
438                         case NodePropType.RAW:
439                         case NodePropType.METHOD :
440                         case NodePropType.SIGNAL :
441                         case NodePropType.USER : 
442                                 return this.name;
443                         
444                         case NodePropType.SPECIAL : 
445                                 return "* " + this.name;
446                                 
447                         // in seperate list..
448                         case NodePropType.LISTENER : 
449                                 return  this.name;
450                                 
451                         case NodePropType.NONE: // not used
452                         case NodePropType.CTOR:
453                                  return "";
454
455                                 
456                 }
457                 return this.name;
458         
459         }
460         // how it appears on the property list. -
461         
462         
463  
464         public string val_short { 
465                 set {
466                         // NOOp ??? should 
467                 }
468                 owned get {
469                         
470                          if (this._val.index_of("\n") < 0) {
471                                 return this._val;
472                          }
473                          var vals = this._val.split("\n");
474                          return vals[0]  + (vals.length > 1 ? " ..." : "");
475                 } 
476         }
477  
478     public string val_tooltip { 
479         set {
480                         // NOOp ??? should 
481                 }
482                 owned get {
483                         
484                                 return "<tt>" + GLib.Markup.escape_text(this.val) + "</tt>";
485                 } 
486     
487     
488     }
489     
490     public string to_display_name_prop { 
491                 set {
492                         // NOOp ??? should 
493                 }
494                 owned get {
495                          return  this.to_display_name();
496                 } 
497         }
498         
499         
500     
501         public string to_display_name()
502         {
503                 var bg = this.is_invalid_ptype ? "  bgcolor=\"red\"" : "";
504                 var nm =  GLib.Markup.escape_text(this.name);
505                 var rt =  GLib.Markup.escape_text(this.rtype);
506                 //return (this.rtype.length > 0 ? this.rtype + " " : "") +  this.name;
507                 // before we showed "@" for signals
508                 switch(this.ptype) {
509                         case NodePropType.PROP:
510                                 return  @"<span$bg>$nm</span>";
511                                 
512                         case NodePropType.RAW:
513                                 return @"<span style=\"italic\">$nm</span>";
514                                 
515                         case NodePropType.METHOD :
516                                 return @"<i>$rt</i> <span color=\"#008000\" font_weight=\"bold\">$nm</span>";
517                                 
518                         case NodePropType.SIGNAL : // purpley
519                                 return @"<span color=\"#ea00d6\" font_weight=\"bold\">$nm</span>";
520                                 
521                         case NodePropType.USER : 
522                                 return  @"<i>$rt</i> <span$bg font_weight=\"bold\">$nm</span>";
523                         
524                         case NodePropType.SPECIAL : 
525                                 return @"<span color=\"#0000CC\" font_weight=\"bold\">$nm</span>";       
526                                 
527                         // in seperate list..
528                         case NodePropType.LISTENER : 
529                                 return  @"<b>$nm</b>";
530                                 
531                         case NodePropType.NONE: // not used
532                         case NodePropType.CTOR:
533                                  return "";
534                 
535                                 
536                 }
537                 return this.name;
538         }
539         
540         public string to_tooltip_name_prop { 
541                 set {
542                         // NOOp ??? should 
543                 }
544                 owned get {
545                          return  this.to_tooltip_name();
546                 } 
547         }
548         
549         public string to_tooltip_name()
550         {
551                 
552                 //return (this.rtype.length > 0 ? this.rtype + " " : "") +  this.name;
553                 // before we showed "@" for signals
554                 switch(this.ptype) {
555                         case NodePropType.PROP:
556                         case NodePropType.SIGNAL:
557                         case NodePropType.RAW:
558                         case NodePropType.SPECIAL : 
559                         case NodePropType.LISTENER :
560                                 return GLib.Markup.escape_text(this.name) ;
561                                 
562                         case NodePropType.METHOD :
563                         case NodePropType.USER :                        
564                                 return  GLib.Markup.escape_text(this.rtype)  + " " + GLib.Markup.escape_text( this.name) ;
565                                 
566                         
567                                 
568                         case NodePropType.NONE: // not used
569                         case NodePropType.CTOR:
570                                  return "";
571                 
572                                 
573                 }
574                 return this.name;
575         }
576         // used ot sort the dispaly list of properties.
577         public string to_sort_key()
578         {
579                 var n = this.name;
580                  
581                 //return (this.rtype.length > 0 ? this.rtype + " " : "") +  this.name;
582                 // before we showed "@" for signals
583                 switch(this.ptype) {
584                         case NodePropType.PROP:
585                                 return "5" +  n;
586                                 
587                         case NodePropType.RAW:
588                                 return "5" +  n;
589                                 
590                         case NodePropType.METHOD :
591                                 return "2" +  n;
592                                 
593                         case NodePropType.SIGNAL :
594                                 return "3" +  n;
595                                 
596                         case NodePropType.USER : 
597                                 return "4" +  n;
598                         
599                         case NodePropType.SPECIAL : 
600                                 return "1" +  n;
601                                 
602                         // in seperate list..
603                         case NodePropType.LISTENER : 
604                                 return  "0" + this.name;
605                         
606                         case NodePropType.NONE: // not used
607                         case NodePropType.CTOR:
608                                  return "";
609                                 
610                 }
611                 return this.name;
612         }
613         // this is really only used for stuct ctors at present  
614         // which are only props (although RAW might be valid)
615         public string value_to_code()
616         {
617                 switch (this.ptype) {
618                         case NodePropType.PROP:
619                                 break;
620                                 
621                         case NodePropType.METHOD :                       
622                         case NodePropType.RAW:
623                         case NodePropType.SIGNAL :                      
624                         case NodePropType.USER : 
625                         case NodePropType.SPECIAL : 
626                         case NodePropType.LISTENER : 
627                         case NodePropType.NONE: // not used
628                         case NodePropType.CTOR:                 
629                                 return this.val;
630                 }
631                 if (this.rtype.contains(".")) {
632                         // probalby an enum
633                         return this.val;
634                 }
635                 
636                 
637                 switch (this.rtype) {
638                         case "string":
639                                 return "\"" + this.rtype.escape() + "\"";
640                         case "bool":
641                                 return this.val.down();
642                         case "float":
643                         case "double":
644                         default:
645                                 break;
646                                 
647                         
648                 
649                 }
650                 return this.val;
651         }
652         
653         
654         
655         public string to_tooltip()
656         {
657                  
658                 switch(this.ptype) {
659                         case NodePropType.PROP:
660                                 return this.rtype + " " + this.name + " = \"" + this.val + "\"";
661                         case NodePropType.LISTENER : 
662                                 // thsi might look a bit odd on javascript?
663                                 return "on " + this.name + " " + this.val;
664                                 
665                         case NodePropType.RAW:
666                                 return  this.rtype + " " + this.name + " = " + this.val;
667                         case NodePropType.METHOD :
668                                 // functions - js    FRED  function () { }  <<< could probably be cleaner..
669                                 // functions - vala    FRED () { }
670                                 return  this.rtype + " " + this.name  + " "  + this.val;
671                         case NodePropType.SIGNAL :
672                                 return  "signal: "  + this.rtype + " " + this.name  +  " " + this.val;
673                         case NodePropType.USER : 
674                                 return  "user defined: "  + this.rtype + " " + this.name  + " = "  + this.val;
675                         
676                         case NodePropType.SPECIAL:                      
677                                 return  "special property: "  + this.rtype + " " + this.name  + " = " +   this.val;                     
678
679                         case NodePropType.NONE: // not used
680                         case NodePropType.CTOR:
681                                  return "";
682                 }
683                 return this.name;
684                  
685         }
686         
687          
688         public string to_property_option_markup(bool isbold)
689         {
690                 return isbold ?  "<b>" + this.name + "</b>" : this.name;
691         }
692         
693         public string to_property_option_tooltip()
694         {
695                 return this.to_property_option_markup( false ); // fixme will probaly want help info (possibly by havinga  reference to the GirObject that its created from
696         }
697         
698         
699         public bool is(NodeProp comp) {
700                 if (comp.ptype == NodePropType.LISTENER || this.ptype == NodePropType.LISTENER ) { 
701                         return comp.ptype == this.ptype && comp.name == this.name;
702                 }
703                 return comp.to_index_key() == this.to_index_key();
704         
705         }
706         
707         
708         /*
709         public NodeProp.listenerfromjson(string str, string inval)
710         {
711                 this.val = inval;
712                 this.name = str;
713                 this.ptype = NodePropType.LISTENER;
714                 this.rtype = "";
715                 
716         }
717         */
718         // regular addition - should work for properties  
719         public NodeProp.prop(string name, string rtype = "", string val = "")
720         {
721                 this(name, NodePropType.PROP, rtype, val);
722         }
723         public NodeProp.raw(string name, string rtype = "", string val = "")
724         {
725                 this(name, NodePropType.RAW, rtype, val);
726         }
727         
728         public NodeProp.valamethod(string name, string rtype = "void", string val = "() {\n\n}")
729         {
730                 this(name, NodePropType.METHOD, rtype, val);
731         }
732         public NodeProp.jsmethod(string name,  string val = "function() {\n\n}")
733         {
734                 this(name, NodePropType.METHOD, "", val);
735         }
736         
737         // vala (and js) specials.. props etc.. - they only have name/value (not type) - type is in xns/xtype
738         public NodeProp.special(string name, string val = "")
739         {
740                 this(name, NodePropType.SPECIAL, "", val);
741         }
742          
743         public NodeProp.listener(string name,   string val = "")
744         {
745                 this(name, NodePropType.LISTENER, "", val);
746         }
747          
748         public NodeProp.user(string name, string rtype = "", string val = "")
749         {
750                 this(name, NodePropType.USER, rtype, val);
751         }
752         public NodeProp.sig(string name, string rtype = "void", string val = "()")
753         {
754                 this(name, NodePropType.SIGNAL, rtype, val);
755         }
756         public void appendChild(NodeProp child)
757         {
758                 this.childstore.append(child);
759
760         }
761          
762         
763         /**
764         could use enums.. but basically.
765         0 - > inline text editor
766         1  -> pulldown
767         2  -> full editor
768         */
769         public bool useTextArea()
770         {
771         
772                 var use_textarea = false;
773
774                 //------------ things that require the text editor...
775                 
776                 if (this.ptype == NodePropType.LISTENER) {
777                     use_textarea = true;
778                 }
779                 if (this.ptype == NodePropType.METHOD) { 
780                     use_textarea = true;
781                 }
782                     
783                 if ( this.name == "init" && this.ptype == NodePropType.SPECIAL) {
784                     use_textarea = true;
785                 }
786                 if (this.val.length > 40 || this.val.index_of("\n") > -1) { // long value...
787                     use_textarea = true;
788                 }
789                 
790                 return use_textarea;
791         
792         }
793         
794         
795         
796         
797 }
798         
799