gflow-simple-node.vala 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /********************************************************************
  2. # Copyright 2014-2019 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;
  30. private List<Sink> sinks;
  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. public SimpleNode() {
  44. base();
  45. this.sources = new List<Source>();
  46. this.sinks = new List<Sink>();
  47. }
  48. /**
  49. * Add the given {@link Source} to this SimpleNode
  50. */
  51. public void add_source(Source s) throws NodeError {
  52. if (s.node != null)
  53. throw new NodeError.DOCK_ALREADY_BOUND_TO_NODE("This Source is already bound");
  54. if (this.sources.index(s) != -1)
  55. throw new NodeError.ALREADY_HAS_DOCK("This node already has this source");
  56. sources.append(s);
  57. s.node = this;
  58. source_added (s);
  59. }
  60. /**
  61. * Add the given {@link Sink} to this SimpleNode
  62. */
  63. public void add_sink (Sink s) throws NodeError {
  64. if (s.node != null)
  65. throw new NodeError.DOCK_ALREADY_BOUND_TO_NODE("This Sink is already bound" );
  66. if (this.sinks.index(s) != -1)
  67. throw new NodeError.ALREADY_HAS_DOCK("This node already has this sink");
  68. sinks.append(s);
  69. s.node = this;
  70. sink_added (s);
  71. }
  72. /**
  73. * Remove the given {@link Source} from this SimpleNode
  74. */
  75. public void remove_source(Source s) throws NodeError {
  76. if (this.sources.index(s) == -1)
  77. throw new NodeError.NO_SUCH_DOCK("This node doesn't have this source");
  78. sources.remove(s);
  79. s.node = null;
  80. source_removed (s);
  81. }
  82. /**
  83. * Remove the given {@link Sink} from this SimpleNode
  84. */
  85. public void remove_sink(Sink s) throws NodeError {
  86. if (this.sinks.index(s) == -1)
  87. throw new NodeError.NO_SUCH_DOCK("This node doesn't have this sink");
  88. sinks.remove(s);
  89. s.node = null;
  90. sink_removed (s);
  91. }
  92. /**
  93. * Returns true if the given {@link Sink} is one of this SimpleNode's Sinks.
  94. */
  95. public bool has_sink(Sink s) {
  96. return this.sinks.index(s) != -1;
  97. }
  98. /**
  99. * Returns true if the given {@link Source} is one of this SimpleNode's Sources.
  100. */
  101. public bool has_source(Source s) {
  102. return this.sources.index(s) != -1;
  103. }
  104. /**
  105. * Returns true if the given {@link Dock} is one of this SimpleNode's Docks.
  106. */
  107. public bool has_dock(Dock d) {
  108. if (d is Source)
  109. return this.has_source(d as Source);
  110. else
  111. return this.has_sink(d as Sink);
  112. }
  113. /**
  114. * Searches this SimpleNode's {@link Dock}s for a Dock with the given name.
  115. * If there is any, it will be returned. Else, null will be returned
  116. */
  117. public Dock? get_dock (string name) {
  118. foreach (Sink s in this.sinks)
  119. if (s.name == name)
  120. return s;
  121. foreach (Source s in this.sources)
  122. if (s.name == name)
  123. return s;
  124. return null;
  125. }
  126. /**
  127. * Returns the sources of this node
  128. */
  129. public unowned List<Source> get_sources() {
  130. return this.sources;
  131. }
  132. /**
  133. * Returns the sinks of this node
  134. */
  135. public unowned List<Sink> get_sinks() {
  136. return this.sinks;
  137. }
  138. /**
  139. * This method checks whether a connection from the given from-Node
  140. * to this Node would lead to a recursion in the direction source -> sink
  141. */
  142. public bool is_recursive_forward(Node from, bool initial=true) {
  143. if (!initial && this == from)
  144. return true;
  145. foreach (Source source in this.get_sources()) {
  146. foreach (Sink sink in source.sinks) {
  147. if (sink.node.is_recursive_forward(from, false))
  148. return true;
  149. }
  150. }
  151. return false;
  152. }
  153. /**
  154. * This method checks whether a connection from the given from-Node
  155. * to this Node would lead to a recursion in the direction sink -> source
  156. */
  157. public bool is_recursive_backward(Node from, bool initial=true) {
  158. if (!initial && this == from)
  159. return true;
  160. foreach (Sink sink in this.sinks) {
  161. foreach (Source source in sink.sources) {
  162. if (source.node.is_recursive_backward(from, false))
  163. return true;
  164. }
  165. }
  166. return false;
  167. }
  168. /**
  169. * Gets all neighbor nodes that this node is connected to
  170. */
  171. public List<Node> get_neighbors() {
  172. var result = new List<Node>();
  173. foreach (Source source in this.get_sources()) {
  174. foreach (Sink sink in source.sinks) {
  175. if (sink.node != null && result.index(sink.node) == -1)
  176. result.append(sink.node);
  177. }
  178. }
  179. foreach (Sink sink in this.get_sinks()) {
  180. foreach (Source source in sink.sources) {
  181. if (source.node != null && result.index(source.node) == -1)
  182. result.append(source.node);
  183. }
  184. }
  185. return result;
  186. }
  187. /**
  188. * Returns true if the given node is directly connected
  189. * to this node
  190. */
  191. public bool is_neighbor(Node n) {
  192. return this.get_neighbors().index(n) != -1;
  193. }
  194. /**
  195. * Disconnect all connections from and to this node
  196. */
  197. public void unlink_all() {
  198. foreach (Source s in this.sources) {
  199. try {
  200. s.unlink_all();
  201. } catch (GLib.Error e) {
  202. warning("Could not unlink source %s from node %s", s.name, this.name);
  203. }
  204. }
  205. foreach (Sink s in this.sinks) {
  206. try {
  207. s.unlink_all();
  208. } catch (GLib.Error e) {
  209. warning("Could not unlink sink %s from node %s", s.name, this.name);
  210. }
  211. }
  212. }
  213. }
  214. }