/libxnoise/SimpleMarkup/xnoise-markup-node.vala

https://code.google.com/p/xnoise/ · Vala · 499 lines · 397 code · 63 blank · 39 comment · 138 complexity · 4873fbf8fa226c8be61f5fd179c6693d MD5 · raw file

  1. /* simple-xml-node.vala
  2. *
  3. * Copyright (C) 2010 J??rn Magens
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * The Xnoise authors hereby grant permission for non-GPL compatible
  11. * GStreamer plugins to be used and distributed together with GStreamer
  12. * and Xnoise. This permission is above and beyond the permissions granted
  13. * by the GPL license by which Xnoise is covered. If you modify this code
  14. * you may extend this exception to your version of the code, but you are not
  15. * obligated to do so. If you do not wish to do so, delete this exception
  16. * statement from your version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  26. *
  27. * Author:
  28. * J??rn Magens
  29. */
  30. namespace Xnoise.SimpleMarkup {
  31. public class Node {
  32. // Represents a xml node. Can contain more nodes, text and attributes
  33. // For convenient usage with vala iteration
  34. private unowned Node _parent;
  35. private unowned Node? _previous = null;
  36. private Node? _next = null;
  37. private int _children_count = 0;
  38. private string? _name = null;
  39. public Attributes attributes = new Attributes();
  40. public Node(string? name) {
  41. this._name = name;
  42. }
  43. public string? text { get; set; default = null; }
  44. public string? name { get { return _name; } }
  45. public Node? parent { get { return _parent; } }
  46. public Node? previous { get { return _previous; } }
  47. public Node? next { get { return _next; } }
  48. public class Attributes {
  49. private GLib.HashTable<string, string> table =
  50. new GLib.HashTable<string, string>(str_hash, str_equal);
  51. public Keys keys;
  52. public Attributes() {
  53. keys = new Keys(this);
  54. }
  55. ~Attributes() {
  56. table.remove_all();
  57. table = null;
  58. }
  59. public class Keys {
  60. private unowned Attributes attrib;
  61. public Keys(Attributes _attrib) {
  62. attrib = _attrib;
  63. }
  64. public bool contains(string needle_key) {
  65. foreach(string current_key in attrib.key_list) {
  66. if(str_equal(needle_key, current_key))
  67. return true;
  68. }
  69. return false;
  70. }
  71. public Iterator iterator() {
  72. return new Iterator(this.attrib);
  73. }
  74. public class Iterator {
  75. private unowned Attributes iter_attib;
  76. private List<unowned string> key_list = null;
  77. private unowned List<string> curr_key;
  78. public Iterator(Attributes _iter_attib) {
  79. this.iter_attib = _iter_attib;
  80. }
  81. public bool next() {
  82. if(this.key_list == null) {
  83. this.key_list = iter_attib.key_list;
  84. if(this.key_list == null)
  85. return false;
  86. this.curr_key = this.key_list.first();
  87. if(this.curr_key.data != null)
  88. return true;
  89. else
  90. return false;
  91. }
  92. else {
  93. if(this.curr_key.next == null)
  94. return false;
  95. this.curr_key = this.curr_key.next;
  96. return true;
  97. }
  98. }
  99. public string? get() {
  100. if(this.curr_key == null)
  101. return null;
  102. return this.curr_key.data;
  103. }
  104. }
  105. }
  106. public void add(string key, string val) {
  107. assert(table != null);
  108. table.insert(key, val);
  109. }
  110. public void replace(string key, string val) {
  111. assert(table != null);
  112. table.replace(key, val);
  113. }
  114. public void remove(string key) {
  115. assert(table != null);
  116. table.remove(key);
  117. }
  118. public void clear() {
  119. assert(table != null);
  120. table.remove_all();
  121. }
  122. public int item_count {
  123. get {
  124. return (int)table.size();
  125. }
  126. }
  127. public List<unowned string> key_list {
  128. owned get {
  129. return table.get_keys();
  130. }
  131. }
  132. public List<unowned string> value_list {
  133. owned get {
  134. return table.get_values();
  135. }
  136. }
  137. public string? get(string key) {
  138. return table.lookup(key);
  139. }
  140. public void set(string key, string? val) {
  141. if(val == null) {
  142. table.remove(key);
  143. }
  144. else {
  145. table.insert(key, val);
  146. }
  147. }
  148. }
  149. public bool has_text() {
  150. return this.text != null;
  151. }
  152. public bool has_children() {
  153. return _children_count > 0 && this._first != null;
  154. }
  155. public bool has_attributes() {
  156. return attributes.item_count > 0;
  157. }
  158. private Node? _first = null;
  159. private unowned Node? _last = null;
  160. public int children_count {
  161. get {
  162. return this._children_count;
  163. }
  164. }
  165. public void prepend_child(Node node) {
  166. assert(node.parent == null);
  167. node._parent = this;
  168. if(this._first == null && this._last == null) {
  169. this._first = node;
  170. this._last = node;
  171. this._children_count++;
  172. }
  173. else {
  174. this.insert_child(0, node);
  175. }
  176. return;
  177. }
  178. public void append_child(Node node) {
  179. assert(node.parent == null);
  180. node._parent = this;
  181. if(this._first == null && this._last == null) {
  182. this._first = node;
  183. this._last = node;
  184. }
  185. else {
  186. this._last._next = node;
  187. node._previous = this._last;
  188. this._last = node;
  189. }
  190. this._children_count++;
  191. return;
  192. }
  193. public void insert_child(int pos, Node node) {
  194. assert(node.parent == null);
  195. node._parent = this;
  196. if(pos < 0) {
  197. pos = this._children_count - 1 - pos;
  198. assert(pos >= 0);
  199. }
  200. if(pos > this._children_count) {
  201. this.append_child(node);
  202. }
  203. else if(pos == 0) {
  204. node._next = this._first;
  205. this._first._previous = node;
  206. this._first = node;
  207. this._children_count++;
  208. }
  209. else {
  210. Node prev = this._first;
  211. int i = 0;
  212. while(i < pos - 1) {
  213. i++;
  214. prev = prev.next;
  215. }
  216. node._previous = prev;
  217. node._next = prev.next;
  218. node.next._previous = node;
  219. prev._next = node;
  220. this._children_count++;
  221. }
  222. }
  223. // returns the first appearance only !!!
  224. //TODO: method that returns all children with a certain name
  225. public unowned Node? get_child_by_name(string childname) {
  226. foreach(unowned Node n in this) {
  227. if(n.name == childname)
  228. return n;
  229. }
  230. return null;
  231. }
  232. public Node[] get_children_by_name(string childname) {
  233. Node[] nds = {};
  234. foreach(unowned Node n in this) {
  235. if(n.name == childname)
  236. nds += n;
  237. }
  238. return nds;
  239. }
  240. public int get_idx_of_child(Node node) {
  241. int idx = -1;
  242. foreach(Node n in this) {
  243. if(&n == &node) { //adress compare
  244. return idx;
  245. }
  246. idx++;
  247. }
  248. return idx;
  249. }
  250. //get node by index; don't use this to iterate over list
  251. public unowned Node? get(int idx) {
  252. if(idx > (this._children_count - 1))
  253. return null;
  254. unowned Node? nd = null;;
  255. if(idx == 0) {
  256. nd = this._first;
  257. }
  258. else if(idx == this._children_count - 1) {
  259. nd = this._last;
  260. }
  261. else if(idx <= this._children_count / 2) { //start from begin
  262. nd = this._first;
  263. int i = 0;
  264. while(i != idx) {
  265. nd = nd.next;
  266. i++;
  267. }
  268. }
  269. else { //start from end
  270. nd = this._last;
  271. for (int i = this._children_count - 1; i != idx; i--) {
  272. nd = nd.previous;
  273. }
  274. }
  275. //check if we have a container
  276. if(nd == null)
  277. return null;
  278. else
  279. return nd;
  280. }
  281. //simply overwrite the Node
  282. public void set(int idx, Node node) {
  283. assert(node.parent == null);
  284. node._parent = this;
  285. if(idx > (this._children_count - 1))
  286. return; //should I put a warning here?
  287. unowned Node? nd = null;;
  288. if(idx == 0) {
  289. nd = this._first;
  290. }
  291. else if(idx == this._children_count - 1) {
  292. nd = this._last;
  293. }
  294. else if(idx <= this._children_count / 2) { //start from begin
  295. int i = 0;
  296. nd = this._first;
  297. while(i != idx) {
  298. nd = nd.next;
  299. i++;
  300. }
  301. }
  302. else { //start from end
  303. int i = this._children_count - 1;
  304. nd = this._last;
  305. while(i != idx) {
  306. nd = nd.previous;
  307. i--;
  308. }
  309. }
  310. return_if_fail(nd != null);
  311. Node prev = nd.previous;
  312. Node nxt = nd.next;
  313. node._previous = prev;
  314. node._next = prev.next;
  315. if(nxt != null)
  316. nxt._previous = node;
  317. if(prev != null)
  318. prev._next = node;
  319. if(nd == this._first)
  320. this._first = node;
  321. if(nd == this._last)
  322. this._last = node;
  323. }
  324. public bool remove_child(Node node) {
  325. int idx = get_idx_of_child(node);
  326. if(idx >= 0) {
  327. return remove_child_at_idx(idx);
  328. }
  329. else {
  330. return false;
  331. }
  332. }
  333. public bool remove_child_at_idx(int idx) {
  334. if(idx > (this._children_count - 1))
  335. return false;
  336. unowned Node? nd = null;;
  337. if(idx == 0) {
  338. nd = this._first;
  339. }
  340. else if(idx == this._children_count - 1) {
  341. nd = this._last;
  342. }
  343. else if(idx <= this._children_count / 2) { //start from begin
  344. nd = this._first;
  345. int i = 0;
  346. while(i != idx) {
  347. nd = nd.next;
  348. i++;
  349. }
  350. }
  351. else { //start from end
  352. nd = this._last;
  353. for(int i = this._children_count - 1; i != idx; i--) {
  354. nd = nd.previous;
  355. }
  356. }
  357. //check if we have a container
  358. if(nd == null)
  359. return false;
  360. //put the list parts together
  361. if(nd == this._first) {
  362. this._first = nd.next;
  363. }
  364. if(nd == this._last) {
  365. this._last = nd.previous;
  366. }
  367. if(nd.previous != null) {
  368. nd.previous._next = nd.next;
  369. }
  370. if(nd.next != null) {
  371. nd.next._previous = nd.previous;
  372. }
  373. nd._previous = null;
  374. nd._next = null;
  375. this._children_count--;
  376. return true;
  377. }
  378. public void clear() {
  379. this._first = this._last = null;
  380. this._children_count = 0;
  381. }
  382. public Iterator iterator() {
  383. return new Iterator(this);
  384. }
  385. public class Iterator {
  386. private bool started = false; //set to first item on first iteration
  387. private bool removed = false;
  388. private unowned Node parent_node;
  389. private int _index;
  390. //a pointer to the current child for the Iterator of the node
  391. private unowned Node? current_child;
  392. public Iterator(Node parent_node) {
  393. this.parent_node = parent_node;
  394. this.current_child = null;
  395. this._index = -1;
  396. }
  397. public bool next() {
  398. if(this.removed && this.current_child != null) {
  399. this.removed = false;
  400. return true;
  401. }
  402. else if(!this.started && this.parent_node._first != null) {
  403. this.started = true;
  404. this.current_child = this.parent_node._first;
  405. this._index++;
  406. return true;
  407. }
  408. else if(this.current_child != null && this.current_child.next != null) {
  409. this.current_child = this.current_child.next;
  410. this._index++;
  411. return true;
  412. }
  413. return false;
  414. }
  415. public unowned Node get() {
  416. assert(this.current_child != null);
  417. return this.current_child;
  418. }
  419. public void set(Node node) {
  420. assert(this.current_child != null);
  421. Node? prev = this.current_child.previous;
  422. Node? nxt = this.current_child.next;
  423. node._previous = prev;
  424. node._next = prev.next;
  425. if(nxt != null)
  426. nxt._previous = node;
  427. if(prev != null)
  428. prev._next = node;
  429. if(this.current_child == this.parent_node._first)
  430. this.parent_node._first = node;
  431. if(this.current_child == this.parent_node._last)
  432. this.parent_node._last = node;
  433. }
  434. }
  435. }
  436. }