src/Builder4/WindowLeftTree.bjs
[app.Builder.js] / src / Builder4 / WindowLeftTree.vala
1 static Xcls_WindowLeftTree  _WindowLeftTree;
2
3 public class Xcls_WindowLeftTree : Object 
4 {
5     public Gtk.ScrolledWindow el;
6     private Xcls_WindowLeftTree  _this;
7
8     public static Xcls_WindowLeftTree singleton()
9     {
10         if (_WindowLeftTree == null) {
11             _WindowLeftTree= new Xcls_WindowLeftTree();
12         }
13         return _WindowLeftTree;
14     }
15     public Xcls_view view;
16     public Xcls_model model;
17     public Xcls_renderer renderer;
18     public Xcls_LeftTreeMenu LeftTreeMenu;
19
20         // my vars (def)
21     public signal bool before_node_change (JsRender.Node? node);
22     public signal void changed ();
23     public signal void node_selected (JsRender.Node? node);
24     public Xcls_MainWindow main_window;
25
26     // ctor 
27     public Xcls_WindowLeftTree()
28     {
29         _this = this;
30         this.el = new Gtk.ScrolledWindow( null, null );
31
32         // my vars (dec)
33         this.main_window = null;
34
35         // set gobject values
36         this.el.shadow_type = Gtk.ShadowType.IN;
37         var child_0 = new Xcls_view( _this );
38         child_0.ref();
39         this.el.add (  child_0.el  );
40         var child_1 = new Xcls_LeftTreeMenu( _this );
41         child_1.ref();
42
43         // init method 
44
45         this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);    }
46
47     // user defined functions 
48     public           JsRender.Node? getActiveElement () { // return path to actie node.
49     
50          var path = this.getActivePath();
51          if (path.length < 1) {
52             return null;
53          }
54          return _this.model.pathToNode(path);
55          
56     }
57     public           JsRender.JsRender getActiveFile () {
58         return this.model.file;
59     }
60     public           string getActivePath () {
61         var model = this.model;
62         var view = this.view.el;
63         if (view.get_selection().count_selected_rows() < 1) {
64             return "";
65         }
66         Gtk.TreeIter iter;
67         Gtk.TreeModel mod;
68         view.get_selection().get_selected(out mod, out iter);
69         return mod.get_path(iter).to_string();
70     }
71     public class Xcls_view : Object 
72     {
73         public Gtk.TreeView el;
74         private Xcls_WindowLeftTree  _this;
75
76
77             // my vars (def)
78         public string dragData;
79         public string[] dropList;
80         public int drag_x;
81         public int drag_y;
82         public bool drag_in_motion;
83         public bool blockChanges;
84
85         // ctor 
86         public Xcls_view(Xcls_WindowLeftTree _owner )
87         {
88             _this = _owner;
89             _this.view = this;
90             this.el = new Gtk.TreeView();
91
92             // my vars (dec)
93             this.blockChanges = false;
94
95             // set gobject values
96             this.el.tooltip_column = 1;
97             this.el.enable_tree_lines = true;
98             this.el.headers_visible = false;
99             var child_0 = new Xcls_model( _this );
100             child_0.ref();
101             this.el.set_model (  child_0.el  );
102             var child_1 = new Xcls_TreeViewColumn4( _this );
103             child_1.ref();
104             this.el.append_column (  child_1.el  );
105
106             // init method 
107
108             {
109                 var description = new Pango.FontDescription();
110                 description.set_size(8000);
111                 this.el.modify_font(description);
112             
113                 var selection = this.el.get_selection();
114                 selection.set_mode( Gtk.SelectionMode.SINGLE);
115             
116             
117                 // is this really needed??
118                 /*
119                 this.selection.signal['changed'].connect(function() {
120                     _this.get('/LeftTree.view').listeners.cursor_changed.apply(
121                         _this.get('/LeftTree.view'), [ _this.get('/LeftTree.view'), '']
122                     );
123                 });
124                 */
125                 Gtk.drag_source_set (
126                     this.el,            /* widget will be drag-able */
127                     Gdk.ModifierType.BUTTON1_MASK,       /* modifier that will start a drag */
128                     BuilderApplication.targetList,            /* lists of target to support */
129                     Gdk.DragAction.COPY   | Gdk.DragAction.MOVE    |  Gdk.DragAction.LINK           /* what to do with data after dropped */
130                 );
131             
132                 // ?? needed??
133                 //Gtk.drag_source_add_text_targets(this.el); 
134             
135                 Gtk.drag_dest_set
136                 (
137                     this.el,              /* widget that will accept a drop */
138                     Gtk.DestDefaults.MOTION  | Gtk.DestDefaults.HIGHLIGHT,
139                     BuilderApplication.targetList,            /* lists of target to support */
140                     Gdk.DragAction.COPY   | Gdk.DragAction.MOVE   | Gdk.DragAction.LINK     /* what to do with data after dropped */
141                 );
142             
143                 //Gtk.drag_dest_set_target_list(this.el, Builder.Application.targetList);
144                 //Gtk.drag_dest_add_text_targets(this.el);
145             }
146             // listeners 
147             this.el.button_press_event.connect( ( ev) => {
148                 //console.log("button press?");
149                 if (! _this.before_node_change(null) ) {
150                    return true;
151                 }
152             
153                 
154                 if (ev.type != Gdk.EventType.BUTTON_PRESS  || ev.button != 3) {
155                     //print("click" + ev.type);
156                     return false;
157                 }
158                 Gtk.TreePath res;
159                 if (!_this.view.el.get_path_at_pos((int)ev.x,(int)ev.y, out res, null, null, null) ) {
160                     return true;
161                 }
162                  
163                 this.el.get_selection().select_path(res);
164                  
165                   //if (!this.get('/LeftTreeMenu').el)  { 
166                   //      this.get('/LeftTreeMenu').init(); 
167                   //  }
168                     
169                  _this.LeftTreeMenu.el.set_screen(Gdk.Screen.get_default());
170                  _this.LeftTreeMenu.el.show_all();
171                   _this.LeftTreeMenu.el.popup(null, null, null,  3, ev.time);
172                  //   print("click:" + res.path.to_string());
173                   return true;
174             });
175             this.el.cursor_changed.connect( ( ) => {
176             
177             
178                  if (this.blockChanges) { // probably not needed.. 
179                    return  ;
180                  }
181                   if (!_this.before_node_change(null) ) {
182                      this.blockChanges = true;
183                      this.el.get_selection().unselect_all();
184                      this.blockChanges = false;
185                      return;
186                  }
187                  if (_this.model.file == null) {
188                      return;
189                  } 
190                  
191                  //var render = this.get('/LeftTree').getRenderer();                
192                 print("LEFT TREE -> view -> selection changed called\n");
193                 
194                 
195                 // -- it appears that the selection is not updated.
196                 
197                 GLib.Timeout.add_full(GLib.Priority.DEFAULT,10 , () => {
198                      
199             
200                         if (this.el.get_selection().count_selected_rows() < 1) {
201             
202                             print("selected rows < 1\n");
203                             //??this.model.load( false);
204                             _this.node_selected(null);
205                             
206                             return false ;
207                         }
208                             
209                             //console.log('changed');
210                         var s = this.el.get_selection();
211                          Gtk.TreeIter iter;
212                          Gtk.TreeModel mod;
213                         s.get_selected(out mod, out iter);
214                         
215                         
216                         // var val = "";
217                         GLib.Value value;
218                         _this.model.el.get_value(iter, 2, out value);
219                         _this.model.activePath = mod.get_path(iter).to_string();
220                         
221                         var node = (JsRender.Node)value.dup_object();
222                         _this.node_selected(node);
223                         return false;
224                   });  
225                 //_this.after_node_change(node);
226             
227             //        _this.model.file.changed(node, "tree");
228                
229                 //Seed.print( value.get_string());
230                 return  ;
231                             
232             });
233             this.el.drag_begin.connect( ( ctx)  => {
234                 //print('SOURCE: drag-begin');
235                     
236                     
237                     //this.targetData = "";
238                     
239                     // find what is selected in our tree...
240                     
241                     var s = _this.view.el.get_selection();
242                     if (s.count_selected_rows() < 1) {
243                         return;
244                     }
245                     Gtk.TreeIter iter;
246                     Gtk.TreeModel mod;
247                     s.get_selected(out mod, out iter);
248             
249                     
250             
251                     // set some properties of the tree for use by the dropped element.
252                     GLib.Value value;
253                     _this.model.el.get_value(iter, 2, out value);
254                     var tp = mod.get_path(iter).to_string();
255                     var data = (JsRender.Node)(value.dup_object());
256                     var xname = data.fqn();
257                     print ("XNAME  IS " + xname+ "\n");
258                     this.dragData = tp;
259                     this.dropList = _this.model.file.palete().getDropList(xname);
260                     
261                     print ("DROP LIST IS " + string.joinv(", ", this.dropList) + "\n");
262                     
263             
264                     // make the drag icon a picture of the node that was selected
265                 
266                     
267                 // by default returns the path..
268                    var path = _this.model.el.get_path(iter);
269             
270                      
271                     var pix = this.el.create_row_drag_icon ( path);
272                     
273                     Gtk.drag_set_icon_surface (ctx, pix) ;
274                     
275                     return;
276             });
277             this.el.drag_end.connect( (drag_context) => {
278                 //Seed.print('LEFT-TREE: drag-end');
279                     this.dragData = "";
280                     this.dropList = null;
281             //        this.targetData = "";
282                     this.highlightDropPath("",0);
283             //        return true;
284             });
285             this.el.drag_motion.connect( ( ctx, x, y, time)  => {
286                print("got drag motion\n");
287                 var src = Gtk.drag_get_source_widget(ctx);
288                this.drag_x = x;
289                this.drag_y = y;     
290             
291                if (src != this.el) {
292                
293              
294              
295                 // the point of this is to detect where an item could be dropped..
296                     print("requesting drag data\n");
297                    this.drag_in_motion = true;
298                    
299                         // request data that will be recieved by the recieve...              
300                     Gtk.drag_get_data
301                     (
302                             this.el,         // will receive 'drag-data-received' signal 
303                             ctx,        // represents the current state of the DnD 
304                             Gdk.Atom.intern("STRING",true),    // the target type we want 
305                             time            // time stamp 
306                     );
307                     return true;
308               }    
309             
310             
311               print("action: %d\n", ctx.get_actions());
312              //print("GETTING POS");
313                 var  targetData = "";
314             
315                 Gtk.TreePath path;
316                 Gtk.TreeViewDropPosition pos;
317                 var isOver = _this.view.el.get_dest_row_at_pos(this.drag_x,this.drag_y, out path, out pos);
318             
319                 // if there are not items in the tree.. the we have to set isOver to true for anything..
320                 var isEmpty = false;
321                 if (_this.model.el.iter_n_children(null) < 1) {
322                     print("got NO children?\n");
323                     isOver = true; //??? 
324                     isEmpty = true;
325                     pos = Gtk.TreeViewDropPosition.INTO_OR_AFTER;
326                 }
327             
328             
329                 // ------------- a drag from self..
330             
331             
332                 //var action = Gdk.DragAction.COPY;
333                     // unless we are copying!!! ctl button..
334                 
335                 var action = (ctx.get_actions() & Gdk.DragAction.MOVE) > 0 ?
336                              Gdk.DragAction.COPY  : Gdk.DragAction.MOVE ;
337                             // Gdk.DragAction.MOVE : Gdk.DragAction.COPY ;
338             
339             
340                 if (_this.model.el.iter_n_children(null) < 1) {
341                     // no children.. -- asume it's ok..
342                     
343                     targetData = "|%d|".printf((int)Gtk.TreeViewDropPosition.INTO_OR_AFTER);
344                        
345                     this.highlightDropPath("", (Gtk.TreeViewDropPosition)0);        
346                     Gdk.drag_status(ctx, action ,time);
347                     return true;
348                     
349                     // continue through to allow drop...
350             
351                 } 
352                     
353                     
354             
355                 
356                 
357                 //print("ISOVER? " + isOver);
358                 if (!isOver) {
359               
360                     Gdk.drag_status(ctx, 0 ,time);
361                      this.highlightDropPath("", (Gtk.TreeViewDropPosition)0);                    
362                      return false;
363             
364                 }
365                         
366                 // drag node is parent of child..
367                 //console.log("SRC TREEPATH: " + src.treepath);
368                 //console.log("TARGET TREEPATH: " + data.path.to_string());
369                 
370                 // nned to check a  few here..
371                 //Gtk.TreeViewDropPosition.INTO_OR_AFTER
372                 //Gtk.TreeViewDropPosition.INTO_OR_BEFORE
373                 //Gtk.TreeViewDropPosition.AFTER
374                 //Gtk.TreeViewDropPosition.BEFORE
375                 
376                 // locally dragged items to not really use the 
377                 var selection_text = this.dragData;
378                 
379                         
380                         
381                 if (selection_text == null || selection_text.length < 1) {
382                             //print("Error  - drag selection text returned NULL");
383                          Gdk.drag_status(ctx, 0 ,time);
384                         this.highlightDropPath("", (Gtk.TreeViewDropPosition)0);
385                          return false;
386                  }
387                                    
388                         
389                         // see if we are dragging into ourself?
390                 var target_path = path.to_string();            
391                 print ("Drag  %s onto %s--%d\n ", selection_text, target_path, pos);
392                 
393                 // pos : 3 = ontop - 0 = after, 1 = before
394                 //print("target_path="+target_path);
395             
396                 // 
397                 if (selection_text  == target_path) {
398                     print("self drag ?? == we should perhaps allow copy onto self..\n");
399                             
400                      Gdk.drag_status(ctx, 0 ,time);
401                       this.highlightDropPath("", (Gtk.TreeViewDropPosition)0);
402                       return false;
403             //                 -- fixme -- this is not really correct..
404             
405                 }
406                         
407                 // check that 
408                 //print("DUMPING DATA");
409                 //console.dump(data);
410                 // path, pos
411                 
412                 //print(data.path.to_string() +' => '+  data.pos);
413                 
414                 // dropList is a list of xtypes that this node could be dropped on.
415                 // it is set up when we start to drag..
416                 
417                 
418                 targetData = _this.model.findDropNodeByPath( path.to_string(), this.dropList, pos);
419                     
420                 print("targetDAta: " + targetData +"\n");
421                 
422                 if (targetData.length < 1) {
423                     //print("Can not find drop node path");
424                    
425                     Gdk.drag_status(ctx, 0, time);
426                     this.highlightDropPath("", (Gtk.TreeViewDropPosition)0);
427                     return false;
428                 }
429                 
430                 var td_ar = targetData.split("|");
431                   
432                 
433             
434                 Gdk.drag_status(ctx, action ,time);
435                 this.highlightDropPath(td_ar[0], (Gtk.TreeViewDropPosition)int.parse(td_ar[1]));
436                 return true;
437                    
438                    
439             });
440             this.el.drag_data_get.connect( ( drag_context, data, info, time) => {
441                         
442                         
443                              //print("drag-data-get");
444                              var s = this.el.get_selection();
445                              if (s.count_selected_rows() < 1) {
446                                     data.set_text("",0);     
447                                      print("return empty string - no selection..");
448                                     return;
449                                 }
450                              
451                              Gtk.TreeIter iter;
452                              Gtk.TreeModel mod;
453                              
454                              s.get_selected(out mod, out iter);
455                              
456                             
457                             
458                              GLib.Value value;
459                              _this.model.el.get_value(iter, 2, out value);
460                              var ndata = (JsRender.Node)(value.dup_object());
461                              var xname = ndata.fqn();
462                             
463                             
464                             var tp = mod.get_path(iter).to_string();
465                             // by default returns the path..
466                             
467                            if ( info != Gdk.Atom.intern("STRING",true) ) {
468                                 tp = ndata.toJsonString();
469                            }   
470                            
471                            //data.set_text(tp,tp.length);   
472                             
473                             data.set (data.get_target (), 8, (uchar[]) tp.to_utf8 ());
474                         
475                             
476                            //  print("return " + tp);
477                         });
478             this.el.drag_data_received.connect( (ctx, x, y, sel, info, time)  => {
479               
480                     // THIS CODE ONLY RELATES TO drag  or drop of "NEW" elements or "FROM another tree.."
481               
482               
483                     //  print("Tree: drag-data-received\n");
484                     var selection_text = (string)sel.get_data();
485                     //print("selection_text= %s\n",selection_text);
486             
487                     var is_drag = this.drag_in_motion;
488                 
489                     
490             
491                     print("Is Drag %s\n", is_drag ? "Y": "N");
492                     var  targetData = "";
493                     
494                     Gtk.TreePath path;
495                     Gtk.TreeViewDropPosition pos;
496                     var isOver = _this.view.el.get_dest_row_at_pos(this.drag_x,this.drag_y, out path, out pos);
497                     
498                     // if there are not items in the tree.. the we have to set isOver to true for anything..
499                     var isEmpty = false;
500                     if (_this.model.el.iter_n_children(null) < 1) {
501                         print("got NO children?\n");
502                         isOver = true; //??? 
503                         isEmpty = true;
504                         pos = Gtk.TreeViewDropPosition.INTO_OR_AFTER;
505                     }
506                     
507                  
508                     //console.log("LEFT-TREE: drag-motion");
509                     var src = Gtk.drag_get_source_widget(ctx);
510                     
511                     // a drag from self - this should be handled by drop and motion.
512                     if (src == this.el) {
513                         print("Source == this element should not happen.. ? \n");
514                         return;
515                     }
516                     //print("drag_data_recieved from another element");
517                     
518                      
519                     
520                     
521                     if (selection_text == null || selection_text.length < 1 || !isOver) {
522                         // nothing valid foudn to drop...
523                            print("empty sel text or not over");
524                         if (is_drag) {
525                             Gdk.drag_status(ctx, 0, time);
526                             this.highlightDropPath("", (Gtk.TreeViewDropPosition)0);
527                             return;
528                         }
529                         Gtk.drag_finish (ctx, false, false, time);        // drop failed..
530                         // no drop action...
531                         return;            
532                     
533                     }
534                     var dropNode = new JsRender.Node(); 
535                     
536                     var dropNodeType  = selection_text;
537                     var show_templates = true;
538                     // for drop
539                     if (dropNodeType[0] == '{') {
540                         var pa = new Json.Parser();
541                         pa.load_from_data(dropNodeType);
542                          
543                         dropNode.loadFromJson( pa.get_root().get_object(), 2);
544                         dropNodeType = dropNode.fqn();
545                         show_templates = false;
546                         
547                         
548                     } else {
549             
550                         dropNode.setFqn(selection_text);
551                     }
552             
553                      
554                     // dropList --- need to gather this ... 
555                     print("get dropList for : %s\n",dropNodeType);            
556                     var dropList = _this.model.file.palete().getDropList(dropNodeType);
557                     
558                     print("dropList: %s\n", string.joinv(" , ", dropList));
559                     
560                     // if drag action is link ... then we can drop it anywahere...
561                      if ((ctx.get_actions() & Gdk.DragAction.LINK) > 0) {
562                          // if path is null?? dragging into an empty tree?
563                          targetData = (path == null ? "" :  path.to_string()) + "|%d".printf((int)pos);
564                      } else {
565                     
566                     
567                         targetData = _this.model.findDropNodeByPath( isEmpty ? "" : path.to_string(), dropList, pos);
568                      }
569                     
570                     
571                         
572                     print("targetDAta: " + targetData +"\n");
573                     
574                     if (targetData.length < 1) {
575                      
576                         // invalid drop path..
577                         if (this.drag_in_motion) {
578                             Gdk.drag_status(ctx, 0, time);
579                             this.highlightDropPath("", (Gtk.TreeViewDropPosition)0);
580                             return;
581                         }
582                         Gtk.drag_finish (ctx, false, false, time);        // drop failed..
583                         // no drop action...
584                         return;
585                     }
586                     // valid drop path..
587                     
588                       var td_ar = targetData.split("|");
589                       
590                     
591                     if (this.drag_in_motion) { 
592                         Gdk.drag_status(ctx, Gdk.DragAction.COPY ,time);
593             
594                         this.highlightDropPath(  td_ar[0]  , (Gtk.TreeViewDropPosition)int.parse(td_ar[1]));
595                         return;
596                     }
597                     // continue on to allow drop..
598                 
599             
600                     // at this point, drag is not in motion... -- as checked above... - so it's a real drop event..
601                     
602             
603                     _this.model.dropNode(targetData, dropNode, show_templates);
604                     print("ADD new node!!!\n");
605                         
606                     ///Xcls_DialogTemplateSelect.singleton().show( _this.model.file.palete(), node);
607                     
608                     Gtk.drag_finish (ctx, false, false,time);
609                     
610                     
611                         
612                         
613                   
614             });
615             this.el.drag_drop.connect( (  ctx, x, y, time)  => {
616                   //Seed.print("TARGET: drag-drop");
617                
618                
619                 var src = Gtk.drag_get_source_widget(ctx);
620                  
621                if (src != this.el) {
622                
623                 
624                    
625                    this.drag_in_motion = false;   
626                         // request data that will be recieved by the recieve...              
627                     Gtk.drag_get_data
628                     (
629                             this.el,         // will receive 'drag-data-received' signal 
630                             ctx,        // represents the current state of the DnD 
631                             Gdk.Atom.intern("application/json",true),    // the target type we want 
632                             time            // time stamp 
633                     );
634             
635                      
636                     // No target offered by source => error
637                
638             
639                      return  false;
640                  }
641                  
642                  // handle drop around self..
643                  
644                               
645                         
646                 //print("GETTING POS");
647                 var  targetData = "";
648                 
649                 Gtk.TreePath path;
650                 Gtk.TreeViewDropPosition pos;
651                 var isOver = _this.view.el.get_dest_row_at_pos(this.drag_x,this.drag_y, out path, out pos);
652                 
653                 // if there are not items in the tree.. the we have to set isOver to true for anything..
654                 var isEmpty = false;
655                 if (_this.model.el.iter_n_children(null) < 1) {
656                     print("got NO children?\n");
657                     isOver = true; //??? 
658                     isEmpty = true;
659                     pos = Gtk.TreeViewDropPosition.INTO_OR_AFTER;
660                 }
661                 
662                  
663                  
664                 //var action = Gdk.DragAction.COPY;
665                     // unless we are copying!!! ctl button..
666                 
667                 var action = (ctx.get_actions() & Gdk.DragAction.MOVE) > 0 ?
668                              Gdk.DragAction.COPY  : Gdk.DragAction.MOVE ;
669                             // Gdk.DragAction.MOVE : Gdk.DragAction.COPY ;
670             
671                   
672                 if (_this.model.el.iter_n_children(null) < 1) {
673                     // no children.. -- asume it's ok..
674                     
675                     targetData = "|%d|".printf((int)Gtk.TreeViewDropPosition.INTO_OR_AFTER);
676                      
677                     // continue through to allow drop...
678             
679                 } else {
680                             
681                             
682                 
683                             
684                             
685                             //print("ISOVER? " + isOver);
686                     if (!isOver) {
687                         
688                         Gtk.drag_finish (ctx, false, false, time);        // drop failed..
689                         return true; // not over apoint!?! - no action on drop or motion..
690                     }
691                             
692                     // drag node is parent of child..
693                     //console.log("SRC TREEPATH: " + src.treepath);
694                     //console.log("TARGET TREEPATH: " + data.path.to_string());
695                     
696                     // nned to check a  few here..
697                     //Gtk.TreeViewDropPosition.INTO_OR_AFTER
698                     //Gtk.TreeViewDropPosition.INTO_OR_BEFORE
699                     //Gtk.TreeViewDropPosition.AFTER
700                     //Gtk.TreeViewDropPosition.BEFORE
701                     
702                     // locally dragged items to not really use the 
703                     var selection_text = this.dragData;
704                     
705                     
706                     
707                     if (selection_text == null || selection_text.length < 1) {
708                         //print("Error  - drag selection text returned NULL");
709                       
710                          Gtk.drag_finish (ctx, false, false, time);        // drop failed..
711                          return true; /// -- fixme -- this is not really correct..
712                     }                
713                             
714                             // see if we are dragging into ourself?
715                             print ("got selection text of  " + selection_text);
716                     
717                     var target_path = path.to_string();
718                     //print("target_path="+target_path);
719             
720                     // 
721                     if (selection_text  == target_path) {
722                         print("self drag ?? == we should perhaps allow copy onto self..\n");
723                         
724                          Gtk.drag_finish (ctx, false, false, time);        // drop failed..
725             
726                          return true; /// -- fixme -- this is not really correct..
727             
728                     }
729                             
730                     // check that 
731                     //print("DUMPING DATA");
732                     //console.dump(data);
733                     // path, pos
734                     
735                     //print(data.path.to_string() +' => '+  data.pos);
736                     
737                     // dropList is a list of xtypes that this node could be dropped on.
738                     // it is set up when we start to drag..
739                     
740                     
741                     targetData = _this.model.findDropNodeByPath( path.to_string(), this.dropList, pos);
742                         
743                     print("targetDAta: " + targetData +"\n");
744                     
745                     if (targetData.length < 1) {
746                         //print("Can not find drop node path");
747                          
748                         Gtk.drag_finish (ctx, false, false, time);        // drop failed..
749                         return true;
750                     }
751                     
752                     var td_ar = targetData.split("|");
753                               
754                             
755                             
756                             // continue on to allow drop..
757               }
758                     // at this point, drag is not in motion... -- as checked above... - so it's a real drop event..
759             
760             
761                  var delete_selection_data = false;
762                     
763                 if (action == Gdk.DragAction.ASK)  {
764                     /* Ask the user to move or copy, then set the ctx action. */
765                 }
766             
767                 if (action == Gdk.DragAction.MOVE) {
768                     delete_selection_data = true;
769                 }
770                   
771                             // drag around.. - reorder..
772                 _this.model.moveNode(targetData, action);
773                     
774                    
775                     
776                     
777                     
778                     // we can send stuff to souce here...
779             
780             
781             // do we always say failure, so we handle the reall drop?
782                 Gtk.drag_finish (ctx, false, false,time); //delete_selection_data, time);
783             
784                 return true;
785              
786              
787              
788              
789              
790              
791             });
792         }
793
794         // user defined functions 
795         public           void highlightDropPath ( string treepath, Gtk.TreeViewDropPosition pos) {
796         
797                 // highlighting for drag/drop
798                 if (treepath.length > 0) {
799                     this.el.set_drag_dest_row(  new  Gtk.TreePath.from_string( treepath ), pos);
800                   } else {
801                     this.el.set_drag_dest_row(null, Gtk.TreeViewDropPosition.INTO_OR_AFTER);
802                  }
803                      
804         }
805         public           void selectNode (string treepath_str) {
806             //this.selection.select_path(new  Gtk.TreePath.from_string( treepath_str));
807              var tp = new Gtk.TreePath.from_string(treepath_str);
808              
809              this.el.set_cursor(tp, null, false);  
810              this.el.scroll_to_cell(tp, null, false, 0,0);
811         }
812     }
813     public class Xcls_model : Object 
814     {
815         public Gtk.TreeStore el;
816         private Xcls_WindowLeftTree  _this;
817
818
819             // my vars (def)
820         public DialogTemplateSelect template_select;
821         public JsRender.JsRender? file;
822         public string activePath;
823         public Project.Project? project;
824
825         // ctor 
826         public Xcls_model(Xcls_WindowLeftTree _owner )
827         {
828             _this = _owner;
829             _this.model = this;
830             this.el = new Gtk.TreeStore( 3, typeof(string),typeof(string),typeof(Object) );
831
832             // my vars (dec)
833             this.template_select = null;
834             this.file = null;
835             this.activePath = "";
836             this.project = null;
837
838             // set gobject values
839
840             // init method 
841
842             print("model initialized");        }
843
844         // user defined functions 
845         public           string findDropNode (string treepath_str, string[] targets) {
846         
847             // this is used by the dragdrop code in the roo version AFAIR..
848         
849             //var path = treepath_str.replace(/^builder-/, '');
850             // treemap is depreciated... - should really check if model has any entries..
851         
852             if (this.el.iter_n_children(null) < 1) {
853                 //print("NO KEYS");
854                 return "|%d".printf((int)Gtk.TreeViewDropPosition.INTO_OR_AFTER);
855             }
856             //print("FIND treepath: " + path);
857             //console.dump(this.treemap);
858             
859             //if (!treepath_str.match(/^builder-/)) {
860             //    return []; // nothing!
861             //}
862             if (targets.length > 0 && targets[0] == "*") {
863                 return  treepath_str;
864             }
865             return this.findDropNodeByPath(treepath_str,targets, -1);
866         }
867         public           void loadFile (JsRender.JsRender f) {
868             //console.dump(f);
869             this.el.clear();
870             this.file = f;
871             
872             
873         //    if (!f) {
874         //        console.log('missing file');
875         //        return;
876         //    }
877             
878             // load the file if not loaded..
879             if (f.tree == null) {
880                 f.loadItems( );
881             }
882             // if it's still null?
883             if (f.tree == null) {
884                 return;
885             }
886             
887             /// this.get('/Window').setTitle(f.project.getName() + ' - ' + f.name);
888             
889             //if (f.items.length && typeof(f.items[0]) == 'string') {
890             
891                 //this.get('/RightEditor').el.show();
892                 //this.get('/RightEditor.view').load( f.items[0]);
893             //    return;
894             //}
895             //print("LOAD");
896             //print(JSON.stringify(f.items, null,4));
897             //console.dump(f.items);
898             var o = new Gee.ArrayList<JsRender.Node>();
899             o.add(f.tree);
900             this.load(o,null);
901             
902             _this.view.el.expand_all();
903         
904             if (f.tree.items.size < 1) {
905                 // single item..
906                 
907                 //this.get('/Window.leftvpaned').el.set_position(80);
908                 // select first...
909                 _this.view.el.set_cursor( 
910                     new  Gtk.TreePath.from_string("0"), null, false);
911                 
912                 
913             } else {
914                   //this.get('/Window.leftvpaned').el.set_position(200);
915             }
916             
917             return;
918             /*    
919             
920             //print("hide right editior");
921             //this.get('/RightEditor').el.hide();
922             //this.get('/Editor').el.hide();
923             //print("set current tree");
924             //this.currentTree = this.toJS(false, false)[0];
925             //console.dump(this.currentTree);
926             //this.currentTree = this.currentTree || { items: [] };
927             //_this.renderView();
928             //console.dump(this.map);
929             //var RightPalete     = imports.Builder.RightPalete.RightPalete;
930             
931             
932             var pm = this.get('/RightPalete.model');
933             // set up provider..
934             
935             this.get('/RightPalete').provider = this.get('/LeftTree').getPaleteProvider();
936             
937             if (!this.get('/RightPalete').provider) {
938                 print ("********* PALETE PROVIDER MISSING?!!");
939             }
940             this.get('/LeftTree').renderView();
941             
942             pm.load( this.get('/LeftTree').getPaleteProvider().gatherList(this.listAllTypes()));
943             
944             
945                     
946             this.get('/Window.view-notebook').el.set_current_page(
947                 this.get('/LeftTree.model').file.getType()== 'Roo' ? 0 : -1);
948                 */
949                     
950         }
951         public    void updateSelected () {
952           
953            
954             var s = _this.view.el.get_selection();
955             
956              Gtk.TreeIter iter;
957             Gtk.TreeModel mod;
958             
959             
960             
961             if (!s.get_selected(out mod, out iter)) {
962                 return; // nothing seleted..
963             }
964           
965           GLib.Value value;
966             this.el.get_value(iter, 2, out value);
967             var node = (JsRender.Node)(value.get_object());
968             
969               this.el.set(iter, 0, node.nodeTitle(),
970                         1, node.nodeTip(), -1
971                 );
972         }
973         public           string findDropNodeByPath (string treepath_str, string[] targets, int in_pref = -1) {
974         
975             var path = treepath_str; // dupe it..
976             
977             
978             // pref : 3 = ontop - 0 = after, 1 = before
979             int pref = in_pref < 0  ?  Gtk.TreeViewDropPosition.INTO_OR_AFTER : in_pref;
980             
981             var last = "";
982             
983             //console.dump(this.treemap);
984             
985             print("findDropNodeByPath : got path length %d / %s\n", path.length, path);
986             
987             if (path.length == 0) {
988                 // top drop. // just return empty..
989                 return "|%d".printf((int)pref) ;
990                 
991             }
992             
993             
994             while (path.length > 0) {
995             
996                 if (path.length == treepath_str.length && pref != Gtk.TreeViewDropPosition.INTO_OR_AFTER) {
997                     if (path.last_index_of(":") < 0 ) {
998                         return "";
999                     }
1000                     path = path.substring(0, path.last_index_of(":"));
1001                     last = treepath_str;
1002                     print("DROP  before or after : using %s\n",path);
1003                     continue;
1004                 }
1005             
1006                 //print("LOOKING FOR PATH: " + path);
1007                 var node_data = this.pathToNode(path);
1008                 
1009                 if (node_data == null) {
1010                     print("node not found");
1011                     return "";
1012                 }
1013                 
1014                 var xname = node_data.fqn();
1015                 var match = "";
1016                 var prop = "";
1017                 
1018                 for (var i =0; i < targets.length; i++)  {
1019                     var tg = targets[i];
1020                     if ((tg == xname)  ) {
1021                         match = tg;
1022                         break;
1023                     }
1024                     // if target is "xxxx:name"
1025                     if (tg.contains(xname +":")) {
1026                         match = tg;
1027                         var ar = tg.split(":");
1028                         prop = ar[1];
1029                         break;
1030                     }
1031                 }
1032                 
1033                 if (match.length > 0) {
1034                     if (last.length > 0) { // pref is after/before..
1035                         // then it's after last
1036                         //if (pref > 1) {
1037                         //    return "";
1038                         //}
1039                         return last + "|%d".printf((int)pref) + "|" + prop;
1040         
1041                         
1042                     }
1043                     return path + "|%d".printf( (int) Gtk.TreeViewDropPosition.INTO_OR_AFTER);// + "|" + prop;
1044                 }
1045                 /*
1046                 last = "" + path;
1047                 var par = path.split(":");
1048                 string [] ppar = {};
1049                 for (var i = 0; i < par.length-1; i++) {
1050                     ppar += par[i];
1051                 }
1052                 
1053                 path = string.joinv(":", ppar);
1054                 */
1055                 break;
1056         
1057             }
1058             
1059             return "";
1060                     
1061         }
1062         public           void moveNode (string target_data, Gdk.DragAction action) 
1063         {
1064            
1065            /// target_data = "path|pos");
1066            
1067            
1068             //print("MOVE NODE");
1069             // console.dump(target_data);
1070             Gtk.TreeIter old_iter;
1071             Gtk.TreeModel mod;
1072             
1073             var s = _this.view.el.get_selection();
1074             s.get_selected(out mod , out old_iter);
1075             mod.get_path(old_iter);
1076             
1077             var node = this.pathToNode(mod.get_path(old_iter).to_string());
1078             //console.dump(node);
1079             if (node == null) {
1080                 print("moveNode: ERROR - node is null?");
1081             }
1082             
1083             
1084         
1085             // needs to drop first, otherwise the target_data 
1086             // treepath will be invalid.
1087         
1088             
1089             if ((action & Gdk.DragAction.MOVE) > 0) {
1090                     print("REMOVING OLD NODE : " + target_data + "\n");
1091                     node.remove();
1092                     this.dropNode(target_data, node, false);
1093                     this.el.remove(ref old_iter);
1094                     
1095                     
1096                                  
1097             } else {
1098                 print("DROPPING NODE // copy: " + target_data + "\n");
1099                 node = node.deepClone();
1100                 this.dropNode(target_data, node, false);
1101             }
1102             _this.changed();
1103             this.activePath= "";
1104             //this.updateNode(false,true);
1105         }
1106         public           void load (Gee.ArrayList<JsRender.Node> tr, Gtk.TreeIter? iter) 
1107         {
1108             Gtk.TreeIter citer;
1109             //this.insert(citer,iter,0);
1110             for(var i =0 ; i < tr.size; i++) {
1111                 if (iter != null) {
1112                     this.el.insert(out citer,iter,-1); // why not append?
1113                 } else {
1114                     this.el.append(out citer,null);
1115                 }
1116                 
1117                 this.el.set(citer, 0, tr.get(i).nodeTitle(),
1118                         1, tr.get(i).nodeTip(), -1
1119                 );
1120                 var o = new GLib.Value(typeof(Object));
1121                 o.set_object((Object)tr.get(i));
1122                 
1123                 this.el.set_value(citer, 2, o);
1124                 
1125                 if (tr.get(i).items.size > 0) {
1126                     this.load(tr.get(i).items, citer);
1127                 }
1128              
1129             }
1130         
1131             
1132         }
1133         public           void deleteSelected () {
1134             
1135             print("DELETE SELECTED?");
1136             //_this.view.blockChanges = true;
1137             print("GET SELECTION?");
1138         
1139             var s = _this.view.el.get_selection();
1140             
1141             print("GET  SELECTED?");
1142            Gtk.TreeIter iter;
1143             Gtk.TreeModel mod;
1144         
1145             
1146             if (!s.get_selected(out mod, out iter)) {
1147                 return; // nothing seleted..
1148             }
1149               
1150         
1151         
1152             this.activePath= "";      
1153             print("GET  vnode value?");
1154         
1155             GLib.Value value;
1156             this.el.get_value(iter, 2, out value);
1157             var data = (JsRender.Node)(value.get_object());
1158             print("removing node from Render\n");
1159             if (data.parent == null) {
1160                 this.file.tree = null;
1161             } else {
1162                 data.remove();
1163             }
1164             print("removing node from Tree\n");    
1165             s.unselect_all();
1166             this.el.remove(ref iter);
1167         
1168             
1169             
1170             
1171             // 
1172             
1173             
1174         
1175         
1176             this.activePath= ""; // again!?!?      
1177             //this.changed(null,true);
1178             
1179             _this.changed();
1180             
1181             _this.view.blockChanges = false;
1182         }
1183         public           JsRender.Node pathToNode (string path) {
1184          
1185              
1186              Gtk.TreeIter   iter;
1187              _this.model.el.get_iter_from_string(out iter, path);
1188              
1189              GLib.Value value;
1190              _this.model.el.get_value(iter, 2, out value);
1191              
1192              return (JsRender.Node)value.dup_object();
1193         
1194         }
1195         public           void dropNode (string target_data_str, JsRender.Node node, bool show_templates) {
1196         //         print("drop Node");
1197              // console.dump(node);
1198           //    console.dump(target_data);
1199           
1200           
1201                 // 0 = before , 1=after 2/3 onto
1202           
1203           
1204                 var target_data= target_data_str.split("|");
1205           
1206                 var parent_str = target_data[0].length > 0 ? target_data[0] : "";
1207                 var pos = target_data.length > 1 ? int.parse(target_data[1]) : 2; // ontop..
1208           
1209           
1210                 Gtk.TreePath tree_path  =   parent_str.length > 0 ? new  Gtk.TreePath.from_string( parent_str ) : null;
1211                 
1212                 
1213                 
1214                 //print("add " + tp + "@" + target_data[1]  );
1215                 
1216                 JsRender.Node parentNode = null;
1217                 
1218                 Gtk.TreeIter iter_after;
1219                 Gtk.TreeIter iter_par ;
1220                 
1221                
1222                  if (target_data.length == 3 && target_data[2].length > 0) {
1223                     node.props.set("* prop", target_data[2]);
1224                 }
1225         
1226                 Gtk.TreePath expand_parent = null;
1227                 
1228                 // we only need to show the template if it's come from else where?
1229                  if (show_templates) {
1230                  
1231                     if (this.template_select == null) {
1232                         this.template_select = new DialogTemplateSelect();
1233                      }
1234                  
1235                      var new_node = this.template_select.show(
1236                           (Gtk.Window) _this.el.get_toplevel (),
1237                               this.file.palete(),
1238                            node);
1239                            
1240                      if (new_node != null) {
1241                          node = new_node;
1242                      }
1243                 }        
1244                 
1245                  //print("pos is %d  \n".printf(pos));
1246                 
1247                  Gtk.TreeIter n_iter; 
1248                  
1249                  if ( parent_str.length < 1) {
1250                       this.el.append(out n_iter, null); // drop at top level..
1251                       node.parent = null;
1252                       this.file.tree = node;
1253                       
1254                       
1255                 } else   if (pos  < 2) {
1256                     //print(target_data[1]  > 0 ? 'insert_after' : 'insert_before');
1257                     
1258                     this.el.get_iter(out iter_after, tree_path );            
1259                     this.el.iter_parent(out iter_par, iter_after);
1260                     expand_parent = this.el.get_path(iter_par);
1261                     
1262                     GLib.Value value;
1263                     this.el.get_value( iter_par, 2, out value);
1264                     parentNode =  (JsRender.Node)value.dup_object();
1265                     
1266                     
1267                     this.el.get_value( iter_after, 2, out value);
1268                     var relNode =  (JsRender.Node)value.dup_object();
1269                     
1270                     if ( pos  > 0 ) {
1271                      
1272                         this.el.insert_after(out n_iter,    iter_par  , iter_after);
1273                         var ix = parentNode.items.index_of(relNode);
1274                         parentNode.items.insert(ix+1, node);
1275                         
1276                     } else {
1277                         this.el.insert_before(out n_iter,  iter_par  , iter_after);
1278                         var ix = parentNode.items.index_of(relNode);
1279                         parentNode.items.insert(ix, node);
1280          
1281                     }
1282                     node.parent = parentNode;
1283                     
1284                     
1285                     
1286                 } else {
1287                    //  print("appending to  " + parent_str);
1288                     this.el.get_iter(out iter_par, tree_path);
1289                     this.el.append(out n_iter,   iter_par );
1290                     expand_parent = this.el.get_path(iter_par);
1291                     
1292                     GLib.Value value;
1293                     this.el.get_value( iter_par, 2, out value);
1294                     parentNode =  (JsRender.Node)value.dup_object();
1295                     node.parent = parentNode;
1296                     parentNode.items.add(node);
1297                 }
1298                 
1299                 // reparent node in tree...
1300                
1301                 
1302                 // why only on no parent???
1303                 
1304                 //if (node.parent = null) {
1305                      
1306                    
1307                     
1308                 //}
1309                 
1310                 
1311                 // work out what kind of packing to use.. -- should be in 
1312                 if (!node.has("pack")   && parent_str.length > 1) {
1313                     
1314                     this.file.palete().fillPack(node,parentNode);
1315                     
1316                     
1317                 }
1318                 
1319                 // add the node...
1320                 
1321                 this.el.set(n_iter, 0, node.nodeTitle(), 1, node.nodeTip(), -1  );
1322                 var o = new GLib.Value(typeof(Object));
1323                 o.set_object((Object)node);
1324                 
1325                 this.el.set_value(n_iter, 2, o);
1326                 
1327                 
1328                 
1329                 
1330         // load children - if it has any..
1331               
1332                 if (node.items.size > 0) {
1333                     this.load(node.items, n_iter);
1334                     _this.view.el.expand_row(this.el.get_path(n_iter), true);
1335                 } else if (expand_parent != null && !_this.view.el.is_row_expanded(expand_parent)) {
1336                    _this.view.el.expand_row(expand_parent,true);
1337                 }
1338         
1339                 //if (tp != null && (node.items.length() > 0 || pos > 1)) {
1340                 //    _this.view.el.expand_row(this.el.get_path(iter_par), true);
1341                // }
1342                 // wee need to get the empty proptypes from somewhere..
1343                 
1344                 //var olditer = this.activeIter;
1345                 this.activePath = this.el.get_path(n_iter).to_string();
1346         
1347         
1348                 
1349                 
1350                 _this.view.el.set_cursor(this.el.get_path(n_iter), null, false);
1351                 _this.changed();
1352              
1353                 
1354                     
1355         }
1356     }
1357     public class Xcls_TreeViewColumn4 : Object 
1358     {
1359         public Gtk.TreeViewColumn el;
1360         private Xcls_WindowLeftTree  _this;
1361
1362
1363             // my vars (def)
1364
1365         // ctor 
1366         public Xcls_TreeViewColumn4(Xcls_WindowLeftTree _owner )
1367         {
1368             _this = _owner;
1369             this.el = new Gtk.TreeViewColumn();
1370
1371             // my vars (dec)
1372
1373             // set gobject values
1374             this.el.title = "test";
1375             var child_0 = new Xcls_renderer( _this );
1376             child_0.ref();
1377             this.el.pack_start (  child_0.el , true );
1378
1379             // init method 
1380
1381             this.el.add_attribute(_this.renderer.el , "markup", 0 );        }
1382
1383         // user defined functions 
1384     }
1385     public class Xcls_renderer : Object 
1386     {
1387         public Gtk.CellRendererText el;
1388         private Xcls_WindowLeftTree  _this;
1389
1390
1391             // my vars (def)
1392
1393         // ctor 
1394         public Xcls_renderer(Xcls_WindowLeftTree _owner )
1395         {
1396             _this = _owner;
1397             _this.renderer = this;
1398             this.el = new Gtk.CellRendererText();
1399
1400             // my vars (dec)
1401
1402             // set gobject values
1403         }
1404
1405         // user defined functions 
1406     }
1407     public class Xcls_LeftTreeMenu : Object 
1408     {
1409         public Gtk.Menu el;
1410         private Xcls_WindowLeftTree  _this;
1411
1412
1413             // my vars (def)
1414
1415         // ctor 
1416         public Xcls_LeftTreeMenu(Xcls_WindowLeftTree _owner )
1417         {
1418             _this = _owner;
1419             _this.LeftTreeMenu = this;
1420             this.el = new Gtk.Menu();
1421
1422             // my vars (dec)
1423
1424             // set gobject values
1425             var child_0 = new Xcls_MenuItem7( _this );
1426             child_0.ref();
1427             this.el.add (  child_0.el  );
1428             var child_1 = new Xcls_MenuItem8( _this );
1429             child_1.ref();
1430             this.el.add (  child_1.el  );
1431             var child_2 = new Xcls_MenuItem9( _this );
1432             child_2.ref();
1433             this.el.add (  child_2.el  );
1434         }
1435
1436         // user defined functions 
1437     }
1438     public class Xcls_MenuItem7 : Object 
1439     {
1440         public Gtk.MenuItem el;
1441         private Xcls_WindowLeftTree  _this;
1442
1443
1444             // my vars (def)
1445
1446         // ctor 
1447         public Xcls_MenuItem7(Xcls_WindowLeftTree _owner )
1448         {
1449             _this = _owner;
1450             this.el = new Gtk.MenuItem();
1451
1452             // my vars (dec)
1453
1454             // set gobject values
1455             this.el.label = "Delete Element";
1456
1457             // listeners 
1458             this.el.activate.connect( ( ) => {
1459                 
1460                 print("ACTIVATE?");
1461                 
1462               
1463                  _this.model.deleteSelected();
1464             });
1465         }
1466
1467         // user defined functions 
1468     }
1469     public class Xcls_MenuItem8 : Object 
1470     {
1471         public Gtk.MenuItem el;
1472         private Xcls_WindowLeftTree  _this;
1473
1474
1475             // my vars (def)
1476
1477         // ctor 
1478         public Xcls_MenuItem8(Xcls_WindowLeftTree _owner )
1479         {
1480             _this = _owner;
1481             this.el = new Gtk.MenuItem();
1482
1483             // my vars (dec)
1484
1485             // set gobject values
1486             this.el.label = "Save as Template";
1487
1488             // listeners 
1489             this.el.activate.connect( () => {
1490             
1491                  DialogSaveTemplate.singleton().show(
1492                         (Gtk.Window) _this.el.get_toplevel (), 
1493                         _this.model.file.palete(), 
1494                         _this.getActiveElement()
1495                 );
1496                  
1497                 
1498             });
1499         }
1500
1501         // user defined functions 
1502     }
1503     public class Xcls_MenuItem9 : Object 
1504     {
1505         public Gtk.MenuItem el;
1506         private Xcls_WindowLeftTree  _this;
1507
1508
1509             // my vars (def)
1510
1511         // ctor 
1512         public Xcls_MenuItem9(Xcls_WindowLeftTree _owner )
1513         {
1514             _this = _owner;
1515             this.el = new Gtk.MenuItem();
1516
1517             // my vars (dec)
1518
1519             // set gobject values
1520             this.el.label = "Save as Module";
1521
1522             // listeners 
1523             this.el.activate.connect( () => {
1524                 var node = _this.getActiveElement();
1525                  var name = DialogSaveModule.singleton().show(
1526                         (Gtk.Window) _this.el.get_toplevel (), 
1527                         _this.model.file.project, 
1528                         node
1529                  );
1530                  if (name.length < 1) {
1531                         return;
1532               
1533                  }
1534                  node.props.set("* xinclude", name);
1535                  node.items.clear();
1536             
1537             
1538                 var s = _this.view.el.get_selection();
1539                 
1540                 print("GET  SELECTED?");
1541                 Gtk.TreeIter iter;
1542                 Gtk.TreeModel mod;
1543             
1544                 
1545                 if (!s.get_selected(out mod, out iter)) {
1546                     return; // nothing seleted..
1547                 }
1548                 Gtk.TreeIter citer;
1549                 var n_cn = mod.iter_n_children(iter) -1;
1550                 for (var i = n_cn; i > -1; i--) {
1551                     mod.iter_nth_child(out citer, iter, i);
1552                     
1553             
1554                     print("removing node from Tree\n");    
1555                 
1556                     _this.model.el.remove(ref citer);
1557                 }
1558                 _this.changed();
1559                 _this.node_selected(node);
1560                  
1561                 
1562             });
1563         }
1564
1565         // user defined functions 
1566     }
1567 }