gflow-simple-sink.vala 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. * A simple implementation of {@link GFlow.Sink}.
  24. */
  25. public class SimpleSink : Object, Dock, Sink {
  26. // Dock interface
  27. protected HashTable<Source, weak GLib.Value?> _val;
  28. protected GLib.Value? _initial = null;
  29. private string? _name = null;
  30. /**
  31. * This SimpleSink's displayname
  32. */
  33. public string? name {
  34. get { return this._name; }
  35. set { this._name = value; }
  36. }
  37. public string? _typename = null;
  38. /**
  39. * This SimpleSink's typestring
  40. */
  41. public string? typename {
  42. get { return this._typename; }
  43. set { this._typename = value; }
  44. }
  45. /**
  46. * Defines how many sources can be connected to this sink
  47. *
  48. * Setting this variable to a lower value than the current
  49. * amount of connected sources will have no further effects
  50. * than not allowing more connections.
  51. */
  52. public uint max_sources {get; set; default=1;}
  53. /**
  54. * Indicates whether this Sink should be rendered highlighted
  55. */
  56. public bool highlight { get; set; default = false; }
  57. /**
  58. * Indicates whether this Sink should be rendered active
  59. */
  60. public bool active {get; set; default=false;}
  61. /**
  62. * A reference to the {@link Node} that this SimpleSink resides in
  63. */
  64. public weak Node? node { get; set; }
  65. /**
  66. * The value that this SimpleSink was initialized with
  67. */
  68. public GLib.Value? initial { get { return _initial; } }
  69. // Sink Interface
  70. private List<Source> _sources = new List<Source> ();
  71. /**
  72. * The {@link Source}s that this SimpleSink is currently connected to
  73. */
  74. public List<Source> sources { get { return _sources; } }
  75. /**
  76. * The value that this SimpleSink holds
  77. */
  78. public List<weak GLib.Value?> val {
  79. public owned get {
  80. var ret = _val.get_values();
  81. return ret;
  82. }
  83. /*set {
  84. if (!_val.holds (value.type ())) return;
  85. _val = value;
  86. this._valid = true;
  87. // FIXME: This properly is read-only then may let implementators to define how "Change a Value"
  88. }*/
  89. }
  90. /**
  91. * Connects this SimpleSink to the given {@link Source}. This will
  92. * only succeed if both {@link Dock}s are of the same type. If this
  93. * is not the case, an exception will be thrown
  94. */
  95. protected void add_source (Source s) throws Error
  96. {
  97. if (this.initial.type() != s.initial.type()) {
  98. throw new NodeError.INCOMPATIBLE_SINKTYPE(
  99. "Can't connect. Source has type %s while Sink has type %s".printf(
  100. s.val.type().name(), this.initial.type().name()
  101. )
  102. );
  103. }
  104. this._sources.append (s);
  105. s.changed.connect (this.do_source_changed);
  106. this._val.@set(s, s.val);
  107. }
  108. /**
  109. * Destroys the connection between this SimpleSink and the given {@link Source}
  110. */
  111. protected void remove_source (Source s) throws GLib.Error
  112. {
  113. if (this._sources.index(s) != -1)
  114. this._sources.remove(s);
  115. if (this._val.contains(s))
  116. this._val.remove(s);
  117. if (s.is_linked_to(this)) {
  118. s.unlink (this);
  119. this.unlinked(s, this._sources.length () == 0);
  120. }
  121. }
  122. /**
  123. * Creates a new SimpleSink with the given initial {@link GLib.Value}
  124. */
  125. public SimpleSink (GLib.Value? initial) {
  126. _val = new HashTable<Source, weak GLib.Value?>(direct_hash, direct_equal);
  127. _initial = initial;
  128. }
  129. /**
  130. * Returns true if this sink is connected to at least one source
  131. */
  132. public bool is_linked() {
  133. return this.sources.length() > 0;
  134. }
  135. /**
  136. * Returns true if this SimpleSink is connected to the given {@link Dock}
  137. */
  138. public bool is_linked_to (Dock dock) { // FIXME Use more logic to know Source type, value or name
  139. if (!(dock is Source)) return false;
  140. return this._sources.index((Source) dock) != -1;
  141. }
  142. /**
  143. * Disconnect from the given {@link Dock}
  144. */
  145. public new void unlink (Dock dock) throws GLib.Error {
  146. if (!this.is_linked_to (dock)) return;
  147. if (dock is Source) {
  148. this.remove_source((Source) dock);
  149. this.do_source_changed();
  150. dock.changed.disconnect (this.do_source_changed);
  151. changed();
  152. }
  153. }
  154. private void do_source_changed() {
  155. foreach (Source s in this._sources) {
  156. this._val.@set(s, s.val);
  157. }
  158. changed ();
  159. }
  160. /**
  161. * Connect to the given {@link Dock}
  162. */
  163. public new void link (Dock dock) throws GLib.Error {
  164. if (this.is_linked_to (dock)) return;
  165. if (!this.before_linking(this, dock)) return;
  166. if (this._sources.length()+1 > this.max_sources && this.sources.length() > 0) {
  167. this.unlink(this.sources.nth_data(this.sources.length()-1));
  168. }
  169. if (dock is Source) {
  170. add_source((Source) dock);
  171. changed();
  172. dock.link (this);
  173. linked (dock);
  174. }
  175. }
  176. /**
  177. * Disconnect from any {@link Dock} that this SimpleSink is connected to
  178. */
  179. public new void unlink_all() throws GLib.Error {
  180. foreach (Source s in this._sources)
  181. if (s != null)
  182. this.unlink(s);
  183. }
  184. /**
  185. * Retrieve the {@link GLib.Value} that this SimpleSource currently holds.
  186. */
  187. public Value? get_value(uint index=0) throws NodeError {
  188. if (this.val.length() > index)
  189. return this.val.nth_data(index);
  190. else
  191. return null;
  192. }
  193. }
  194. }