Jamoma API  0.6.0.a19
TTContainer.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup modularLibrary
4  *
5  * @brief A Container object
6  *
7  * @details
8  *
9  * @authors Théo de la Hogue
10  *
11  * @copyright © 2010, Théo de la Hogue @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 
17 #include "TTContainer.h"
18 
19 #define thisTTClass TTContainer
20 #define thisTTClassName "Container"
21 #define thisTTClassTags "node, container"
22 
23 TT_MODULAR_CONSTRUCTOR,
24 mPriority(0),
25 mDescription(kTTSym_none),
26 mService(kTTSym_none),
27 mTags(TTValue(kTTSym_none)),
28 mInitialized(NO),
29 mActive(YES),
30 mAddress(kTTAdrsEmpty),
31 mAlias(kTTAdrsEmpty),
32 activityAttribute(NULL),
33 contentAttribute(NULL)
34 {
35  if(arguments.size() == 2)
36  {
37  mReturnAddressCallback = arguments[0];
38  mReturnValueCallback = arguments[1];
39  }
40 
42  addAttribute(Description, kTypeSymbol);
43 
44  addAttribute(Service, kTypeSymbol);
45 
47 
48  addAttribute(Initialized, kTypeBoolean);
49  addAttributeProperty(Initialized, readOnly, YES);
50  addAttributeProperty(Initialized, hidden, YES);
51 
53 
55  addAttributeProperty(Address, hidden, YES);
56 
58 
59  addAttribute(Activity, kTypeLocalValue); // TODO : have a way to add notification (instead of a readonly attribute)
60  addAttributeProperty(Activity, readOnly, YES);
61 
62  addAttribute(Content, kTypeLocalValue); // TODO : have a way to add notification (instead of a readonly attribute)
63  addAttributeProperty(Content, readOnly, YES);
64 
66  addMessageProperty(Send, hidden, YES);
67 
68  addMessage(Init);
69 
71  addMessageProperty(Rename, hidden, YES);
72 
73  addMessage(AliasRemove);
74 
75  // needed to be handled by a TTTextHandler
76  addMessageWithArguments(WriteAsText);
77  addMessageProperty(WriteAsText, hidden, YES);
78 
79  mIsSending = false;
80 
81  // cache some attribute for observer notification
82  this->findAttribute(kTTSym_activity, &activityAttribute);
83  this->findAttribute(kTTSym_content, &contentAttribute);
84 }
85 
86 TTContainer::~TTContainer()
87 {
88  setAlias(kTTAdrsEmpty);
89  unbind();
90 }
91 
92 TTErr TTContainer::Send(TTValue& AddressAndValue, TTValue& outputValue)
93 {
94  TTValue hk, cacheElement, v, none;
95  TTValuePtr valueToSend;
96  TTObject anObject;
97  TTAddress aRelativeAddress, topAddress, belowAddress, keyAddress;
98  TTSymbol attrOrMess, service;
99  TTUInt32 i;
100  TTInt8 depth = 0;
101  TTErr err = kTTErrNone;
102 
103  if (!mIsSending) {
104 
105  // lock
106  mIsSending = true;
107 
108  // get relativeAddress and valueToSend
109  aRelativeAddress = AddressAndValue[0];
110 
111  // get attribute or message (default is value)
112  if (aRelativeAddress.getAttribute() != NO_ATTRIBUTE)
113  attrOrMess = aRelativeAddress.getAttribute();
114  else
115  attrOrMess = kTTSym_value;
116 
117  // If there is a wild card into relative address part
118  if (strrchr(aRelativeAddress.c_str(), C_WILDCARD)) {
119 
120  mIsSending = false;
121 
122  // split relative address
123  aRelativeAddress.splitAt(0, topAddress, belowAddress);
124 
125  // Get each keys sorted by priority
126  mObjectsObserversCache.getKeysSorted(hk, &TTContainerCompareObjectPriority);
127 
128  // find each keyAddress equals to the top address part
129  for (i = 0; i < mObjectsObserversCache.getSize(); i++) {
130 
131  keyAddress = hk[i];
132 
133  TTAddressComparisonFlag comparison = topAddress.compare(keyAddress, depth);
134 
135  // is topAddress the address of cached container ?
136  if (comparison == kAddressEqual)
137  {
138  // replace relativeAddress by keyAddress
139  AddressAndValue[0] = keyAddress.appendAddress(belowAddress).appendAttribute(attrOrMess);
140 
141  if (this->Send(AddressAndValue, none))
142  err = kTTErrGeneric;
143  }
144  // or is it the top address part of a cached object ?
145  else if (comparison == kAddressUpper)
146  {
147  // compare the relative address
148  TTAddressComparisonFlag comparison = aRelativeAddress.compare(keyAddress, depth);
149 
150  if (comparison == kAddressEqual)
151  {
152  // replace relativeAddress by keyAddress
153  AddressAndValue[0] = keyAddress.appendAttribute(attrOrMess);
154 
155  if (this->Send(AddressAndValue, none))
156  err = kTTErrGeneric;
157  }
158  }
159  }
160 
161  return err;
162  }
163 
164  valueToSend = TTValuePtr((TTPtr)AddressAndValue[1]);
165 
166  // get the object
167  err = mObjectsObserversCache.lookup(aRelativeAddress.removeAttribute(), cacheElement);
168 
169  // if the relativeAddress is in the cache
170  if (!err) {
171 
172  anObject = cacheElement[0];
173 
174  // DATA CASE for value attribute
175  if (anObject.name() == kTTSym_Data && attrOrMess == kTTSym_value) {
176 
177  // what kind of service the data is used for ?
178  anObject.get(kTTSym_service, v);
179  service = v[0];
180 
181  // we are not supposed to address returns
182  if (service == kTTSym_return)
183  return kTTErrNone;
184 
185  // set the value attribute using a command
186  anObject.send(kTTSym_Command, *valueToSend);
187 
188  // unlock
189  mIsSending = false;
190  return kTTErrNone;
191  }
192 
193  // VIEWER CASE for a same attribute
194  if (anObject.name() == kTTSym_Viewer && attrOrMess == kTTSym_value) {
195 
196  // send the value
197  anObject.send(kTTSym_Send, *valueToSend);
198 
199  // unlock
200  mIsSending = false;
201  return kTTErrNone;
202  }
203 
204  // DEFAULT CASE
205  // Try to set attribute
206  err = anObject.set(attrOrMess, *valueToSend);
207  if (err == kTTErrInvalidAttribute) {
208 
209  // Or try to send a message
210  anObject.send(attrOrMess, *valueToSend);
211  }
212  }
213  // maybe the relative address is for Container below ourself
214  else {
215 
216  // split relative address
217  aRelativeAddress.splitAt(0, topAddress, belowAddress);
218 
219  // retry using only the first (top) part of the relative address
220  err = mObjectsObserversCache.lookup(topAddress, cacheElement);
221 
222  // if the object is in our cache : we replace the relative addres by the belowAddress and send the value
223  if (!err) {
224 
225  anObject = cacheElement[0];
226 
227  // check if it is a #TTContainer object
228  if (anObject.name() == kTTSym_Container) {
229 
230  AddressAndValue[0] = belowAddress;
231  anObject.send(kTTSym_Send, AddressAndValue);
232 
233  // unlock
234  mIsSending = false;
235  return kTTErrNone;
236  }
237  }
238  }
239  }
240 
241  // unlock
242  mIsSending = false;
243  return err;
244 }
245 
246 TTErr TTContainer::Init()
247 {
248  TTAttributePtr anAttribute;
249  TTList nodeList;
250  TTNodePtr aNode;
251 
252  // Restart initialisation
253  mInitialized = NO;
254 
255  // Notify observers (this can't be prioritized because observers have no priority)
256  findAttribute(kTTSym_initialized, &anAttribute);
257  anAttribute->sendNotification(kTTSym_notify, mInitialized);
258 
259  // Look for all nodes under the address into the directory with the same Context
260  if (!accessApplicationLocalDirectory->Lookup(mAddress, nodeList, &aNode))
261  initNode(aNode);
262 
263  // End of initialisation
264  mInitialized = YES;
265 
266  // Notify observers
267  findAttribute(kTTSym_initialized, &anAttribute);
268  anAttribute->sendNotification(kTTSym_notify, mInitialized);
269 
270  return kTTErrNone;
271 }
272 
273 TTErr TTContainer::initNode(TTNodePtr aNode)
274 {
275  TTList nodeList, nameList, initializedList;
276 
277  // get all children below
278  aNode->getChildren(S_WILDCARD, S_WILDCARD, nodeList);
279 
280  // sort children by priority order
281  nodeList.sort(&compareNodePriorityThenNameThenInstance);
282 
283  // build a list of name and instance
284  for (nodeList.begin(); nodeList.end(); nodeList.next())
285  {
286  TTNodePtr aChild = TTNodePtr((TTPtr)nodeList.current()[0]);
287  TTValue nameInstance(aChild->getName(), aChild->getInstance());
288 
289  nameList.append(nameInstance);
290  }
291 
292  // retreive each child using its name and instance in case one parameter have an effect on the children
293  while (!nameList.isEmpty())
294  {
295  nameList.begin();
296  TTSymbol name = nameList.current()[0];
297  TTSymbol instance = nameList.current()[1];
298 
299  // if a child doesn't exist anymore
300  if (aNode->getChildren(name, instance, nodeList))
301  {
302  // rebuild the name list without the nodes already initialized
303  nameList.clear();
304  aNode->getChildren(S_WILDCARD, S_WILDCARD, nodeList);
305 
306  // sort children by priority order
307  nodeList.sort(&compareNodePriorityThenNameThenInstance);
308 
309  for (nodeList.begin(); nodeList.end(); nodeList.next())
310  {
311  TTNodePtr aChild = TTNodePtr((TTPtr)nodeList.current()[0]);
312  TTValue nameInstance(aChild->getName(), aChild->getInstance());
313 
314  // if the node haven't been initialized
315  TTValue found;
316  if (initializedList.findEquals(nameInstance, found))
317  nameList.append(nameInstance);
318  }
319 
320  // skip the missing child
321  continue;
322  }
323 
324  // mark the child as initialized
325  initializedList.append(nameList.current());
326  nameList.remove(nameList.current());
327 
328  // get the first and only node with this name and instance
329  nodeList.begin();
330  TTNodePtr aChild = TTNodePtr((TTPtr)nodeList.current()[0]);
331 
332  TTObject anObject = aChild->getObject();
333 
334  if (anObject.valid())
335  {
336  // Send an Init message to all Data service parameter which are in the same context
337  if (anObject.name() == kTTSym_Data)
338  {
339  if (aChild->getContext() != aNode->getContext())
340  continue;
341 
342  TTValue v;
343  TTSymbol service;
344 
345  anObject.get(kTTSym_service, v);
346  service = v[0];
347 
348  if (service == kTTSym_parameter)
349  anObject.send(kTTSym_Init);
350  }
351  // Send an Init message to all Container
352  else if (anObject.name() == kTTSym_Container)
353  anObject.send(kTTSym_Init);
354  }
355 
356  initNode(aChild);
357  }
358 
359  return kTTErrNone;
360 }
361 
362 TTErr TTContainer::Rename(const TTValue& inputValue, TTValue& outputValue)
363 {
364  if (inputValue.size() == 1) {
365 
366  if (inputValue[0].type() == kTypeSymbol) {
367 
368  TTSymbol newNameInstance = inputValue[0];
369  TTAddress oldAddress = mAddress;
370  TTValue args(TTObject(this), newNameInstance);
371 
372  unbind();
373 
374  TTErr err = accessApplicationFrom(mAddress)->sendMessage("ObjectRename", args, outputValue);
375 
376  if (!err)
377  newNameInstance = outputValue[0];
378 
379  mAddress = oldAddress.getParent().appendAddress(TTAddress(newNameInstance));
380 
381  bind();
382 
383  return err;
384  }
385  }
386 
387  return kTTErrGeneric;
388 }
389 
390 /** */
391 TTErr TTContainer::AliasRemove()
392 {
393  return setAlias(kTTAdrsEmpty);
394 }
395 
396 TTErr TTContainer::setAddress(const TTValue& value)
397 {
398  unbind();
399  mAddress = value[0];
400 
401  if (mAddress != kTTAdrsEmpty)
402  return bind();
403  else
404  return kTTErrNone;
405 }
406 
407 TTErr TTContainer::setAlias(const TTValue& value)
408 {
410  TTAttributePtr anAttribute;
411  TTAddress oldAlias = mAlias;
412  TTNodePtr aNode;
413  TTObject anObject;
414  TTValue hk, cacheElement;
415  TTSymbol key;
416  TTUInt32 i;
417  TTString aliasKey;
418 
419  TTAddress newAlias = value[0];
420 
421  // if the alias is relative append to our parent address
422  if (newAlias.getType() == kAddressRelative)
423  mAlias = mAddress.getParent().appendAddress(newAlias);
424  else
425  mAlias = newAlias;
426 
427  // check it changes
428  if (oldAlias != mAlias) {
429 
430  if (oldAlias != kTTAdrsEmpty) {
431 
432  localDirectory->AliasRemove(oldAlias);
433 
434  // notify the deletion of all /alias/key address
435  mObjectsObserversCache.getKeys(hk);
436  for (i = 0; i < mObjectsObserversCache.getSize(); i++) {
437  key = hk[i];
438 
439  // edit alias/key address
440  aliasKey = oldAlias.c_str();
441  aliasKey += S_SEPARATOR.c_str();
442  aliasKey += key.c_str();
443 
444  // get the node at this address
445  mObjectsObserversCache.lookup(key, cacheElement);
446  aNode = TTNodePtr((TTPtr)cacheElement[2]);
447 
448  localDirectory->notifyObservers(TTAddress(aliasKey), aNode, kAddressDestroyed);
449 
450  // remove alias of Container object
451  anObject = cacheElement[0];
452 
453  if (anObject.name() == kTTSym_Container)
454  anObject.set(kTTSym_alias, kTTAdrsEmpty);
455  }
456  }
457 
458  if (mAlias != kTTAdrsEmpty && mAddress != kTTAdrsEmpty) {
459 
460  localDirectory->AliasCreate(mAlias, mAddress);
461 
462  // notify the creation of all /alias/key address
463  mObjectsObserversCache.getKeys(hk);
464  for (i = 0; i < mObjectsObserversCache.getSize(); i++) {
465  key = hk[i];
466 
467  // edit alias/key address
468  aliasKey = mAlias.c_str();
469  aliasKey += S_SEPARATOR.c_str();
470  aliasKey += key.c_str();
471 
472  // get the node at this address
473  mObjectsObserversCache.lookup(key, cacheElement);
474  aNode = TTNodePtr((TTPtr)cacheElement[2]);
475 
476  localDirectory->notifyObservers(TTAddress(aliasKey), aNode, kAddressCreated);
477 
478  // set alias of Container object
479  anObject = cacheElement[0];
480 
481  if (anObject.name() == kTTSym_Container)
482  anObject.set(kTTSym_alias, TTAddress(aliasKey));
483 
484  }
485  }
486 
487  this->findAttribute(kTTSym_alias, &anAttribute);
488  anAttribute->sendNotification(kTTSym_notify, mAlias); // we use kTTSym_notify because we know that observers are TTCallback
489 
490  return kTTErrNone;
491  }
492 
493  return kTTErrGeneric;
494 }
495 
496 TTErr TTContainer::setTags(const TTValue& value)
497 {
498  TTAttributePtr anAttribute;
499  TTErr err = kTTErrNone;
500 
501  mTags = value;
502 
503  err = this->findAttribute(kTTSym_tags, &anAttribute);
504  if (!err)
505  anAttribute->sendNotification(kTTSym_notify, mTags); // we use kTTSym_notify because we know that observers are TTCallback
506 
507  return kTTErrNone;
508 }
509 
510 TTErr TTContainer::setPriority(const TTValue& value)
511 {
512  TTAttributePtr anAttribute;
513  TTErr err = kTTErrNone;
514 
515  mPriority = value;
516 
517  err = this->findAttribute(kTTSym_priority, &anAttribute);
518  if (!err)
519  anAttribute->sendNotification(kTTSym_notify, mPriority); // we use kTTSym_notify because we know that observers are TTCallback
520 
521  return kTTErrNone;
522 }
523 
524 TTErr TTContainer::setActive(const TTValue& value)
525 {
526  TTAttributePtr anAttribute;
527  TTErr err = kTTErrNone;
528 
529  mActive = value;
530 
531  err = this->findAttribute(kTTSym_active, &anAttribute);
532  if (!err)
533  anAttribute->sendNotification(kTTSym_notify, mActive); // we use kTTSym_notify because we know that observers are TTCallback
534 
535  return kTTErrNone;
536 }
537 
538 TTErr TTContainer::bind()
539 {
540  TTNodePtr aNode;
541  TTPtr aContext;
542  TTList aNodeList, allObjectsNodes;
543  TTValue v, baton, none;
544  TTErr err;
545 
546  mObjectsObserversCache.clear();
547 
548  // 1. Look for all nodes under the address into the directory with the same Context
549  err = accessApplicationLocalDirectory->Lookup(mAddress, aNodeList, &aNode);
550  aContext = aNode->getContext();
551 
552  v.append(aContext);
553  err = accessApplicationLocalDirectory->LookFor(&aNodeList, TTContainerTestObjectAndContext, &v, allObjectsNodes, &aNode);
554 
555  // 2. make a cache containing each relativeAddress : Data and Observer
556  for (allObjectsNodes.begin(); allObjectsNodes.end(); allObjectsNodes.next()) {
557 
558  aNode = TTNodePtr((TTPtr)allObjectsNodes.current()[0]);
559  makeCacheElement(aNode);
560  }
561 
562  // 3. Observe any creation or destruction below the address
563  mObserver = TTObject("callback");
564  baton = TTValue(TTPtr(this), aContext); // théo -- we have to register our self as a #TTPtr to not reference this instance otherwhise the destructor will never be called
565  mObserver.set(kTTSym_baton, baton);
566  mObserver.set(kTTSym_function, TTPtr(&TTContainerDirectoryCallback));
567 
568  accessApplicationLocalDirectory->addObserverForNotifications(mAddress, mObserver); // ask for notification for addresses below
569 
570  return err;
571 }
572 
573 TTErr TTContainer::makeCacheElement(TTNodePtr aNode)
574 {
575  TTValue cacheElement, baton, v, none;
576  TTAddress aRelativeAddress;
577  TTSymbol service;
578  TTObject anObject, empty;
579  TTAttributePtr anAttribute = NULL;
580  TTErr err;
581 
582  // process the relative address
583  aNode->getAddress(aRelativeAddress, mAddress);
584 
585  // Filter none valid object
586  anObject = aNode->getObject();
587  if (!anObject.valid())
588  return kTTErrGeneric;
589 
590  // DEBUG : check if the cache element do not exist already
591  err = mObjectsObserversCache.lookup(aRelativeAddress, cacheElement);
592  if (!err) {
593 
594  // DEBUG : this means there is a bad tree managment : we need to trace this
595  std::cout << "TTContainer::makeCacheElement -- object at " << (const char*)aRelativeAddress.c_str() << " already exists" << std::endl;
596 
597  // DEBUG : remove the former element : this way is bad because we don't free the observer
598  mObjectsObserversCache.remove(aRelativeAddress);
599  }
600 
601  // 0 : cache Object
602  cacheElement.append(anObject);
603 
604  // Special case for Data : observe the Value attribute
605  if (anObject.name() == kTTSym_Data) {
606 
607  // what kind of service the data is used for ?
608  anObject.get(kTTSym_service, v);
609  service = v[0];
610 
611  // we are not supposed to address returns
612  if (service == kTTSym_message) {
613 
614  // 1 : cache empty object
615  cacheElement.append(empty);
616  }
617  else {
618 
619  TTObject valueObserver = TTObject("callback");
620 
621  // create a value Attribute observer on it
622  anObject.instance()->findAttribute(kTTSym_value, &anAttribute);
623 
624  baton = TTValue(TTObject(this), aRelativeAddress);
625 
626  valueObserver.set(kTTSym_baton, baton);
627  valueObserver.set(kTTSym_function, TTPtr(&TTContainerValueAttributeCallback));
628 
629  anAttribute->registerObserverForNotifications(valueObserver);
630 
631  // 1 : cache observer
632  cacheElement.append(valueObserver);
633  }
634  }
635 
636  // Special case for Viewer : observe what it returns
637  else if (anObject.name() == kTTSym_Viewer) {
638 
639  TTObject returnedValueObserver = TTObject("callback");
640 
641  // create a returnedValue Attribute observer on it
642  anObject.instance()->findAttribute(kTTSym_returnedValue, &anAttribute);
643 
644  baton = TTValue(TTObject(this), aRelativeAddress);
645 
646  returnedValueObserver.set(kTTSym_baton, baton);
647  returnedValueObserver.set(kTTSym_function, TTPtr(&TTContainerValueAttributeCallback));
648 
649  anAttribute->registerObserverForNotifications(returnedValueObserver);
650 
651  // 1 : cache observer
652  cacheElement.append(returnedValueObserver);
653  }
654 
655  // Special case for Container : observe his activity
656  else if (anObject.name() == kTTSym_Container) {
657 
658  TTObject activityObserver = TTObject("callback");
659 
660  // create a activity Attribute observer on it
661  anObject.instance()->findAttribute(kTTSym_activity, &anAttribute);
662 
663  baton = TTValue(TTObject(this), aRelativeAddress);
664 
665  activityObserver.set(kTTSym_baton, baton);
666  activityObserver.set(kTTSym_function, TTPtr(&TTContainerValueAttributeCallback));
667 
668  anAttribute->registerObserverForNotifications(activityObserver);
669 
670  // 1 : cache observer
671  cacheElement.append(activityObserver);
672  }
673 
674  // Special case for PresetManager : do nothing ?
675  else if (anObject.name() == kTTSym_PresetManager) {
676 
677  // 1 : cache empty object
678  cacheElement.append(empty);
679  }
680 
681  else
682  // 1 : cache empty object
683  cacheElement.append(empty);
684 
685  // 2 : cache the node too (used during alias creation/destruction)
686  cacheElement.append((TTPtr)aNode);
687 
688  // append the cacheElement to the cache hash table
689  mObjectsObserversCache.append(aRelativeAddress, cacheElement);
690 
691  updateContent();
692 
693  return kTTErrNone;
694 }
695 
696 TTErr TTContainer::deleteCacheElement(TTNodePtr aNode)
697 {
698  TTAddress aRelativeAddress;
699  TTValue v, cacheElement;
700  TTSymbol service;
701  TTObject anObject;
702  TTObject anObserver;
703  TTAttributePtr anAttribute;
704  TTErr err;
705 
706  // process the relative address
707  aNode->getAddress(aRelativeAddress, mAddress);
708 
709  // unregister attribute observers
710  err = mObjectsObserversCache.lookup(aRelativeAddress, cacheElement);
711 
712  if (!err) {
713 
714  // get the object using the node instead of the stored one
715  anObject = aNode->getObject();
716 
717  // Filter none valid object
718  if (anObject.valid()) {
719 
720  // it is a Data
721  if (anObject.name() == kTTSym_Data) {
722 
723  // unregister Value observer for parameter and return
724  anObserver = cacheElement[1];
725  anAttribute = NULL;
726  err = anObject.instance()->findAttribute(kTTSym_value, &anAttribute);
727 
728  if (!err) {
729  err = anAttribute->unregisterObserverForNotifications(anObserver);
730  }
731  }
732 
733  // it is a Viewer
734  else if (anObject.name() == kTTSym_Viewer) {
735 
736  // unregistrer returnedValue observer
737  anObserver = cacheElement[1];
738  anAttribute = NULL;
739  err = anObject.instance()->findAttribute(kTTSym_returnedValue, &anAttribute);
740 
741  if (!err)
742  err = anAttribute->unregisterObserverForNotifications(anObserver);
743  }
744 
745  // it is a Container
746  else if (anObject.name() == kTTSym_Container) {
747 
748  // unregister activity observer
749  anObserver = cacheElement[1];
750  anAttribute = NULL;
751  err = anObject.instance()->findAttribute(kTTSym_activity, &anAttribute);
752 
753  if (!err)
754  err = anAttribute->unregisterObserverForNotifications(anObserver);
755  }
756  }
757 
758  // remove cacheData
759  err = mObjectsObserversCache.remove(aRelativeAddress);
760 
761  updateContent();
762  }
763 
764  return err;
765 }
766 
767 TTErr TTContainer::updateContent()
768 {
769  TTErr err;
770 
771  // update content with all relative address sorted alphabetically
772  err = mObjectsObserversCache.getKeysSorted(mContent);
773 
774  // notify content observers
775  contentAttribute->sendNotification(kTTSym_notify, mContent); // we use kTTSym_notify because we know that observers are TTCallback
776 
777  return err;
778 }
779 
780 TTErr TTContainer::unbind()
781 {
782  TTValue hk, v;
783  TTValue cacheElement;
784  TTObject anObject;
785  TTObject aValueObserver;
786  TTAttributePtr anAttribute;
787  TTSymbol key;
788  TTUInt32 i;
789  TTErr err;
790 
791  // unregister all attribute/message observers of mDatasObserversCache
792  mObjectsObserversCache.getKeys(hk);
793 
794  for (i = 0; i < mObjectsObserversCache.getSize(); i++) {
795 
796  key = hk[i];
797  mObjectsObserversCache.lookup(key, cacheElement);
798  anObject = cacheElement[0];
799 
800  if (anObject.valid()) {
801 
802  // Théo -- the code below is partly the same than deleteCacheElement
803 
804  // is it a Data ?
805  if (anObject.name() == kTTSym_Data) {
806 
807  // unregister value observer
808  aValueObserver = cacheElement[1];
809  anAttribute = NULL;
810  err = anObject.instance()->findAttribute(kTTSym_value, &anAttribute);
811 
812  if (!err)
813  anAttribute->unregisterObserverForNotifications(aValueObserver);
814  }
815  else if (anObject.name() == kTTSym_Viewer) {
816 
817  // unregister returnedValue observer
818  aValueObserver = cacheElement[1];
819  anAttribute = NULL;
820  err = anObject.instance()->findAttribute(kTTSym_returnedValue, &anAttribute);
821 
822  if (!err)
823  anAttribute->unregisterObserverForNotifications(aValueObserver);
824  }
825  else if (anObject.name() == kTTSym_Container) {
826 
827  // unregister activity observer
828  aValueObserver = cacheElement[1];
829  anAttribute = NULL;
830  err = anObject.instance()->findAttribute(kTTSym_activity, &anAttribute);
831 
832  if (!err)
833  anAttribute->unregisterObserverForNotifications(aValueObserver);
834  }
835  }
836  }
837 
838  mObjectsObserversCache.clear();
839 
840  // stop life cycle observation
841  if (mObserver.valid() && accessApplicationLocalDirectory) {
842 
843  accessApplicationLocalDirectory->removeObserverForNotifications(mAddress, mObserver);
844  mObserver = TTObject();
845  }
846 
847  mAddress = kTTAdrsEmpty;
848 
849  return kTTErrNone;
850 }
851 
852 TTErr TTContainer::WriteAsText(const TTValue& inputValue, TTValue& outputValue)
853 {
854  TTObject o = inputValue[0];
855  TTTextHandlerPtr aTextHandler = TTTextHandlerPtr(o.instance());
856  if (!aTextHandler)
857  return kTTErrGeneric;
858 
859  TTString *buffer, toWrite;
860  TTUInt16 i, numInput = 0, numOutput = 0;
861  TTValue keys, cacheElement, s, arg, tags, none;
862  TTSymbol name, service;
863  TTObject anObject;
864 
865  buffer = aTextHandler->mWriter;
866 
867  // html header
868  *buffer = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">";
869  *buffer += "<html>";
870  *buffer += "\t<head>";
871  *buffer += "\t\t<meta http-equiv=\"content-type\" content=\"text/html;charset=UTF-16\">";
872  *buffer += "<title>";
873  *buffer += this->mAddress.c_str();
874  *buffer += "</title>";
875 
876  this->cssDefinition(buffer);
877 
878  *buffer += "\t</head>";
879  *buffer += "";
880 
881  // html body
882  *buffer += "<body>";
883  *buffer += "\t<div id=\"jmod_header\">";
884 
885  // Top of page displaying name of module etc.
886  *buffer += "\t<img src=\"../../../documentation/graphics/jmodular.icon.png\" width=\"128\" height=\"128\">";
887  *buffer += "\t<h1>";
888  *buffer += this->mAddress.c_str();
889  *buffer += "</h1>";
890  *buffer += "\t<h2>";
891  *buffer += this->mDescription.c_str();
892  *buffer += "</h2>";
893 
894  // Menu
895  *buffer += "\t<h6><a href=\"../../../documentation/html/index.html\">Table of Contents</a> | <a href=\"../../../documentation/html/modules.html\">Index of Modules</a> | <a href=\"../../../documentation/html/credits.html\">Credits</a> | <a href=\"http://pledgie.com/campaigns/5615\">Donate</a> | <a href=\"http://www.jamoma.org/\">Jamoma.org</a></h6>";
896  *buffer += "\t</div>";
897  *buffer += "";
898 
899  /*
900  Configuration
901  */
902  tags = mTags;
903  tags.toString();
904  *buffer += "\t<h3> Configuration </h3>";
905  *buffer += "\t<p> Tags : <code>";
906  *buffer += TTString(tags[0]);
907  *buffer += "</code> <br>";
908 
909  mObjectsObserversCache.getKeysSorted(keys);
910 
911  /*
912  Inlets and outlets Objects
913  */
914 
915  for (i = 0; i < keys.size(); i++)
916  {
917  name = keys[i];
918  mObjectsObserversCache.lookup(name, cacheElement);
919  anObject = cacheElement[0];
920 
921  if (anObject.name() == kTTSym_Input || anObject.name() == kTTSym_InputAudio)
922  numInput++;
923 
924  if (anObject.name() == kTTSym_Output || anObject.name() == kTTSym_OutputAudio)
925  numOutput++;
926  }
927 
928  // write the number of inputs
929  s = numInput;
930  s.toString();
931  toWrite = TTString(s[0]);
932  *buffer += "\t<p>Number of signal inlets : <code> ";
933  *buffer += toWrite.data();
934  *buffer += " </code> <br/>";
935 
936  // write the number of outputs
937  s = numOutput;
938  s.toString();
939  toWrite = TTString(s[0]);
940  *buffer += "\t<p>Number of signal outlets : <code> ";
941  *buffer += toWrite;
942  *buffer += " </code> <br/>";
943 
944  /*
945  Data @service parameter
946  */
947  *buffer += "\t<h3> Parameters </h3>";
948  this->dataHeading(buffer);
949 
950  for (i = 0; i < keys.size(); i++)
951  {
952  name = keys[i];
953  mObjectsObserversCache.lookup(name, cacheElement);
954  anObject = cacheElement[0];
955 
956  if (anObject.name() == kTTSym_Data) {
957  anObject.get(kTTSym_service, s);
958  service = s[0];
959 
960  if (service == kTTSym_parameter) {
961  *buffer += "\t\t<tr>";
962  *buffer += "\t\t\t<td class=\"instructionName\"> ";
963  *buffer += name.c_str();
964  *buffer += "</td>";
965 
966  arg = TTValue(anObject);
967  aTextHandler->setAttributeValue(kTTSym_object, arg);
968 
969  anObject.send("WriteAsText", inputValue);
970  *buffer += "\t\t<tr>";
971  }
972  }
973  }
974 
975  // End of table
976  *buffer += "\t</table>";
977  *buffer += "";
978  *buffer += "\t<p>&nbsp;</p>";
979  *buffer += "";
980 
981  /*
982  Data @service message
983  */
984  *buffer += "\t<h3> Messages </h3>";
985  this->dataHeading(buffer);
986 
987  for (i = 0; i < keys.size(); i++)
988  {
989  name = keys[i];
990  mObjectsObserversCache.lookup(name, cacheElement);
991  anObject = cacheElement[0];
992 
993  if (anObject.name() == kTTSym_Data) {
994  anObject.get(kTTSym_service, s);
995  service = s[0];
996 
997  if (service == kTTSym_message) {
998  *buffer += "\t\t<tr>";
999  *buffer += "\t\t\t<td class=\"instructionName\"> ";
1000  *buffer += name.c_str();
1001  *buffer += "</td>";
1002 
1003  arg = TTValue(anObject);
1004  aTextHandler->setAttributeValue(kTTSym_object, arg);
1005 
1006  anObject.send("WriteAsText", inputValue);
1007  *buffer += "\t\t<tr>";
1008  }
1009  }
1010  }
1011 
1012  // End of table
1013  *buffer += "\t</table>";
1014  *buffer += "";
1015  *buffer += "\t<p>&nbsp;</p>";
1016  *buffer += "";
1017 
1018 
1019  /*
1020  Data @service return
1021  */
1022  *buffer += "\t<h3> Returns </h3>";
1023  this->dataHeading(buffer);
1024 
1025  for (i = 0; i < keys.size(); i++)
1026  {
1027  name = keys[i];
1028  mObjectsObserversCache.lookup(name, cacheElement);
1029  anObject = cacheElement[0];
1030 
1031  if (anObject.name() == kTTSym_Data) {
1032  anObject.get(kTTSym_service, s);
1033  service = s[0];
1034 
1035  if (service == kTTSym_return) {
1036  *buffer += "\t\t<tr>";
1037  *buffer += "\t\t\t<td class=\"instructionName\"> ";
1038  *buffer += name.c_str();
1039  *buffer += "</td>";
1040 
1041  arg = TTValue(anObject);
1042  aTextHandler->setAttributeValue(kTTSym_object, arg);
1043 
1044  anObject.send("WriteAsText", inputValue);
1045  *buffer += "\t\t<tr>";
1046  }
1047  }
1048  }
1049 
1050  // End of table
1051  *buffer += "\t</table>";
1052  *buffer += "";
1053  *buffer += "\t<p>&nbsp;</p>";
1054  *buffer += "";
1055 
1056 
1057  // Some final info on Jamoma
1058  *buffer += "\t<h3> About Jamoma </h3>";
1059  *buffer += "\t<p> Jamoma is a system for creating and exchanging structured Max patches. ";
1060  *buffer += "\tIt consists of both a set of guidelines and an implementation of those guidelines. ";
1061  *buffer += "\tFor more information please visit <a href=\"http://jamoma.org/\">jamoma.org</a>. </p> ";
1062 
1063  // End of page
1064  *buffer += "</body>";
1065  *buffer += "</html>";
1066 
1067  return kTTErrNone;
1068 }
1069 
1070 void TTContainer::dataHeading(TTString *buffer)
1071 {
1072  *buffer += "\t<table>";
1073  *buffer += "\t\t<tr class=\"tableHeading2\">";
1074  *buffer += "\t\t\t<td> name </td>";
1075  *buffer += "\t\t\t<td> type </td>";
1076  *buffer += "\t\t\t<td> bounds </td>";
1077  *buffer += "\t\t\t<td> clipmode </td>";
1078  *buffer += "\t\t\t<td> ramp/drive </td>";
1079 #ifndef TT_NO_DSP
1080  *buffer += "\t\t\t<td> ramp/function </td>";
1081 #endif
1082  *buffer += "\t\t\t<td> dataspace </td>";
1083  *buffer += "\t\t\t<td> dataspace/unit </td>";
1084  *buffer += "\t\t\t<td> repetitions/filter </td>";
1085  *buffer += "\t\t\t<td> description </td>";
1086  *buffer += "\t\t<tr>";
1087 }
1088 
1089 void TTContainer::cssDefinition(TTString *buffer)
1090 {
1091  *buffer += "<style type=\"text/css\">";
1092 
1093  *buffer += "\
1094  body {\
1095  margin: 0px;\
1096  font-family: Arial, Helvetica, sans-serif;\
1097  }\
1098  \
1099  h1 {\
1100  font-size: 24px;\
1101  font-weight:100;\
1102  padding-top: 1em;\
1103  margin: 0;\
1104  }\
1105  \
1106  \
1107  h2 {\
1108  font-size: 18px;\
1109  font-weight:200;\
1110  margin: 0;\
1111  color: #555;\
1112  text-transform: lowercase;\
1113  }\
1114  \
1115  h3 {\
1116  color: #888;\
1117  border-bottom: 1px solid #333;\
1118  font-size: 18px;\
1119  font-weight:100;\
1120  margin-top: 20px;\
1121  margin-bottom: 10px;\
1122  margin-left: 2%;\
1123  margin-right: 2%;\
1124  }\
1125  \
1126  h4{\
1127  color: #333;\
1128  font-size: 14px;\
1129  font-weight: bold;\
1130  margin-bottom: 0px;\
1131  margin-left: 2%;\
1132  margin-right: 2%;\
1133  }\
1134  \
1135  h6 {\
1136  font-size: 12px;\
1137  font-weight:100;\
1138  line-height: 1.2;\
1139  margin-right: 2%;\
1140  margin-left: 2%;\
1141  }\
1142  \
1143  p {\
1144  font-size: 12px;\
1145  font-weight:100;\
1146  margin: 5px 2%;\
1147  padding-bottom: 1em;\
1148  }\
1149  \
1150  ul{\
1151  margin-top:0;\
1152  padding-top:0;\
1153  }\
1154  \
1155  li {\
1156  font-size: 12px;\
1157  font-weight:100;\
1158  margin-top: 0;\
1159  margin-left: 10px;\
1160  padding: 0em 0em 0.3em;\
1161  }\
1162  \
1163  img {\
1164  padding: 10px 10px 0px 0px;\
1165  }\
1166  \
1167  \
1168  #jmod_header{\
1169  display: block;\
1170  margin: 0 0 40px 0;\
1171  }\
1172  \
1173  #jmod_header img{\
1174  float: left;\
1175  }\
1176  \
1177  \
1178  .objectname {\
1179  font-size: 24px;\
1180  font-weight: bold;\
1181  }\
1182  \
1183  \
1184  .moduleName {\
1185  font-size: 2em;\
1186  background-color: #c5c5c5;\
1187  text-align: right;\
1188  vertical-align: top;\
1189  font-weight: bold;\
1190  }\
1191  .moduleDescription {\
1192  font-size: 1em;\
1193  background-color: #000000;\
1194  color: #c5c5c5;\
1195  text-align: right;\
1196  vertical-align: top;\
1197  }\
1198  \
1199  .tableHeading2 {\
1200  background-color: #eee;\
1201  text-align: left;\
1202  vertical-align: top;\
1203  font-weight:bold;\
1204  font-size: 12px;\
1205  }\
1206  \
1207  table {\
1208  border: 0px;\
1209  width: 96%;\
1210  margin-top: 10px;\
1211  margin-bottom: 10px;\
1212  margin-left: 2%;\
1213  font-size: 14px;\
1214  }\
1215  ";
1216 
1217  *buffer += "\
1218  \
1219  .instructionName {\
1220  font-family: 'Courier New', Courier, mono;\
1221  background-color: #edd;\
1222  vertical-align: top;\
1223  }\
1224  \
1225  .instructionType {\
1226  font-family: 'Times New Roman', Times, serif;\
1227  background-color: #eee;\
1228  vertical-align: top;\
1229  }\
1230  \
1231  .instructionDataspace {\
1232  font-family: 'Times New Roman', Times, serif;\
1233  background-color: #eed;\
1234  vertical-align: top;\
1235  }\
1236  \
1237  .instructionDataspaceUnit {\
1238  font-family: 'Times New Roman', Times, serif;\
1239  background-color: #eee;\
1240  vertical-align: top;\
1241  }\
1242  \
1243  .instructionRangeBounds {\
1244  font-family: 'Times New Roman', Times, serif;\
1245  background-color: #eed;\
1246  vertical-align: top;\
1247  }\
1248  .instructionRangeClipmode {\
1249  font-family: 'Times New Roman', Times, serif;\
1250  background-color: #eee;\
1251  vertical-align: top;\
1252  }\
1253  .instructionRampDrive {\
1254  font-family: 'Times New Roman', Times, serif;\
1255  background-color: #eed;\
1256  vertical-align: top;\
1257  }\
1258  .instructionRampFunction {\
1259  font-family: 'Times New Roman', Times, serif;\
1260  background-color: #eee;\
1261  vertical-align: top;\
1262  }\
1263  .instructionRepetitionsFilter {\
1264  font-family: 'Times New Roman', Times, serif;\
1265  background-color: #eed;\
1266  vertical-align: top;\
1267  }\
1268  .instructionDescription {\
1269  font-family: 'Times New Roman', Times, serif;\
1270  background-color: #eee;\
1271  vertical-align: top;\
1272  }\
1273  td {\
1274  padding-right: 5px;\
1275  padding-left: 5px;\
1276  }\
1277  ul {\
1278  list-style-type: disc;\
1279  }\
1280  .patchimage {\
1281  clear: both;\
1282  }\
1283  .comment {\
1284  color: #6666FF;\
1285  }\
1286  .smallTable {\
1287  width: 400px;\
1288  border: none;\
1289  }\
1290  caption {\
1291  font-size: 11px;\
1292  font-style: italic;\
1293  }\
1294  .filepath {\
1295  font-family: 'Courier New', Courier, mono;\
1296  }\
1297  .instruction {\
1298  font-family: 'Courier New', Courier, mono;\
1299  }\
1300  ";
1301 
1302  *buffer += "</style>";
1303 }
1304 
1305 #if 0
1306 #pragma mark -
1307 #pragma mark Some Methods
1308 #endif
1309 
1311 {
1312  TTValue arg;
1313  TTContainerPtr aContainer;
1314  TTPtr hisContext;
1315  TTObject anObserver;
1316  TTNodePtr aNode;
1317  TTAddress anAddress;
1318  TTUInt8 flag;
1319 
1320  // unpack baton (a #TTContainerPtr, his Context)
1321  aContainer = TTContainerPtr((TTPtr)baton[0]); // théo -- we have to register our self as a #TTPtr to not reference this instance otherwhise the destructor will never be called
1322  hisContext = baton[1];
1323 
1324  // Unpack data (anAddress, aNode, flag, anObserver)
1325  anAddress = data[0];
1326  aNode = TTNodePtr((TTPtr)data[1]);
1327  flag = data[2];
1328  anObserver = data[3];
1329 
1330  // Prepare argument
1331  arg.append(hisContext);
1332 
1333  switch (flag) {
1334 
1335  case kAddressCreated :
1336  {
1337  if (TTContainerTestObjectAndContext(aNode, &arg))
1338  aContainer->makeCacheElement(aNode);
1339 
1340  break;
1341  }
1342 
1343  case kAddressDestroyed :
1344  {
1345  if (TTContainerTestObjectAndContext(aNode, &arg))
1346  aContainer->deleteCacheElement(aNode);
1347 
1348  break;
1349  }
1350 
1351  default:
1352  break;
1353  }
1354 
1355  return kTTErrNone;
1356 }
1357 
1359 {
1360  TTValue cacheElement, v;
1361  TTObject anObject;
1362  TTObject aContainer;
1363  TTAddress relativeAddress, relativeDataAddress;
1364  TTErr err;
1365 
1366  // check baton
1367  if (baton.size() == 2) {
1368 
1369  if (baton[0].type() == kTypeObject && baton[1].type() == kTypeSymbol) {
1370 
1371  // unpack baton
1372  aContainer = baton[0];
1373  relativeAddress = baton[1];
1374 
1375  if (TTContainerPtr(aContainer.instance())->mReturnAddressCallback.valid() && TTContainerPtr(aContainer.instance())->mReturnValueCallback.valid()) {
1376 
1377  // Check what type of object is notifyng the container
1378  err = TTContainerPtr(aContainer.instance())->mObjectsObserversCache.lookup(relativeAddress, cacheElement);
1379 
1380  if (!err) {
1381 
1382  anObject = cacheElement[0];
1383 
1384  // DEBUG : check if the cached object is still valid
1385  if (!anObject.valid()) {
1386 
1387  // DEBUG : this means there is a bad tree managment : we need to trace this
1388  std::cout << "TTContainerValueAttributeCallback -- object at " << (const char*)relativeAddress.c_str() << " is not valid" << std::endl;
1389 
1390  // DEBUG : we have to exit because it's going to crash
1391  return kTTErrGeneric;
1392  }
1393 
1394  // none CONTAINER CASE
1395  if (anObject.name() != kTTSym_Container) {
1396 
1397  v = data; // protect the data
1398  }
1399  // CONTAINER CASE : activity out observation
1400  // the data is <relativeDataAddress, value, ...>
1401  else {
1402 
1403  relativeDataAddress = data[0];
1404  relativeAddress = relativeAddress.appendAddress(relativeDataAddress);
1405 
1406  v.copyFrom(data, 1); // protect the data
1407  }
1408 
1409  TTValue dummy;
1410 
1411  // return the address to the owner of the #TTContainer
1412  TTContainerPtr(aContainer.instance())->mReturnAddressCallback.send("notify", relativeAddress, dummy);
1413 
1414  // return the value to the owner of the #TTContainer
1415  TTContainerPtr(aContainer.instance())->mReturnValueCallback.send("notify", v, dummy);
1416 
1417  // Notify activity observers (about value changes only)
1418  v.prepend(relativeAddress);
1419  TTContainerPtr(aContainer.instance())->activityAttribute->sendNotification(kTTSym_notify, v); // we use kTTSym_notify because we know that observers are TTCallback
1420 
1421  return kTTErrNone;
1422  }
1423  }
1424  }
1425  }
1426 
1427  return kTTErrGeneric;
1428 }
1429 
1431 {
1432  TTValue v;
1433  TTValuePtr av;
1434  TTPtr c, t_c, p_c = NULL;
1435 
1436  // our context
1437  av = (TTValuePtr)args;
1438  t_c = (*av)[0];
1439 
1440  // context of the tested node
1441  c = n->getContext();
1442 
1443  // context of the parent of the tested node
1444  if (n->getParent())
1445  if (n->getParent()->getName() != S_SEPARATOR)
1446  p_c = n->getParent()->getContext();
1447 
1448  /* to - this doesn't allow data under the root to subscribe to a container at the root
1449 
1450  // Keep only nodes from our context if they aren't under the root (p_c is NULL)
1451  // if contexts are different, check also if the parent context is the same as our context
1452  return (c == t_c && p_c ) || (c != t_c && p_c == t_c );
1453  */
1454 
1455  // Keep only nodes from our context if they have the same context than the container
1456  // if contexts are different, check also if the parent context is the same as our context
1457  return (c == t_c) || (c != t_c && p_c == t_c );
1458 
1459 }
1460 
1462 {
1463  TTSymbol k1, k2;
1464  TTValuePtr s1, s2;
1465  TTObject o1, o2;
1466  TTValue v;
1467  TTInt32 p1 = 0;
1468  TTInt32 p2 = 0;
1469 
1470  // get key and stored value
1471  k1 = v1[0];
1472  k2 = v2[0];
1473  s1 = TTValuePtr(TTPtr(v1[1]));
1474  s2 = TTValuePtr(TTPtr(v2[1]));
1475 
1476  // get priority of the object stored in v1
1477  if (s1) {
1478  o1 = (*s1)[1];
1479  if (o1.valid())
1480  if (!o1.get(kTTSym_priority, v))
1481  p1 = v[0];
1482  }
1483 
1484  // get priority of the object stored in v2
1485  if (s2) {
1486  o2 = (*s2)[1];
1487  if (o2.valid())
1488  if (!o2.get(kTTSym_priority, v))
1489  p2 = v[0];
1490  }
1491 
1492  if (p1 == 0 && p2 == 0) return v1 < v2;
1493 
1494  if (p1 == 0) return NO;
1495  if (p2 == 0) return YES;
1496 
1497  return p1 < p2;
1498 }
TTContainer ...
Definition: TTContainer.h:27
TTAddress appendAddress(const TTAddress &toAppend)
Return a new TTAddress with the appended part.
Definition: TTAddress.h:167
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
TTErr registerObserverForNotifications(const TTObject &observingObject)
Register an observer.
this flag means that a TTNode have been destroyed in the tree structure
Definition: TTAddressBase.h:56
A Container object.
TTErr send(const TTSymbol aName)
Send a message to this object with no arguments.
Definition: TTObject.cpp:135
TTErr getKeysSorted(TTValue &hashKeysSorted, TTBoolean(*comparisonFunction)(TTValue &, TTValue &)=NULL)
Get an array of all of the keys sorted for the hash table.
Definition: TTHash.cpp:148
TTAddress appendAttribute(TTSymbol anAttribute)
Return a new TTAddress with attribute part.
Definition: TTAddress.h:161
TTErr unregisterObserverForNotifications(const TTObject &observingObject)
Unregister an observer for notifications.
TTSymbol & getName()
Get the name of the node.
Definition: TTNode.cpp:286
TTString toString(TTBoolean quotes=YES) const
Return the content as a single string with spaces between elements.
Definition: TTValue.h:351
TTErr lookup(const TTSymbol key, TTValue &value)
Find the value for the given key.
Definition: TTHash.cpp:76
TTBoolean TTContainerTestObjectAndContext(TTNodePtr n, TTPtr args)
#define addAttribute(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom getter...
Definition: TTAttribute.h:29
We build a directory of TTNodes, and you can request a pointer for any TTNode, or add an observer to ...
Definition: TTNode.h:59
void copyFrom(const TTValue &obj, TTUInt16 index)
Copy a value starting from an index until the last element.
Definition: TTValue.h:147
#define accessApplicationFrom(anAddress)
Access to any application using an address.
TTErr AliasRemove(TTAddress alias)
Create an alias address.
TTAddress getParent()
Get a pointer to the parent address.
Definition: TTAddress.h:112
TTPtr getContext()
Get a pointer to the context of this node.
Definition: TTNode.cpp:473
Object type.
Definition: TTBase.h:283
The TTAddress class is used to represent a string and efficiently pass and compare that string...
Definition: TTAddress.h:29
Create and use Jamoma object instances.
Definition: TTObject.h:29
TTObject & getObject()
Get the object binded by this node.
Definition: TTNode.cpp:468
size_type size() const noexcept
Return the number of elements.
TTBoolean TTContainerCompareObjectPriority(TTValue &v1, TTValue &v2)
compare priority attribute of object's
TTErr AliasCreate(TTAddress alias, TTAddress anAddress)
Create an alias address.
TTErr TTContainerValueAttributeCallback(const TTValue &baton, const TTValue &data)
TTUInt32 getSize()
Return the number of keys in the hash table.
Definition: TTHash.cpp:199
TTErr sendNotification(const TTSymbol name, const TTValue &arguments)
Send a notification.
this flag means that an address have no leading slash
Definition: TTAddressBase.h:64
TTErr getKeys(TTValue &hashKeys)
Get an array of all of the keys for the hash table.
Definition: TTHash.cpp:126
This class represents a single attribute, as used by the TTObjectBase class.
Definition: TTAttribute.h:79
TTErr notifyObservers(TTAddress anAddress, TTNodePtr aNode, TTAddressNotificationFlag flag)
Notify life cycle observers that something appends below this TTNode.
friend TTErr TTMODULAR_EXPORT TTContainerValueAttributeCallback(const TTValue &baton, const TTValue &data)
TTErr TTContainerDirectoryCallback(const TTValue &baton, const TTValue &data)
Symbol type.
Definition: TTBase.h:282
This is a special type used by TTAttribute to indicate that a value is a TTValue and is locally maint...
Definition: TTBase.h:286
TTBoolean valid
If the object isn't completely built, or is in the process of freeing, this will be false...
Definition: TTObjectBase.h:124
friend TTErr TTMODULAR_EXPORT TTContainerDirectoryCallback(const TTValue &baton, const TTValue &data)
void prepend(const TTValue &aValueToPrepend)
Insert another TTValue before the first element.
Definition: TTValue.h:162
void append(const T &anElementValueToAppend)
Insert a single TTElement at the end.
Definition: TTValue.h:243
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
TTErr get(const TTSymbol aName, T &aReturnedValue) const
Get an attribute value for an object.
TTSymbol name() const
Return the name of this class.
Definition: TTObject.cpp:129
this flag means that address1 an address2 refer to the same node in the tree structure ...
Definition: TTAddressBase.h:48
TTSymbol & getInstance()
Get the instance of the node.
Definition: TTNode.cpp:291
#define addAttributeProperty(attributeName, propertyName, initialValue)
A convenience macro to be used for registering properties of attributes.
Definition: TTAttribute.h:68
TTErr set(const TTSymbol aName, T aValue)
Set an attribute value for an object.
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
TTErr append(const TTSymbol key, const TTValue &value)
Insert an item into the hash table.
Definition: TTHash.cpp:70
Boolean (1/0) or (true/false) flag.
Definition: TTBase.h:281
TTSymbol & getAttribute()
Get the attribute part.
Definition: TTAddress.h:130
#define addMessageWithArguments(name)
A convenience macro to be used by subclasses for registering messages.
Definition: TTMessage.h:27
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
std::int32_t TTInt32
32 bit signed integer
Definition: TTBase.h:177
TTErr clear()
Remove all items from the hash table.
Definition: TTHash.cpp:117
TTAddressComparisonFlag
Comparison flags between address returned by address1->compare(address2).
Definition: TTAddressBase.h:45
TTErr getAddress(TTAddress &returnedAddress, TTAddress from=kTTAdrsEmpty)
Get the address of the node.
Definition: TTNode.cpp:478
this flag means that address1 refers to a node at a upper level than address2 in the tree structure ...
Definition: TTAddressBase.h:49
32-bit signed integer, range is -2,147,483,648 through 2,147,483,647.
Definition: TTBase.h:277
Something went wrong, but what exactly is not known. Typically used for context-specific problems...
Definition: TTBase.h:344
TTAddressType getType()
Get the type.
Definition: TTAddress.h:136
TTErr remove(const TTSymbol key)
Remove an item from the hash table.
Definition: TTHash.cpp:108
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
signed char TTInt8
8 bit signed integer (char)
Definition: TTBase.h:173
this flag means that a TTNode have been created in the tree structure
Definition: TTAddressBase.h:57
std::uint32_t TTUInt32
32 bit unsigned integer
Definition: TTBase.h:178
TTErr splitAt(TTUInt32 whereToSplit, TTAddress &returnedPart1, TTAddress &returnedPart2)
A parsing tool : split address in two part from a given '/' position.
Definition: TTAddress.h:192
#define addAttributeWithSetter(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom setter...
Definition: TTAttribute.h:47
#define addMessage(name)
A convenience macro to be used by subclasses for registering messages.
Definition: TTMessage.h:19
TTErr getChildren(TTSymbol &name, TTSymbol &instance, TTList &returnedChildren)
Get a linklist of children of the node : select them by name and instance (use wilcards to select the...
Definition: TTNode.cpp:301
TTObjectBase * instance() const
Return a direct pointer to the internal instance.
Definition: TTObject.cpp:105
No Error.
Definition: TTBase.h:343
TTAddressComparisonFlag compare(const TTAddress &toCompare, TTInt8 &depthDifference)
A comparison tool.
Definition: TTAddress.h:182
TTAddress removeAttribute()
Return a new TTAddress without attribute part.
Definition: TTAddress.h:155
The TTString class is used to represent a string.
Definition: TTString.h:34
TTBoolean valid() const
Determine if the object contained by this TTObject is truly ready for use.
Definition: TTObject.cpp:179
We build a tree of TTNodes, and you can request a pointer for any TTNode, or add an observer to any T...
#define accessApplicationLocalDirectory
Access to the local application directory.
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
Bad Attribute specified.
Definition: TTBase.h:348
TTNodePtr getParent()
Get a pointer to the parent node of the node.
Definition: TTNode.cpp:296
TTErr findAttribute(const TTSymbol name, TTAttribute **attr)
Find an attribute.
unsigned char TTUInt8
8 bit unsigned integer (char)
Definition: TTBase.h:174
#define addMessageProperty(messageName, propertyName, initialValue)
A convenience macro to be used for registering properties of messages.
Definition: TTMessage.h:37