gflow-simple-node.vala 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /********************************************************************
  2. # Copyright 2014-2017 Daniel 'grindhold' Brendle, 2015 Daniel Espinosa <esodan@gmail.com>
  3. #
  4. # This file is part of libgtkflow.
  5. #
  6. # libgtkflow is free software: you can redistribute it and/or
  7. # modify it under the terms of the GNU Lesser General Public License
  8. # as published by the Free Software Foundation, either
  9. # version 3 of the License, or (at your option) any later
  10. # version.
  11. #
  12. # libgtkflow is distributed in the hope that it will be
  13. # useful, but WITHOUT ANY WARRANTY; without even the implied
  14. # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. # PURPOSE. See the GNU Lesser General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Lesser General Public
  18. # License along with libgtkflow.
  19. # If not, see http://www.gnu.org/licenses/.
  20. *********************************************************************/
  21. namespace GFlow {
  22. /**
  23. * Represents an element that can generate, process or receive data
  24. * This is done by adding Sources and Sinks to it. The inner logic of
  25. * The node can be represented towards the user as arbitrary Gtk widget.
  26. */
  27. public class SimpleNode : Object, Node
  28. {
  29. private List<Source> sources = new List<Source>();
  30. private List<Sink> sinks = new List<Sink>();
  31. /**
  32. * This SimpleNode's name
  33. */
  34. public string name { get; set; default="SimpleNode";}
  35. /**
  36. * Determines wheter the node can be deleted by the user
  37. */
  38. public bool deletable { get; set; default=true;}
  39. /**
  40. * Determines wheter the node can resized by the user
  41. */
  42. public bool resizable { get; set; default=true;}
  43. /**
  44. * Add the given {@link Source} to this SimpleNode
  45. */
  46. public void add_source(Source s) throws NodeError {
  47. if (s.node != null)
  48. throw new NodeError.DOCK_ALREADY_BOUND_TO_NODE("This Source is already bound");
  49. if (this.sources.index(s) != -1)
  50. throw new NodeError.ALREADY_HAS_DOCK("This node already has this source");
  51. sources.append(s);
  52. s.node = this;
  53. source_added (s);
  54. }
  55. /**
  56. * Add the given {@link Sink} to this SimpleNode
  57. */
  58. public void add_sink (Sink s) throws NodeError {
  59. if (s.node != null)
  60. throw new NodeError.DOCK_ALREADY_BOUND_TO_NODE("This Sink is already bound" );
  61. if (this.sinks.index(s) != -1)
  62. throw new NodeError.ALREADY_HAS_DOCK("This node already has this sink");
  63. sinks.append(s);
  64. s.node = this;
  65. sink_added (s);
  66. }
  67. /**
  68. * Remove the given {@link Source} from this SimpleNode
  69. */
  70. public void remove_source(Source s) throws NodeError {
  71. if (this.sources.index(s) == -1)
  72. throw new NodeError.NO_SUCH_DOCK("This node doesn't have this source");
  73. sources.remove(s);
  74. s.node = null;
  75. source_removed (s);
  76. }
  77. /**
  78. * Remove the given {@link Sink} from this SimpleNode
  79. */
  80. public void remove_sink(Sink s) throws NodeError {
  81. if (this.sinks.index(s) == -1)
  82. throw new NodeError.NO_SUCH_DOCK("This node doesn't have this sink");
  83. sinks.remove(s);
  84. s.node = null;
  85. sink_removed (s);
  86. }
  87. /**
  88. * Returns true if the given {@link Sink} is one of this SimpleNode's Sinks.
  89. */
  90. public bool has_sink(Sink s) {
  91. return this.sinks.index(s) != -1;
  92. }
  93. /**
  94. * Returns true if the given {@link Source} is one of this SimpleNode's Sources.
  95. */
  96. public bool has_source(Source s) {
  97. return this.sources.index(s) != -1;
  98. }
  99. /**
  100. * Returns true if the given {@link Dock} is one of this SimpleNode's Docks.
  101. */
  102. public bool has_dock(Dock d) {
  103. if (d is Source)
  104. return this.has_source(d as Source);
  105. else
  106. return this.has_sink(d as Sink);
  107. }
  108. /**
  109. * Searches this SimpleNode's {@link Dock}s for a Dock with the given name.
  110. * If there is any, it will be returned. Else, null will be returned
  111. */
  112. public Dock? get_dock (string name) {
  113. foreach (Sink s in this.sinks)
  114. if (s.name == name)
  115. return s;
  116. foreach (Source s in this.sources)
  117. if (s.name == name)
  118. return s;
  119. return null;
  120. }
  121. /**
  122. * Returns the sources of this node
  123. */
  124. public unowned List<Source> get_sources() {
  125. return this.sources;
  126. }
  127. /**
  128. * Returns the sinks of this node
  129. */
  130. public unowned List<Sink> get_sinks() {
  131. return this.sinks;
  132. }
  133. /**
  134. * This method checks whether a connection from the given from-Node
  135. * to this Node would lead to a recursion in the direction source -> sink
  136. */
  137. public bool is_recursive_forward(Node from, bool initial=true) {
  138. if (!initial && this == from)
  139. return true;
  140. foreach (Source source in this.get_sources()) {
  141. foreach (Sink sink in source.sinks) {
  142. if (sink.node.is_recursive_forward(from, false))
  143. return true;
  144. }
  145. }
  146. return false;
  147. }
  148. /**
  149. * This method checks whether a connection from the given from-Node
  150. * to this Node would lead to a recursion in the direction sink -> source
  151. */
  152. public bool is_recursive_backward(Node from, bool initial=true) {
  153. if (!initial && this == from)
  154. return true;
  155. foreach (Sink sink in this.sinks) {
  156. foreach (Source source in sink.sources) {
  157. if (source.node.is_recursive_backward(from, false))
  158. return true;
  159. }
  160. }
  161. return false;
  162. }
  163. /**
  164. * Gets all neighbor nodes that this node is connected to
  165. */
  166. public List<Node> get_neighbors() {
  167. var result = new List<Node>();
  168. foreach (Source source in this.get_sources()) {
  169. foreach (Sink sink in source.sinks) {
  170. if (sink.node != null && result.index(sink.node) == -1)
  171. result.append(sink.node);
  172. }
  173. }
  174. foreach (Sink sink in this.get_sinks()) {
  175. foreach (Source source in sink.sources) {
  176. if (source.node != null && result.index(source.node) == -1)
  177. result.append(source.node);
  178. }
  179. }
  180. return result;
  181. }
  182. /**
  183. * Returns true if the given node is directly connected
  184. * to this node
  185. */
  186. public bool is_neighbor(Node n) {
  187. return this.get_neighbors().index(n) != -1;
  188. }
  189. /**
  190. * Disconnect all connections from and to this node
  191. */
  192. public void unlink_all() {
  193. foreach (Source s in this.sources) {
  194. try {
  195. s.unlink_all();
  196. } catch (GLib.Error e) {
  197. warning("Could not unlink source %s from node %s", s.name, this.name);
  198. }
  199. }
  200. foreach (Sink s in this.sinks) {
  201. try {
  202. s.unlink_all();
  203. } catch (GLib.Error e) {
  204. warning("Could not unlink sink %s from node %s", s.name, this.name);
  205. }
  206. }
  207. }
  208. }
  209. }