[gxml] Gom-collections: moved to its own file
- From: Daniel Espinosa Ortiz <despinosa src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gxml] Gom-collections: moved to its own file
- Date: Wed, 20 Mar 2019 16:53:03 +0000 (UTC)
commit f2cfaab6ce3ef9e38b115de876471d39cfe11120
Author: Daniel Espinosa <esodan gmail com>
Date: Tue Mar 19 13:20:44 2019 -0600
Gom-collections: moved to its own file
gxml/GomArrayList.vala | 54 +++
gxml/GomBaseCollection.vala | 223 +++++++++++
gxml/GomCollections.vala | 906 --------------------------------------------
gxml/GomHashMap.vala | 172 +++++++++
gxml/GomHashPairedMap.vala | 243 ++++++++++++
gxml/GomHashThreeMap.vala | 313 +++++++++++++++
gxml/meson.build | 8 +-
test/GomElementTest.vala | 1 -
8 files changed, 1011 insertions(+), 909 deletions(-)
---
diff --git a/gxml/GomArrayList.vala b/gxml/GomArrayList.vala
new file mode 100644
index 0000000..80f0d1c
--- /dev/null
+++ b/gxml/GomArrayList.vala
@@ -0,0 +1,54 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * GomArrayList.vala
+ *
+ * Copyright (C) 2016 Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Daniel Espinosa <esodan gmail com>
+ */
+
+using Gee;
+
+/**
+ * A class impementing {@link Collection} to store references to
+ * child {@link DomElement} of {@link Collection.element}, using an index.
+ *
+ * {{{
+ * public class YourObject : GomElement {
+ * [Description (nick="::Name")]
+ * public string name { get; set; }
+ * }
+ * public class YourList : GomArrayList {
+ * construct {
+ * try { initialize (typeof (YourObject)); }
+ * catch (GLib.Error e) {
+ * warning ("Initialization error for collection type: %s : %s"
+ * .printf (get_type ().name(), e.message));
+ * }
+ * }
+ * }
+ * }}}
+ */
+public class GXml.GomArrayList : GXml.BaseCollection, GXml.List {
+ public override bool validate_append (int index, DomElement element) throws GLib.Error {
+#if DEBUG
+ GLib.message ("Adding node:"+element.node_name);
+#endif
+ return true;
+ }
+}
+
diff --git a/gxml/GomBaseCollection.vala b/gxml/GomBaseCollection.vala
new file mode 100644
index 0000000..f5557ba
--- /dev/null
+++ b/gxml/GomBaseCollection.vala
@@ -0,0 +1,223 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/* GomBaseCollection.vala
+ *
+ * Copyright (C) 2016 Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Daniel Espinosa <esodan gmail com>
+ */
+
+using Gee;
+
+/**
+ * Base class for collections implemeting {@link Collection}, priving basic
+ * infrastructure.
+ *
+ * Collections properties should be initialized with current container element
+ * in order to be able to add new references to elements. Use {@link initialize_element}
+ * to set parent element and {@link search} to find elements for collection.
+ */
+public abstract class GXml.BaseCollection : Object, Traversable<DomElement>, Iterable<DomElement>,
Collection {
+ /**
+ * A collection of node's index refered. Don't modify it manually.
+ */
+ protected GLib.Queue<int> _nodes_index = new GLib.Queue<int> ();
+ /**
+ * Element used to refer of containier element. You should define it at construction time
+ * our set it as a construction property.
+ */
+ protected GomElement _element;
+ /**
+ * Local name of {@link DomElement} objects of {@link element}, which could be
+ * contained in this collection.
+ *
+ * Used when reading to add elements to collection. You can set it at construction time,
+ * by, for example, instantaiting a object of the type {@link Collection.items_type}
+ * then use {@link GomElement.local_name}'s value.
+ */
+ protected string _items_name = "";
+ /**
+ * Objects' type to be referenced by this collection and to deserialize objects.
+ * Derived classes, can initilize this value at constructor or as construct property.
+ *
+ * Used when reading and at initialization time, to know {@link GomElement.local_name}
+ * at runtime.
+ */
+ protected GLib.Type _items_type = GLib.Type.INVALID;
+ /**
+ * {@inheritDoc}
+ */
+ public string items_name { get { return _items_name; } }
+ /**
+ * {@inheritDoc}
+ */
+ public Type items_type {
+ get { return _items_type; } construct set { _items_type = value; }
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public GLib.Queue<int> nodes_index { get { return _nodes_index; } }
+ /**
+ * {@inheritDoc}
+ */
+ public DomElement element {
+ get { return _element as DomElement; }
+ construct set {
+ if (value is GomElement)
+ _element = value as GomElement;
+ }
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public void initialize (GLib.Type items_type) throws GLib.Error {
+ if (!items_type.is_a (typeof (GomElement))) {
+ throw new DomError.INVALID_NODE_TYPE_ERROR
+ (_("Invalid attempt to initialize a collection using an unsupported type. Only
GXmlGomElement is supported"));
+ }
+ var o = Object.new (items_type) as GomElement;
+ _items_name = o.local_name;
+ _items_type = items_type;
+ }
+ /**
+ * Initialize an {@link Collection} to use an element as children's parent.
+ * Searchs for all nodes, calling {@link Collection.search}
+ * with {@link Collection.items_type}, using its
+ * {@link DomElement.local_name} to find it.
+ *
+ * Implemenation classes, should initialize collection to hold a {@link GomElement}
+ * derived type using {@link Collection.initialize}.
+ */
+ public void initialize_element (GomElement e) throws GLib.Error {
+ _element = e;
+ }
+
+ /**
+ * Adds an {@link DomElement} of type {@link GomObject} as a child of
+ * {@link element}.
+ *
+ * Object is always added as a child of {@link element}
+ * but just added to collection if {@link validate_append} returns true;
+ */
+ public void append (DomElement node) throws GLib.Error {
+ if (_element == null)
+ throw new DomError.INVALID_NODE_TYPE_ERROR
+ (_("Parent Element is invalid"));
+ if (!(node is GomElement))
+ throw new DomError.INVALID_NODE_TYPE_ERROR
+ (_("Invalid attempt to set unsupported type. Only GXmlGomElement is supported"));
+ if (node.owner_document != _element.owner_document)
+ throw new DomError.HIERARCHY_REQUEST_ERROR
+ (_("Invalid attempt to set a node with a different parent document"));
+ if (node.parent_node == null)
+ _element.append_child (node);
+ if (_element.child_nodes.size == 0)
+ throw new DomError.QUOTA_EXCEEDED_ERROR
+ (_("Node element not appended as child of parent. No node added to collection"));
+ var index = _element.child_nodes.size - 1;
+ if (!validate_append (index, node)) return;
+ _nodes_index.push_tail (index);
+ }
+ /**
+ * Search for all child nodes in {@link element} of type {@link GomElement}
+ * with a {@link GomElement.local_name} equal to {@link Collection.items_name},
+ * to add it to collection. This method calls {@link clear} first.
+ *
+ * Implementations could add additional restrictions to add element to collection.
+ */
+ public void search () throws GLib.Error {
+ _nodes_index.clear ();
+ clear ();
+ if (_element == null)
+ throw new DomError.INVALID_NODE_TYPE_ERROR
+ (_("Parent Element is invalid"));
+ for (int i = 0; i < _element.child_nodes.size; i++) {
+ var n = _element.child_nodes.get (i);
+ if (n is GomObject) {
+ if ((n as DomElement).local_name.down () == items_name.down ()) {
+ if (validate_append (i, n as DomElement))
+ _nodes_index.push_tail (i);
+ }
+ }
+ }
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool validate_append (int index, DomElement element) throws GLib.Error;
+ /**
+ * {@inheritDoc}
+ */
+ public virtual void clear () throws GLib.Error {}
+
+ // Traversable Interface
+ public bool @foreach (ForallFunc<DomElement> f) {
+ var i = iterator ();
+ return i.foreach (f);
+ }
+ // Itarable Interface
+ public Iterator<DomElement> iterator () { return new CollectionIterator (this); }
+ // For Iterable interface implementation
+ private class CollectionIterator : Object, Traversable<DomElement>, Iterator<DomElement> {
+ private int pos;
+ private Collection _collection;
+ public bool read_only { get { return false; } }
+ public bool valid { get { return (pos >= 0 && pos < _collection.length); } }
+
+ public CollectionIterator (Collection col) {
+ _collection = col;
+ pos = -1;
+ }
+
+ public new DomElement @get ()
+ requires (pos >= 0 && pos < _collection.length) {
+ DomElement e = null;
+ try {
+ e = _collection.get_item (pos);
+ } catch (GLib.Error e) {
+ warning (_("Error: %s").printf (e.message));
+ }
+ return e;
+ }
+ public bool has_next () { return (pos + 1 < _collection.length); }
+ public bool next () {
+ if (!has_next ()) return false;
+ pos++;
+ return true;
+ }
+ public void remove () {
+ DomElement e = null;
+ try {
+ e = _collection.get_item (pos);
+ if (e == null) return;
+ e.remove ();
+ _collection.search ();
+ } catch (GLib.Error e) {
+ warning (_("Error: %s").printf (e.message));
+ }
+ }
+
+ public bool @foreach (ForallFunc<DomElement> f) {
+ while (has_next ()) {
+ next ();
+ if (!f (get ())) return false;
+ }
+ return true;
+ }
+ }
+}
+
diff --git a/gxml/GomHashMap.vala b/gxml/GomHashMap.vala
new file mode 100644
index 0000000..6da2a4c
--- /dev/null
+++ b/gxml/GomHashMap.vala
@@ -0,0 +1,172 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * GomHashMap.vala
+ *
+ * Copyright (C) 2016 Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Daniel Espinosa <esodan gmail com>
+ */
+
+using Gee;
+
+/**
+ * A class impementing {@link Collection} to store references to
+ * child {@link DomElement} of {@link Collection.element}, using an attribute in
+ * items as key or {@link MappeableElement.get_map_key} method if implemented
+ * by items to be added. If key is not defined in node, it is not added; but
+ * keeps it as a child node of actual {@link Collection.element}.
+ *
+ * If {@link GomElement} to be added is of type {@link Collection.items_type}
+ * and implements {@link MappeableElement}, you should set {@link GomHashMap.attribute_key}
+ * to null in order to use returned value of {@link MappeableElement.get_map_key}
+ * as key.
+ *
+ * {{{
+ * public class YourObject : GomElement {
+ * [Description (nick="::Name")]
+ * public string name { get; set; }
+ * }
+ * public class YourList : GomHashMap {
+ * construct {
+ * try { initialize_with_key (typeof (YourObject),"Name"); }
+ * catch (GLib.Error e) {
+ * warning ("Initialization error for collection type: %s : %s"
+ * .printf (get_type ().name(), e.message));
+ * }
+ * }
+ * }
+ * }}}
+ */
+public class GXml.GomHashMap : GXml.BaseCollection, GXml.Map {
+ /**
+ * A hashtable with all keys as string to node's index refered. Don't modify it manually.
+ */
+ protected Gee.HashMap<string,int> _hashtable = new Gee.HashMap<string,int> ();
+ /**
+ * Element's attribute name used to refer of container's element.
+ * You should define it at construction time
+ * our set it as a construction property.
+ */
+ protected string _attribute_key;
+ /**
+ * An attribute's name in items to be added and used to retrieve elements
+ * as key.
+ */
+ public string attribute_key {
+ get { return _attribute_key; } construct set { _attribute_key = value; }
+ }
+ /**
+ * Convenient function to initialize a {@link GomHashMap} collection, using
+ * given element, items' type and name.
+ */
+ public void initialize_element_with_key (GomElement element,
+ GLib.Type items_type,
+ string attribute_key) throws GLib.Error
+ {
+ initialize (items_type);
+ initialize_element (element);
+ _attribute_key = attribute_key;
+ }
+
+ /**
+ * Convenient function to initialize a {@link GomHashMap} collection, using
+ * given element, items' type and name.
+ *
+ * Using this method at construction time of derived classes.
+ */
+ public void initialize_with_key (GLib.Type items_type,
+ string attribute_key) throws GLib.Error
+ {
+ initialize (items_type);
+ _attribute_key = attribute_key;
+ }
+ /**
+ * Returns an {@link DomElement} in the collection using a string key.
+ */
+ public new DomElement? get (string key) {
+ if (!_hashtable.has_key (key)) return null;
+ var i = _hashtable.get (key);
+#if DEBUG
+ GLib.message ("Key:"+key+" item:"+i.to_string ());
+#endif
+ return _element.child_nodes.get (i) as DomElement;
+ }
+ /**
+ * Returns true if @key is used in collection.
+ */
+ public bool has_key (string key) {
+ if (_hashtable.has_key (key)) return true;
+ return false;
+ }
+ /**
+ * Returns list of keys used in collection.
+ */
+ public GLib.List<string> get_keys () {
+ var l = new GLib.List<string> ();
+ foreach (string k in _hashtable.keys) { l.append (k); }
+ return l;
+ }
+ /**
+ * Validates if given element has a {@link GomHashMap.attribute_key} set,
+ * if so adds a new key pointing to given index and returns true.
+ *
+ * Attribute should be a valid {@link DomElement} attribute or
+ * a {@link GomObject} property identified using a nick with a '::' prefix.
+ *
+ * If there are more elements with same key, they are kept as child nodes
+ * but the one in collection will be the last one to be found.
+ *
+ * Return: false if element should not be added to collection.
+ */
+ public override bool validate_append (int index, DomElement element) throws GLib.Error {
+ if (!(element is GomElement)) return false;
+#if DEBUG
+ message ("Validating HashMap Element..."
+ +(element as GomElement).write_string ()
+ +" Attrs:"+(element as GomElement).attributes.length.to_string());
+#endif
+ string key = null;
+ if (attribute_key != null) {
+ key = (element as DomElement).get_attribute (attribute_key);
+ if (key == null)
+ key = (element as DomElement).get_attribute (attribute_key.down ());
+ } else {
+ if (items_type.is_a (typeof(MappeableElement))) {
+ if (!(element is MappeableElement)) return false;
+ key = ((MappeableElement) element).get_map_key ();
+ }
+ }
+ if (key == null) return false;
+#if DEBUG
+ message ("Attribute key value: "+key);
+#endif
+ _hashtable.set (key, index);
+ return true;
+ }
+ public override void clear () {
+ _hashtable = new HashMap<string,int> ();
+ }
+ public DomElement? item (string key) { return get (key); }
+ public Gee.Set<string> keys_set {
+ owned get {
+ var l = new HashSet<string> ();
+ foreach (string k in _hashtable.keys) { l.add (k); }
+ return l;
+ }
+ }
+}
+
diff --git a/gxml/GomHashPairedMap.vala b/gxml/GomHashPairedMap.vala
new file mode 100644
index 0000000..7161ed9
--- /dev/null
+++ b/gxml/GomHashPairedMap.vala
@@ -0,0 +1,243 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * GomHashPairedMap.vala
+ *
+ * Copyright (C) 2016 Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Daniel Espinosa <esodan gmail com>
+ */
+
+using Gee;
+
+/**
+ * A class impementing {@link Collection} to store references to
+ * child {@link DomElement} of {@link Collection.element}, using two attributes in
+ * items as primary and secondary keys or {@link MappeableElementPairKey.get_map_primary_key}
+ * and {@link MappeableElementPairKey.get_map_secondary_key} methods if
+ * {@link MappeableElementPairKey} are implemented
+ * by items to be added. If one or both keys are not defined in node,
+ * it is not added; but keeps it as a child node of actual
+ * {@link Collection.element}.
+ *
+ * If {@link GomElement} to be added is of type {@link Collection.items_type}
+ * and implements {@link MappeableElementPairKey}, you should set
+ * {@link attribute_primary_key} and {@link attribute_secondary_key}
+ * to null in order to use returned value of {@link MappeableElementPairKey.get_map_primary_key}
+ * and {@link MappeableElementPairKey.get_map_secondary_key}
+ * as keys.
+ *
+ * {{{
+ * public class YourObject : GomElement, MappeableElementPairKey {
+ * [Description (nick="::Name")]
+ * public string name { get; set; }
+ * public string code { get; set; }
+ * public string get_map_primary_key () { return code; }
+ * public string get_map_secondary_key () { return name; }
+ * }
+ * public class YourList : GomHashPairedMap {
+ * construct {
+ * try { initialize_with (typeof (YourObject)); }
+ * catch (GLib.Error e) {
+ * warning ("Initialization error for collection type: %s : %s"
+ * .printf (get_type ().name(), e.message));
+ * }
+ * }
+ * }
+ * }}}
+ */
+public class GXml.GomHashPairedMap : GXml.BaseCollection, GXml.PairedMap {
+ /**
+ * A hashtable with all keys as string to node's index refered. Don't modify it manually.
+ */
+ protected Gee.HashMap<string,HashMap<string,int>> _hashtable = new HashMap<string,HashMap<string,int>> ();
+ /**
+ * Element's attribute name used to refer of container's element as primery key.
+ * You should define it at construction time
+ * our set it as a construction property.
+ */
+ protected string _attribute_primary_key;
+ /**
+ * Element's attribute name used to refer of container's element as secondary key.
+ * You should define it at construction time
+ * our set it as a construction property.
+ */
+ protected string _attribute_secondary_key;
+ /**
+ * An attribute's name in items to be added and used to retrieve elements
+ * as primary key.
+ */
+ public string attribute_primary_key {
+ get { return _attribute_primary_key; } construct set { _attribute_primary_key = value; }
+ }
+ /**
+ * An attribute's name in items to be added and used to retrieve elements
+ * as secondary key.
+ */
+ public string attribute_secondary_key {
+ get { return _attribute_secondary_key; } construct set { _attribute_secondary_key = value; }
+ }
+ /**
+ * Convenient function to initialize a {@link GomHashMap} collection, using
+ * given element, items' type and name.
+ */
+ public void initialize_element_with_keys (GomElement element,
+ GLib.Type items_type,
+ string attribute_primary_key,
+ string attribute_secondary_key) throws GLib.Error
+ {
+ initialize (items_type);
+ initialize_element (element);
+ _attribute_primary_key = attribute_primary_key;
+ _attribute_secondary_key = attribute_secondary_key;
+ }
+
+ /**
+ * Convenient function to initialize a {@link GomHashMap} collection, using
+ * given element, items' type and name.
+ *
+ * Using this method at construction time of derived classes.
+ */
+ public void initialize_with_keys (GLib.Type items_type,
+ string attribute_primary_key,
+ string attribute_secondary_key) throws GLib.Error
+ {
+ initialize (items_type);
+ _attribute_primary_key = attribute_primary_key;
+ _attribute_secondary_key = attribute_secondary_key;
+ }
+ /**
+ * Returns an {@link DomElement} in the collection using given string keys.
+ */
+ public new DomElement? get (string primary_key, string secondary_key) {
+ if (!_hashtable.has_key (primary_key)) return null;
+ var ht = _hashtable.get (primary_key);
+ if (ht == null) return null;
+ if (!ht.has_key (secondary_key)) return null;
+ var i = ht.get (secondary_key);
+ return _element.child_nodes.get (i) as DomElement;
+ }
+ /**
+ * Returns true if @key is used in collection as primery key.
+ */
+ public bool has_primary_key (string key) {
+ if (_hashtable.has_key (key)) return true;
+ return false;
+ }
+ /**
+ * Returns true if @key is used in collection as secondary key
+ * with @pkey as primary.
+ */
+ public bool has_secondary_key (string pkey, string key) {
+ if (!(_hashtable.has_key (pkey))) return false;
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return false;
+ if (ht.has_key (key)) return true;
+ return false;
+ }
+ /**
+ * Returns list of primary keys used in collection.
+ */
+ public GLib.List<string> get_primary_keys () {
+ var l = new GLib.List<string> ();
+ foreach (string k in _hashtable.keys) {
+ l.append (k);
+ }
+ return l;
+ }
+ /**
+ * Returns list of secondary keys used in collection with @pkey as primary key.
+ */
+ public GLib.List<string> get_secondary_keys (string pkey) {
+ var l = new GLib.List<string> ();
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return l;
+ foreach (string k in ht.keys) {
+ l.append (k);
+ }
+ return l;
+ }
+ /**
+ * Validates if given element has a {@link attribute_primary_key}
+ * and {@link attribute_secondary_key} set,
+ * if so adds a new keys pointing to given index and returns true.
+ *
+ * Attribute should be a valid {@link DomElement} attribute or
+ * a {@link GomObject} property identified using a nick with a '::' prefix.
+ *
+ * If there are more elements with same keys, they are kept as child nodes
+ * but the one in collection will be the last one to be found.
+ *
+ * Return: false if element should not be added to collection.
+ */
+ public override bool validate_append (int index, DomElement element) throws GLib.Error {
+ if (!(element is GomElement)) return false;
+#if DEBUG
+ message ("Validating HashMap Element..."
+ +(element as GomElement).write_string ()
+ +" Attrs:"+(element as GomElement).attributes.length.to_string());
+#endif
+ string pkey = null;
+ string skey = null;
+ if (attribute_primary_key != null && attribute_secondary_key != null) {
+ pkey = (element as DomElement).get_attribute (attribute_primary_key);
+ skey = (element as DomElement).get_attribute (attribute_secondary_key);
+ if (pkey == null || skey == null) {
+ pkey = (element as DomElement).get_attribute (attribute_primary_key.down ());
+ skey = (element as DomElement).get_attribute (attribute_secondary_key.down ());
+ }
+ } else {
+ if (items_type.is_a (typeof(MappeableElementPairKey))) {
+ if (!(element is MappeableElementPairKey)) return false;
+ pkey = ((MappeableElementPairKey) element).get_map_primary_key ();
+ skey = ((MappeableElementPairKey) element).get_map_secondary_key ();
+ }
+ }
+ if (pkey == null || skey == null)
+ throw new DomError.NOT_FOUND_ERROR (_("No primary key and/or secondary key was found"));
+ var ht = _hashtable.get (pkey);
+ if (ht == null) {
+ ht = new HashMap<string,int> ();
+ _hashtable.set (pkey, ht);
+ }
+ ht.set (skey, index);
+ return true;
+ }
+ public override void clear () {
+ _hashtable = new HashMap<string,HashMap<string,int>> ();
+ }
+ public DomElement? item (string primary_key, string secondary_key) {
+ return get (primary_key, secondary_key);
+ }
+ public Set<string> primary_keys_set {
+ owned get {
+ var l = new HashSet<string> ();
+ foreach (string k in _hashtable.keys) {
+ l.add (k);
+ }
+ return l;
+ }
+ }
+ public Set<string> secondary_keys_set (string pkey) {
+ var l = new HashSet<string> ();
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return l;
+ foreach (string k in ht.keys) {
+ l.add (k);
+ }
+ return l;
+ }
+}
diff --git a/gxml/GomHashThreeMap.vala b/gxml/GomHashThreeMap.vala
new file mode 100644
index 0000000..f836d69
--- /dev/null
+++ b/gxml/GomHashThreeMap.vala
@@ -0,0 +1,313 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * GomHashThreeMap.vala
+ *
+ * Copyright (C) 2016 Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Daniel Espinosa <esodan gmail com>
+ */
+
+using Gee;
+
+/**
+ * A class impementing {@link Collection} to store references to
+ * child {@link DomElement} of {@link Collection.element}, using three attributes in
+ * items as primary, secondary tertiary keys or {@link MappeableElementThreeKey.get_map_pkey},
+ * {@link MappeableElementThreeKey.get_map_skey}
+ * and {@link MappeableElementThreeKey.get_map_tkey}
+ * methods if {@link MappeableElementThreeKey} are implemented
+ * by items to be added. All keys should be defined in node, otherwise
+ * it is not added; but keeps it as a child node of actual
+ * {@link Collection.element}.
+ *
+ * If {@link GomElement} to be added is of type {@link Collection.items_type}
+ * and implements {@link MappeableElementThreeKey}, you should set
+ * {@link attribute_primary_key}, {@link attribute_secondary_key}
+ * and {@link attribute_third_key}
+ * to null in order to use returned value of {@link MappeableElementThreeKey.get_map_pkey},
+ * {@link MappeableElementThreeKey.get_map_skey}
+ * and {@link MappeableElementThreeKey.get_map_tkey}
+ * as keys.
+ *
+ * {{{
+ * public class YourObject : GomElement, MappeableElementThirdKey {
+ * [Description (nick="::Name")]
+ * public string name { get; set; }
+ * public string code { get; set; }
+ * public string category { get; set; }
+ * public string get_map_primary_key () { return code; }
+ * public string get_map_secondary_key () { return name; }
+ * public string get_map_third_key () { return category; }
+ * }
+ * public class YourList : GomHashPairedMap {
+ * construct {
+ * try { initialize_with (typeof (YourObject)); }
+ * catch (GLib.Error e) {
+ * warning ("Initialization error for collection type: %s : %s"
+ * .printf (get_type ().name(), e.message));
+ * }
+ * }
+ * }
+ * }}}
+ */
+public class GXml.GomHashThreeMap : GXml.BaseCollection, ThreeMap {
+ /**
+ * A hashtable with all keys as string to node's index refered. Don't modify it manually.
+ */
+ protected HashMap<string,HashMap<string,HashMap<string,int>>> _hashtable = new
HashMap<string,HashMap<string,HashMap<string,int>>> ();
+ /**
+ * Element's attribute name used to refer of container's element as primery key.
+ * You should define it at construction time
+ * our set it as a construction property.
+ */
+ protected string _attribute_primary_key;
+ /**
+ * Element's attribute name used to refer of container's element as secondary key.
+ * You should define it at construction time
+ * our set it as a construction property.
+ */
+ protected string _attribute_secondary_key;
+ /**
+ * Element's attribute name used to refer of container's element as third key.
+ * You should define it at construction time
+ * our set it as a construction property.
+ */
+ protected string _attribute_third_key;
+ /**
+ * An attribute's name in items to be added and used to retrieve elements
+ * as primary key.
+ */
+ public string attribute_primary_key {
+ get { return _attribute_primary_key; } construct set { _attribute_primary_key = value; }
+ }
+ /**
+ * An attribute's name in items to be added and used to retrieve elements
+ * as secondary key.
+ */
+ public string attribute_secondary_key {
+ get { return _attribute_secondary_key; } construct set { _attribute_secondary_key = value; }
+ }
+ /**
+ * An attribute's name in items to be added and used to retrieve elements
+ * as third key.
+ */
+ public string attribute_third_key {
+ get { return _attribute_third_key; } construct set { _attribute_third_key = value; }
+ }
+ /**
+ * Convenient function to initialize a {@link GomHashMap} collection, using
+ * given element, items' type and name.
+ */
+ public void initialize_element_with_keys (GomElement element,
+ GLib.Type items_type,
+ string attribute_primary_key,
+ string attribute_secondary_key,
+ string attribute_third_key) throws GLib.Error
+ {
+ initialize (items_type);
+ initialize_element (element);
+ _attribute_primary_key = attribute_primary_key;
+ _attribute_secondary_key = attribute_secondary_key;
+ _attribute_third_key = attribute_third_key;
+ }
+
+ /**
+ * Convenient function to initialize a {@link GomHashMap} collection, using
+ * given element, items' type and name.
+ *
+ * Using this method at construction time of derived classes.
+ */
+ public void initialize_with_keys (GLib.Type items_type,
+ string attribute_primary_key,
+ string attribute_secondary_key,
+ string attribute_third_key) throws GLib.Error
+ {
+ initialize (items_type);
+ _attribute_primary_key = attribute_primary_key;
+ _attribute_secondary_key = attribute_secondary_key;
+ _attribute_third_key = attribute_third_key;
+ }
+ /**
+ * Returns an {@link DomElement} in the collection using given string keys.
+ */
+ public new DomElement? get (string primary_key, string secondary_key, string third_key) {
+ if (!_hashtable.has_key (primary_key)) return null;
+ var ht = _hashtable.get (primary_key);
+ if (ht == null) return null;
+ if (!ht.has_key (secondary_key)) return null;
+ var hte = ht.get (secondary_key);
+ if (hte == null) return null;
+ if (!hte.has_key (third_key)) return null;
+ var i = hte.get (secondary_key);
+ return _element.child_nodes.get (i) as DomElement;
+ }
+ /**
+ * Returns true if @key is used in collection as primery key.
+ */
+ public bool has_primary_key (string key) {
+ if (_hashtable.has_key (key)) return true;
+ return false;
+ }
+ /**
+ * Returns true if @key is used in collection as secondary key
+ * with @pkey as primary.
+ */
+ public bool has_secondary_key (string pkey, string key) {
+ if (!(_hashtable.has_key (pkey))) return false;
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return false;
+ if (ht.has_key (key)) return true;
+ return false;
+ }
+ /**
+ * Returns true if @key is used in collection as third key with secondary key
+ * and pkey as primary.
+ */
+ public bool has_third_key (string pkey, string skey, string key) {
+ if (!(_hashtable.has_key (pkey))) return false;
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return false;
+ var hte = ht.get (skey);
+ if (hte == null) return false;
+ if (hte.has_key (key)) return true;
+ return false;
+ }
+ /**
+ * Returns list of primary keys used in collection.
+ */
+ public GLib.List<string> get_primary_keys () {
+ var l = new GLib.List<string> ();
+ foreach (string k in _hashtable.keys) {
+ l.append (k);
+ }
+ return l;
+ }
+ /**
+ * Returns list of secondary keys used in collection with pkey as primary key.
+ */
+ public GLib.List<string> get_secondary_keys (string pkey) {
+ var l = new GLib.List<string> ();
+ if (!_hashtable.has_key (pkey)) return l;
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return l;
+ foreach (string k in ht.keys) {
+ l.append (k);
+ }
+ return l;
+ }
+ /**
+ * Returns list of third keys used in collection with pkey as primary key
+ * and skey as secondary key.
+ */
+ public GLib.List<string> get_third_keys (string pkey, string skey) {
+ var l = new GLib.List<string> ();
+ if (!_hashtable.has_key (pkey)) return l;
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return l;
+ var hte = ht.get (skey);
+ if (hte == null) return l;
+ foreach (string k in hte.keys) {
+ l.append (k);
+ }
+ return l;
+ }
+ /**
+ * Validates if given element has a {@link attribute_primary_key},
+ * {@link attribute_secondary_key} and
+ * {@link attribute_third_key} set,
+ * if so adds a new keys pointing to given index and returns true.
+ *
+ * Attribute should be a valid {@link DomElement} attribute or
+ * a {@link GomObject} property identified using a nick with a '::' prefix.
+ *
+ * If there are more elements with same keys, they are kept as child nodes
+ * but the one in collection will be the last one to be found.
+ *
+ * Return: false if element should not be added to collection.
+ */
+ public override bool validate_append (int index, DomElement element) throws GLib.Error {
+ if (!(element is GomElement)) return false;
+ string pkey = null;
+ string skey = null;
+ string tkey = null;
+ if (attribute_primary_key != null && attribute_secondary_key != null
+ && attribute_third_key != null) {
+ pkey = (element as DomElement).get_attribute (attribute_primary_key);
+ skey = (element as DomElement).get_attribute (attribute_secondary_key);
+ tkey = (element as DomElement).get_attribute (attribute_third_key);
+ if (pkey == null || skey == null || tkey == null) {
+ pkey = (element as DomElement).get_attribute (attribute_primary_key.down ());
+ skey = (element as DomElement).get_attribute (attribute_secondary_key.down ());
+ tkey = (element as DomElement).get_attribute (attribute_third_key.down ());
+ }
+ } else {
+ if (items_type.is_a (typeof(MappeableElementThreeKey))) {
+ if (!(element is MappeableElementThreeKey)) return false;
+ pkey = ((MappeableElementThreeKey) element).get_map_pkey ();
+ skey = ((MappeableElementThreeKey) element).get_map_skey ();
+ tkey = ((MappeableElementThreeKey) element).get_map_tkey ();
+ }
+ }
+ if (pkey == null || skey == null || tkey == null) return false;
+ var ht = _hashtable.get (pkey);
+ if (ht == null) ht = new HashMap<string,HashMap<string,int>> ();
+ var hte = ht.get (skey);
+ if (hte == null) hte = new HashMap<string,int> ();
+ if (!_hashtable.has_key (pkey)) _hashtable.set (pkey, ht);
+ if (!ht.has_key (skey)) ht.set (skey, hte);
+ hte.set (tkey, index);
+ return true;
+ }
+ public override void clear () {
+ _hashtable = new HashMap<string,HashMap<string,HashMap<string,int>>> ();
+ }
+
+ public DomElement? item (string primary_key, string secondary_key, string third_key) {
+ return get (primary_key, secondary_key, third_key);
+ }
+ public Set<string> primary_keys_set {
+ owned get {
+ var l = new HashSet<string> ();
+ foreach (string k in _hashtable.keys) {
+ l.add (k);
+ }
+ return l;
+ }
+ }
+ public Set<string> secondary_keys_set (string pkey) {
+ var l = new HashSet<string> ();
+ if (!_hashtable.has_key (pkey)) return l;
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return l;
+ foreach (string k in ht.keys) {
+ l.add (k);
+ }
+ return l;
+ }
+ public Set<string> third_keys_set (string pkey, string skey) {
+ var l = new HashSet<string> ();
+ if (!_hashtable.has_key (pkey)) return l;
+ var ht = _hashtable.get (pkey);
+ if (ht == null) return l;
+ var hte = ht.get (skey);
+ if (hte == null) return l;
+ foreach (string k in hte.keys) {
+ l.add (k);
+ }
+ return l;
+ }
+}
diff --git a/gxml/meson.build b/gxml/meson.build
index f04be68..cd16e8d 100644
--- a/gxml/meson.build
+++ b/gxml/meson.build
@@ -57,10 +57,14 @@ valasources = files ([
'Element.vala',
'Enumeration.vala',
'GHtml.vala',
+ 'GomArrayList.vala',
'GomAttr.vala',
- 'GomCollections.vala',
+ 'GomBaseCollection.vala',
'GomDocument.vala',
'GomElement.vala',
+ 'GomHashMap.vala',
+ 'GomHashPairedMap.vala',
+ 'GomHashThreeMap.vala',
'GomNode.vala',
'GomObject.vala',
'GomProperty.vala',
@@ -180,4 +184,4 @@ endif
libgxml_dep = declare_dependency(include_directories : inc_rooth_dep,
- link_with : libgxml)
\ No newline at end of file
+ link_with : libgxml)
diff --git a/test/GomElementTest.vala b/test/GomElementTest.vala
index 912c398..355962e 100644
--- a/test/GomElementTest.vala
+++ b/test/GomElementTest.vala
@@ -753,7 +753,6 @@ class GomElementTest : GXmlTest {
assert (e.get_attribute ("prop") == "value_prop");
assert (e.text != null);
assert (e.prop != null);
- assert_not_reached ();
} catch (GLib.Error e) {
GLib.message ("Error: "+e.message);
assert_not_reached ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]