6 This basically provides all the data needed to add stuff to gtk objects
21 public class Gtk : Palete {
23 public Gee.ArrayList<string> package_cache;
25 public Gtk(Project.Project project)
30 var context = new Vala.CodeContext ();
32 this.package_cache = this.loadPackages(Path.get_dirname (context.get_vapi_path("glib-2.0")));
33 this.package_cache.add_all(
34 this.loadPackages(Path.get_dirname (context.get_vapi_path("gee-0.8")))
42 // a) build a list of all widgets that can be added generically.
43 // b) build child list for all containers.
44 // c) build child list for all widgets (based on properties)
45 // d) handle oddities?
47 public bool loaded = false; // set to false to force a reload
49 public override void load ()
54 Gir.factory(this.project, "Gtk"); // triggers a load...
56 this.init_node_defaults();
57 this.add_node_default_from_ctor_all();
58 this.init_child_defaults();
69 public string doc(string what)
71 var ns = what.split(".")[0];
72 var gir = Gir.factory(this.project,ns);
73 return ((Gir) gir).doc(what);
75 //return typeof(this.comments[ns][what]) == 'undefined' ? '' : this.comments[ns][what];
78 public GirObject? loadGir (string ename) {
79 var es = ename.split(".");
83 var gir = Gir.factory(this.project,es[0]);
91 // does not handle implements...
92 public override GirObject? getClass(string ename)
94 var es = ename.split(".");
95 var gir = this.loadGir(ename);
96 return gir == null ? null : gir.classes.get(es[1]);
100 public GirObject? getDelegate(string ename)
102 var es = ename.split(".");
103 var gir = this.loadGir(ename);
104 return gir == null ? null : gir.delegates.get(es[1]);
107 public GirObject? getClassOrEnum(string ename)
109 var es = ename.split(".");
110 var gir = this.loadGir(ename);
111 return gir == null ? null :
112 (gir.classes.has_key(es[1]) ? gir.classes.get(es[1]) : gir.consts.get(es[1]) );
117 public override Gee.HashMap<string,GirObject> getPropertiesFor( string ename, JsRender.NodePropType ptype)
119 //print("Loading for " + ename);
123 // if (typeof(this.proplist[ename]) != 'undefined') {
124 //print("using cache");
125 // return this.proplist[ename][type];
127 // use introspection to get lists..
129 var es = ename.split(".");
130 var gir = Gir.factory(this.project,es[0]);
132 print("WARNING = could not load vapi for %s (%s)\n", ename , es[0]);
133 return new Gee.HashMap<string,GirObject>();
135 var cls = gir.classes.get(es[1]);
137 var ret = new Gee.HashMap<string,GirObject>();
139 //throw new Error.INVALID_VALUE( "Could not find class: " + ename);
144 //cls.parseSignals(); // ?? needed for add handler..
145 //cls.parseMethods(); // ?? needed for ??..
146 //cls.parseConstructors(); // ?? needed for ??..
148 cls.overlayParent(this.project);
151 case JsRender.NodePropType.PROP:
152 var ret = this.filterProps(cls.props);
154 this.add_props_from_ctors(cls, ret);
156 case JsRender.NodePropType.LISTENER:
157 return this.filterSignals(cls.signals);
158 case JsRender.NodePropType.METHOD:
160 case JsRender.NodePropType.CTOR: // needed to query the arguments of a ctor.
163 GLib.error( "getPropertiesFor called with: " + ptype.to_string());
164 //var ret = new Gee.HashMap<string,GirObject>();
170 //cls.overlayInterfaces(gir);
174 // get rid of objecst from props list..
175 public Gee.HashMap<string,GirObject> filterProps(Gee.HashMap<string,GirObject> props)
177 // we shold probably cache this??
179 var outprops = new Gee.HashMap<string,GirObject>();
181 foreach(var k in props.keys) {
182 var val = props.get(k);
183 // GLib.debug("FilterProp: %s", k);
184 // properties that dont make any sense to display.
188 k == "default_widget" ||
190 k == "layout_manager" || // ??
191 k == "widget" // gestures..
196 if (val.is_deprecated) {
199 if (!val.is_writable && !val.ctor_only ) { // if it's ctor we accept it.
203 if (val.type == "GLib.Object") { /// this is practually everything? ?? shoud we display it as a property?
206 if (!val.type.contains(".")) {
210 var cls = this.getClassOrEnum(val.type);
212 // if cls == null - it's probably a struct? I don't think we handle thses
213 if ( cls != null ) { // cls.nodetype == "Enum") {
218 // do nothing? - classes not allowed?
228 private void add_props_from_ctors(GirObject cls, Gee.HashMap<string,GirObject> props)
230 if (cls.ctors.has_key("new")) {
231 this.add_props_from_ctor(cls.ctors.get("new"), props);
234 // does not have new ?? needed?
235 foreach(var ctor in cls.ctors.values) {
236 this.add_props_from_ctor(ctor, props);
242 private void add_props_from_ctor(GirObject ctor, Gee.HashMap<string,GirObject> props)
244 var cname = ctor.gparent.fqn();
245 GLib.debug("Add node from ctor %s:%s", ctor.gparent.fqn(), ctor.name);
247 if (ctor.paramset == null) {
252 // assume we are calling this for a reason...
253 // get the first value params.
256 //GLib.debug("No. of parmas %s %d", cls, ctor.params.size);
258 foreach (var prop in ctor.paramset.params) {
261 if (props.has_key(prop.name)) { // overlap (we assume it's the same..)
264 prop.propertyof = cname + "." + ctor.name; // as it's probably not filled in..
266 GLib.debug("adding proprty from ctor : %s, %s, %s", cname , prop.name, prop.type);
268 props.set(prop.name, prop);
277 // get rid of depricated from signal list..
278 public Gee.HashMap<string,GirObject> filterSignals(Gee.HashMap<string,GirObject> props)
280 // we shold probably cache this??
282 var outprops = new Gee.HashMap<string,GirObject>();
284 foreach(var k in props.keys) {
285 var val = props.get(k);
287 if (val.is_deprecated) {
293 // do nothing? - classes not allowed?
303 public string[] getInheritsFor(string ename)
307 var cls = this.getClass(ename);
309 if (cls == null || cls.nodetype != "Class") {
310 print("getInheritsFor:could not find cls: %s\n", ename);
314 return cls.inheritsToStringArray();
318 Gee.HashMap<string,Gee.HashMap<string,JsRender.NodeProp>> node_defaults;
319 Gee.HashMap<string,Gee.ArrayList<JsRender.NodeProp>> child_defaults;
321 public void init_node_defaults()
323 this.node_defaults = new Gee.HashMap<string,Gee.HashMap<string,JsRender.NodeProp>>();
325 // this lot could probably be configured?
327 // does this need to add properties to methods?
328 // these are fake methods.
333 this.add_node_default("Gtk.ComboBox", "has_entry", "false");
334 this.add_node_default("Gtk.Expander", "label", "Label");
336 this.add_node_default("Gtk.Frame", "label", "Label");
338 this.add_node_default("Gtk.Grid", "columns", "2"); // special properties (is special as it's not part of the standard?!)
339 //this.add_node_default("Gtk.Grid", "rows", "2"); << this is not really that important..
341 this.add_node_default("Gtk.HeaderBar", "title", "Window Title");
342 this.add_node_default("Gtk.Label", "label", "Label"); // althought the ctor asks for string.. - we can use label after ctor.
344 this.add_node_default("Gtk.Scale", "orientation");
346 this.add_node_default("Gtk.ToggleButton", "label", "Label");
347 this.add_node_default("Gtk.MenuItem", "label", "Label");
348 this.add_node_default("Gtk.CheckItem", "label", "Label");
349 this.add_node_default("Gtk.RadioMenuItem", "label", "Label");
350 this.add_node_default("Gtk.TearoffMenuItem", "label", "Label");
352 // not sure how many of these 'attributes' there are - documenation is a bit thin on the ground
353 this.add_node_default("Gtk.CellRendererText", "markup_column", "-1");
354 this.add_node_default("Gtk.CellRendererText", "text_column","-1");
355 this.add_node_default("Gtk.CellRendererPixBuf", "pixbuf_column", "-1");
356 this.add_node_default("Gtk.CellRendererToggle", "active_column", "-1");
370 private void add_node_default_from_ctor_all()
373 var pr = (Project.Gtk) this.project;
377 foreach(var key in pr.gir_cache.keys) {
378 var gir = pr.gir_cache.get(key);
379 GLib.debug("building drop list for package %s", key);
380 this.add_node_default_from_ctor_package(gir.classes);
384 private void add_node_default_from_ctor_package(Gee.HashMap<string,GirObject> classes)
389 foreach(var cls in classes.values) {
390 GLib.debug("building drop list for class %s.%s", cls.package, cls.name);
391 this.add_node_default_from_ctor_classes(cls);
396 private void add_node_default_from_ctor_classes(GirObject cls)
398 if (cls.ctors.has_key("new")) {
399 this.add_node_default_from_ctor(cls.ctors.get("new"));
400 return; // and no more.
402 // does not have new ?? needed?
403 foreach(var ctor in cls.ctors.values) {
404 this.add_node_default_from_ctor(ctor);
415 private void add_node_default_from_ctor(GirObject ctor )
417 var cname = ctor.gparent.fqn();
418 GLib.debug("Add node from ctor %s:%s", ctor.gparent.fqn(), ctor.name);
419 if (!this.node_defaults.has_key(cname)) {
420 this.node_defaults.set(cname, new Gee.HashMap<string,JsRender.NodeProp>());
423 if (ctor.paramset == null) {
427 var defs= this.node_defaults.get(cname);
431 GLib.debug("ctor: %s: %s", cname , ctor.name);
434 // assume we are calling this for a reason...
435 // get the first value params.
438 //GLib.debug("No. of parmas %s %d", cls, ctor.params.size);
440 foreach (var prop in ctor.paramset.params) {
443 if (defs.has_key(prop.name)) {
446 var sub = this.getClass(prop.type);
448 // GLib.debug("adding property from ctor : %s, %s, %s [%s]", cname , prop.name, prop.type, sub == null ? "-" : sub.nodetype);
450 if (sub != null) { // can't add child classes here...
451 if (sub.nodetype == "Struct") {
452 this.node_defaults.get(cname).set(prop.name, new JsRender.NodeProp.raw(prop.name, prop.type, ""));
455 GLib.debug("skipping ctor argument proprty is an object");
459 sub = this.getDelegate(prop.type);
460 if (sub != null) { // can't add child classes here...
461 this.node_defaults.get(cname).set(prop.name, new JsRender.NodeProp.raw(prop.name, prop.type, sub.sig));
465 // FIXME!!! - what about functions
475 default: // enam? or bool?
476 this.typeOptions(cname, prop.name, prop.type, out opts);
477 dval = opts.length > 0 ? opts[0] : "";
481 this.node_defaults.get(cname).set(prop.name, new JsRender.NodeProp.prop( prop.name, prop.type, dval));
488 private void add_node_default(string cname, string propname, string val = "")
490 if (!this.node_defaults.has_key(cname)) {
491 var add = new Gee.HashMap<string, JsRender.NodeProp>();
492 this.node_defaults.set(cname, add);
495 var cls = this.getClass(cname);
497 GLib.debug("invalid class name %s", cname);
502 // liststore.columns - exists as a property but does not have a type (it's an array of typeofs()....
503 if (ar.has_key(propname) && ar.get(propname).type != "") { // must have type (otherwise special)
504 //GLib.debug("Class %s has property %s from %s - adding normal property", cls, propname, ar.get(propname).asJSONString());
505 var add = ar.get(propname).toNodeProp(this, cname); // our nodes dont have default values.
507 this.node_defaults.get(cname).set(propname, add);
511 //GLib.debug("Class %s has property %s - adding special property", cls, propname);
512 this.node_defaults.get(cname).set(propname,
513 new JsRender.NodeProp.special( propname, val)
520 private void init_child_defaults()
522 this.child_defaults = new Gee.HashMap<string,Gee.ArrayList<JsRender.NodeProp>>();
524 this.add_child_default("Gtk.Fixed", "x", "int", "0");
525 this.add_child_default("Gtk.Fixed", "y", "int", "0");
526 this.add_child_default("Gtk.Layout", "x", "int", "0");
527 this.add_child_default("Gtk.Layout", "y", "int", "0");
528 this.add_child_default("Gtk.Grid", "colspan", "int", "1");
529 //this.add_child_default("Gtk.Grid", "height", "int", "1");
530 this.add_child_default("Gtk.Stack", "stack_name", "string", "name");
531 this.add_child_default("Gtk.Stack", "stack_title", "string", "title");
535 private void add_child_default(string cls, string propname, string type, string val)
537 if (!this.child_defaults.has_key(cls)) {
538 this.child_defaults.set(cls, new Gee.ArrayList<JsRender.NodeProp>());
542 this.child_defaults.get(cls).add( new JsRender.NodeProp.prop(propname, type, val));
546 public Gee.ArrayList<string> packages(Project.Gtk gproject)
548 var vapidirs = gproject.vapidirs();
549 var ret = new Gee.ArrayList<string>();
550 ret.add_all(this.package_cache);
551 for(var i = 0; i < vapidirs.length;i++) {
552 var add = this.loadPackages(vapidirs[i]);
553 for (var j=0; j < add.size; j++) {
554 if (ret.contains(add.get(j))) {
564 // get a list of available vapi files...
566 public Gee.ArrayList<string> loadPackages(string dirname)
569 var ret = new Gee.ArrayList<string>();
570 //this.package_cache = new Gee.ArrayList<string>();
572 if (!GLib.FileUtils.test(dirname, FileTest.IS_DIR)) {
573 print("opps package directory %s does not exist", dirname);
577 var dir = File.new_for_path(dirname);
581 var file_enum = dir.enumerate_children(
582 GLib.FileAttribute.STANDARD_DISPLAY_NAME,
583 GLib.FileQueryInfoFlags.NONE,
589 while ((next_file = file_enum.next_file(null)) != null) {
590 var fn = next_file.get_display_name();
591 if (!Regex.match_simple("\\.vapi$", fn)) {
594 ret.add(Path.get_basename(fn).replace(".vapi", ""));
596 } catch(GLib.Error e) {
597 print("oops - something went wrong scanning the packages\n");
603 public override bool typeOptions(string fqn, string key, string type, out string[] opts)
606 if (type == "" ) { // empty type dont try and fill in options
609 GLib.debug("get typeOptions %s (%s)%s", fqn, type, key);
610 if (type.up() == "BOOL" || type.up() == "BOOLEAN") {
611 opts = { "true", "false" };
615 var gir= Gir.factoryFqn(this.project,type) ; // not get class as we are finding Enums.
617 GLib.debug("could not find Gir data for %s\n", key);
620 //print ("Got type %s", gir.asJSONString());
621 if (gir.nodetype != "Enum") {
625 var iter = gir.consts.map_iterator();
628 ret += (type + "." + iter.get_value().name);
631 if (ret.length > 0) {
644 void add_classes_from_method(GirObject cls, string method , Gee.ArrayList<string> ret)
647 //GLib.debug("add_classes_from_method %s, %s", cls.fqn(), method);
648 // does class have this method?
649 if (!cls.methods.has_key(method)) {
650 GLib.debug("skip %s does not have method %s", cls.fqn(), method);
653 // add all the possible classes to ret based on first arguemnt?
654 var m = cls.methods.get(method);
656 if (m.paramset.params.size < 1) {
657 GLib.debug("%s: %s does not have any params?", cls.fqn(), method);
663 var ty = m.paramset.params.get(0).type;
664 GLib.debug("add %s method %s arg0 = %s", cls.fqn(), method, ty);
665 this.addRealClasses(ret, ty);
666 // skip dupe // skip depricated
667 // skip not object // skip GLib.Object (base)
670 //if (cls.fqn() == "GLib.Menu" && method == "append_submenu") {
671 // ty = m.paramset.params.get(1).type;
672 // GLib.debug("add %s method %s arg1 = %s", cls.fqn(), method, ty);
673 // this.addRealClasses(ret, ty);
678 void addRealClasses(Gee.ArrayList<string> ret, string cn, bool allow_root = false)
680 if (!cn.contains(".")) {
684 var w = this.getClass(cn);
689 if (w.nodetype != "Class" && w.nodetype != "Interface" ) {
692 if (ret.contains(cn)) {
696 if (!allow_root && w.implements.contains("Gtk.Native")) { // removes popover + window
700 if (!w.is_deprecated && !w.is_abstract && w.nodetype == "Class" ) {
707 foreach (var str in w.implementations) {
708 var c = this.getClass(str);
709 if (c.is_deprecated || c.is_abstract) {
712 if (ret.contains(str)) {
715 if (!allow_root && c.implements.contains("Gtk.Native")) { // removes popover + window
727 this is the real list of objects that appear in the add object pulldown
728 @param in_rval "*top" || "Gtk.Widget"
731 public override Gee.ArrayList<string> getChildList(string in_rval, bool with_props)
734 GLib.debug("getChildList %s %s", in_rval, with_props ? "(with props)" : "");
736 //return this.original_getChildList( in_rval, with_props);
737 var pr = (Project.Gtk) this.project;
738 if (with_props && pr.child_list_cache_props.has_key(in_rval)) {
739 return pr.child_list_cache_props.get(in_rval);
741 if (!with_props && pr.child_list_cache.has_key(in_rval)) {
742 return pr.child_list_cache.get(in_rval);
746 var ret = new Gee.ArrayList<string>();
748 if (in_rval == "*top") {
749 // everythign that's not depricated and extends Gtk.Widget
750 // even a gtk window and about dialog are widgets
751 this.addRealClasses(ret, "Gtk.Widget", true);
758 var cls = this.getClass(in_rval);
760 GLib.debug("could not get class for %s", in_rval);
764 // look through methods of in_rval
767 this.add_classes_from_method(cls, "add_controller", ret);
768 this.add_classes_from_method(cls, "add_shortcut", ret);
769 this.add_classes_from_method(cls, "add_tick_callback", ret); // wtf does this do.
770 this.add_classes_from_method(cls, "append", ret);
771 this.add_classes_from_method(cls, "append_column", ret); // columnview column
772 this.add_classes_from_method(cls, "append_item", ret); // GLib.Menu
773 //this.add_classes_from_method(cls, "append_submenu", ret); // GLib.Menu - complicated to support
774 this.add_classes_from_method(cls, "attach", ret); // grid column
775 this.add_classes_from_method(cls, "pack_start", ret); // headerbar (also has pack end?)
777 // add_controller 1st arge = ??
778 // add_menomic_label ??? << no ???
780 // add_tick_callback ?
781 // append << core one to add stuff..
785 pr.child_list_cache.set(in_rval, ret);
788 foreach(var pn in cls.props.values) {
790 if (!pn.is_writable ) {
791 GLib.debug("Skip (not write) %s : (%s) %s", cls.fqn(), pn.type , pn.name);
794 // if (&& !pn.ctor_only << we add these?
795 // are they really available ?
796 GLib.debug("Add %s : (%s) %s", cls.fqn(), pn.type , pn.name);
797 this.addRealClasses(ret, pn.type);
800 pr.child_list_cache_props.set(in_rval, ret);
807 public void buildChildListForDroppingProject()
811 var pr = (Project.Gtk) this.project;
813 if (pr.dropList != null) {
814 GLib.debug("Drop list alreayd loaded");
818 pr.dropList = new Gee.HashMap<string,Gee.ArrayList<string>>();
819 foreach(var key in pr.gir_cache.keys) {
820 var gir = pr.gir_cache.get(key);
821 GLib.debug("building drop list for package %s", key);
822 this.buildChildListForDropping(key, gir.classes);
826 public void buildChildListForDropping(string pkg, Gee.HashMap<string,GirObject> classes)
831 foreach(var cls in classes.keys) {
832 GLib.debug("building drop list for class %s.%s", pkg, cls);
833 this.buildDropList(pkg + "." + cls, this.getChildList(pkg + "." + cls, true));
835 this.buildDropList("*top", this.getChildList("*top", true));
840 public void buildDropList(string parent, Gee.ArrayList<string> children)
843 var pr = (Project.Gtk) this.project;
844 foreach(var c in children) {
845 if (!pr.dropList.has_key(c)) {
847 pr.dropList.set(c, new Gee.ArrayList<string>());
849 var dl = pr.dropList.get(c);
850 if (dl.contains(parent)) {
853 GLib.debug("%s[] = %s", c, parent);
860 public override Gee.ArrayList<string> getDropList(string rval)
862 this.buildChildListForDroppingProject();
863 var pr = (Project.Gtk) this.project;
864 if (!pr.dropList.has_key(rval)) {
865 GLib.debug("returning empty drop list for %s", rval);
866 return new Gee.ArrayList<string>();
868 GLib.debug("returning %d items in drop list %s", pr.dropList.get(rval).size, rval);
869 return pr.dropList.get(rval);
875 public override JsRender.Node fqnToNode(string fqn)
878 var ret = new JsRender.Node();
880 if (!this.node_defaults.has_key(fqn)) {
884 foreach (var nv in this.node_defaults.get(fqn).values) {
885 ret.add_prop(nv.dupe());