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