HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OP_Bundle.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: OP_Bundle.h ( OP Library, C++)
7  *
8  * COMMENTS: A bundle of OPs. These OPs can span across multiple networks
9  * and are thus heterogeneous (unlike OP_Groups).
10  *
11  * CAVEATS:
12  * Currently, we store the node membership as an int-array. In theory,
13  * this can be changed to use a full-path string array. The interface
14  * should remain the same.
15  *
16  * TODO:
17  * What we want to do in the long run is to have a mechanism to apply
18  * expressions to "filter" the contents of the bundle. Basically, there
19  * should be an expression associated with the bundle. The expression
20  * will define "membership". There will be a bundle of new expression
21  * functions which work on bundles:
22  * bundlematch(string pattern);
23  * Glob the pattern. I'm guessing that the pattern will be
24  * defined on a per-op basis, so that we can handle relative
25  * paths.
26  *
27  * bundleexpand(string bundle_name);
28  * Expand the bundle into a list of op names.
29  *
30  * operator +(bundle, bundle) - Union
31  * operator -(bundle, bundle) - Subtraction
32  * operator ^(bundle, bundle) - Intersection
33  *
34  * bundlefilter(bundle, filter_type)
35  * Filter a bundle according to some pre-defined filter type. For
36  * example "obj/light" (only allow light objects)
37  * Possibly, there will be two expressions, the first is run before the
38  * static list is accumulated. This allows arbitrary OPs to be added
39  * before the hard-coded OPs are processed. The second is run after the
40  * fact, in order to trim the list down. Of course, this may not be the
41  * way it works, this is just a todo.
42  */
43 
44 #ifndef __OP_Bundle__
45 #define __OP_Bundle__
46 
47 #include "OP_API.h"
48 #include "OP_BundleFilter.h"
49 #include "OP_BundlePattern.h"
50 #include "OP_Node.h"
51 #include <UT/UT_Array.h>
52 #include <UT/UT_Notifier.h>
53 #include <UT/UT_String.h>
54 
55 class OP_Network;
56 class OP_Bundle;
57 class OP_Group;
58 class UT_WorkBuffer;
59 
60 // a small class for notifications about bundle events
62 {
63 public:
64 
66  {
67  BUNDLE_RENAMED, // bundle was renamed
68  BUNDLE_PICKED, // bundle was picked
69  BUNDLE_LOCK_CHANGED, // lock on the bundle changed
70  BUNDLE_FILTER_CHANGED, // filter of the bundle changed
71  OP_ADDED, // operator was added to the bundle
72  OP_DELETED, // operator was removed from the bundle
74  OP_RENAMED // operator was renamed
75  };
76 
78  : myEventType( type ), myBundle( bundle ) {}
79 
80  // the event type and originating bundle
83 };
84 
85 
87 public:
88  OP_Bundle(const char *name, int internal=0);
89  ~OP_Bundle();
90 
91  /// Obtains the unique name of the bungle.
92  const char *getName() const { return myName; }
93 
94  /// Determines whether the budnle has been internally created. An internal
95  /// bundle is created in C++ code, based on some pattern string obtained
96  /// from a node's parameter. The non-internal bundles are explicitly created
97  /// by the user and are all listed in the bundle pane.
98  int isInternal() const { return myInternal; }
99 
100  /// Rename the bundle to a new name.
101  void rename(const char *name);
102 
103  /// Processes a new node that has been added to some network. The bundle
104  /// may decide to add that node to itself, if it is a pattern bundle.
105  bool nodeAdded(OP_Node *node);
106 
107  /// Processes a node that is about to be deleted from some network. If that
108  /// node belongs to the bundle, it will be reomved as a member.
109  void nodeDeleted(OP_Node *node);
110 
111  /// Processes a list of nodes that have just been added to some network. Any
112  /// nodes that match the pattern (if set) will be added to the bundle.
113  void bulkNodesAdded(const OP_NodeList &list);
114 
115  /// Informs the bundle that some unspecified nodes have been added or
116  /// deleted. The bundle will mark itself as dirty, if necessary.
117  void nodeAddedDeleted();
118 
119  /// Informs the bundle that some other bundle contents has changed. This
120  /// bundle will mark iself as dirty, if necessary.
121  /// @param bundle_name The name of the other bundle that has changed
122  /// (including the @ signg )
123  void otherBundleChanged(const char *bundle_name);
124 
125  /// Calculates and caches the member nodes that match the specified pattern,
126  /// and other member values (such as myPatternSubnetInclusion)
127  ///
128  /// @param creator The creator network whose descendant nodes (children and
129  /// grand children, etc) are considered for the bundle
130  /// membership.
131  /// @param relativeto The node with respect to which the pattern is
132  /// specified (so that it is possible to resolve
133  /// relative path patterns such as "../sibbling*"
134  /// @param pattern The pattern which the member member nodes must match.
135  void expandPattern(const OP_Network *creator,
136  const OP_Node *relativeto,
137  const char *pattern);
138 
139  /// Removes all the member nodes (or cached nodes and dirties the bundle).
140  void clear();
141 
142  /// Sets a new node filter for the bundle, dirties the bundle, and sends
143  /// out an event.
144  /// @param filter The new filter that influences the membership. It
145  /// accepts some nodes and rejects other.
146  void setFilter(const OP_BundleFilter *filter);
147 
148  /// Returns the current node filter.
150  {
151  return myFilter;
152  }
153 
154  /// Sets the pattern and turn the bundle into a smart bundle, if it is not
155  /// already smart. If the pattern is NULL, the bundle will no longer be
156  /// smart (it will be converted into a normal bundle).
157  void setStringPattern( const char * pattern );
158 
159  /// Returns the pattern originally set on the bundle.
160  const char *getStringPattern() const
161  {
162  return myPattern ? myPattern->buffer()
163  : NULL;
164  }
165 
166  /// Returns the current pattern for nodes. The nodes that match the pattern
167  /// are the members of the bundle.
169  {
170  return myBundlePattern;
171  }
172 
173  /// Mark the bundle pattern as dirty
175  {
176  if (myBundlePattern)
177  myPatternDirty = true;
178  }
179 
180  /// Returns true if the bundle is "smart". That is if it is a non-internal
181  /// bundle whose contents is determined by a pattern.
182  bool isSmart() const
183  {
184  return myPattern && !myInternal;
185  }
186 
187  /// The subnet inclusion flag determines whether a pattern includes subnet
188  /// contents. This means that if a node does not explicitly a member
189  /// of the bundle (ie, does not match the pattern), but its ancestor
190  /// does, then that node is also a member.
191  void setSubnetInclusionFlag(bool onoff);
192 
193  /// Obtains the subnet inclusion flag.
195  { return myPatternSubnetInclusion; }
196 
197  /// Adds the node to the bundle and sends out a notification that a node
198  /// has been added.
199  int addOp(OP_Node *op);
200  int addOp(int unique_id);
201 
202  /// Adds the nodes in the list to the bundle and sends out a
203  /// notification that nodes have been added. If filter or a pattern is set,
204  /// only the nodes that match them will be added.
205  /// @return Returns the number of added nodes .
206  int addOpList(const OP_NodeList &list);
207 
208  /// Removes the node from the bundle and sends out a notification event.
209  int removeOp(OP_Node *op);
210  int removeOp(int unique_id);
211 
212  /// Processes a node when its type (or representative type) has changed.
213  /// The bundle gets marked as dirty if necessary.
214  void refilterOp(OP_Node &node);
215 
216  /// Returns the touch time, which is an integer that gets incremented
217  /// each time the bundle contents changes.
218  int getTouchTime() const { return myTouchTime; }
219 
220  /// Returns a flag that indicates if the bundle tries to automatically add
221  /// newly created nodes to itself.
222  int isLocked() const { return myLockedFlag; }
223  void setLocked(bool onoff);
224 
225  /// Returns the number of member nodes.
226  int entries();
227 
228  /// Returns the i-th member of the bundle. The order is arbitrary, but the
229  /// index should not exceed the number of total entries.
230  OP_Node *getNode(int idx);
231 
232  /// Returns the root node at which the search begins when matching the
233  /// pattern. Only the ancestors (children, grandchildren - that is nodes
234  /// contained in some way by the root) are considered when matching the
235  /// pattern.
236  const OP_Node *getPatternNode() const;
237 
238  /// Returns the node used to resolve relative paths in the pattern.
239  const OP_Node *getRelativeNode() const;
240 
241  /// Sorts the member nodes alphanumerically by node path.
242  void sortByPath();
243 
244  /// Sorts the member nodes by numerical value of the node pointer.
245  void sortByPointer();
246 
247  /// Changes (ie, increases or decreases) the reference count by the given
248  /// amount. When the count decreases to zero, the bundle list (ie, the owner
249  /// of all the bundles) will delete the bundle.
250  void bumpRefCount(int dir) { myRefCount += dir; }
251 
252  /// Returns the current reference count.
253  int getRefCount() const { return myRefCount; }
254 
255  /// Determines whether or not a node is contained in the bundle. If the
256  /// check_representative flag is true, then the node's parents will be
257  /// checked for containment inside the bundle.
258  int contains(const OP_Node *op, bool check_representative);
259  int contains(int unique_id, bool check_representative);
260 
261  /// Builds a string that specifies all the members of the bundle.
262  void buildString(UT_WorkBuffer &buffer, OP_Node *cwd = 0,
263  char delim = ' ');
264 
265  /// Obtains all the bundle member ids.
266  void getMembers(UT_Array<int> &list);
267 
268  /// Obtains all the bundle members as a node list.
269  void getMembers(UT_Array<OP_Node *> &list);
270 
271  /// Obtains the union of the member nodes from all the given bundles.
272  /// The nodes in the result list are unique.
273  static void getAllMembers(const UT_Array<OP_Bundle *> &bundles,
274  UT_Array<OP_Node *> &nodes);
275 
276  /// For undo mechanism only. Don't go mucking with the array please
277  /// @private
278  const UT_Array<int> &undoGetMembers() const { return myNodes; }
279  void undoSetMembers(UT_Array<int> &nodes);
280 
281  /// For undo mechanism only. Don't emit events whenever you feel like
282  /// (otherwise it would be private)
283  /// @private
284  void emitEvent( OP_BundleEvent::OP_EventType type );
285 
286  /// Adds a node interest to the bundle. If the bundle changes, it will
287  /// alert all the nodes that expressed interest in it by calling
288  /// bundleChanged() on it. This is a separate notification mechanism
289  /// from passing the OP_BundleEvent via myEventNotifier.
290  /// @param add_id The node id of the interested node.
291  void addInterest(int add_id);
292 
293  /// Removes the node interest from the bundle.
294  /// @param remove_id The node id that is no longer interested in bundle.
295  void removeInterest(int remove_id);
296 
297  /// Adds a parameter interest to the bundle. If the bundle changes,
298  /// it will alert all the parameter channels by calling parmChanged()
299  /// on the node with parm id. This is a separate notification mechanism
300  /// from passing the OP_BundleEvent via myEventNotifier.
301  /// @param add_id The node id of the interested node.
302  /// @param parm_id The id (index) of the referencing parameter
303  void addParmInterest(int node_id, int parm_id);
304 
305  /// Removes the parameter interest from the bundle.
306  /// @param add_id The node id of the interested node.
307  /// @param parm_id The id (index) of the referencing parameter
308  void removeParmInterest(int node_id, int parm_id);
309 
310  /// Processes the given group after it has changed. If any bundles
311  /// reference this group, the will be marked as dirty.
312  static void notifyOpsOfGroupChange(OP_Group *group);
313 
314  /// Sets the picked (selected) flag to on/off.
315  int setPicked(int on_off);
316 
317  /// Returns the current pick (selected) flag.
318  int getPicked() const { return myPickedFlag; }
319 
320  /// Returns an object that emmits events originating from the bundle
321  /// when something about the bundle changes.
323  &getEventNotifier() { return myEventNotifier; }
324 
325  /// Converts the normal bundle to a smart bundle by using the members
326  /// of the bundle to constuct a pattern that will match all of the
327  /// current members and only the current members.
328  void convertToSmartBundle(UT_String* finalpattern);
329 
330 
331 public: // convenience methods that operate on all members of a bundle
332  /// Sets the flag on on all the members of this bundle.
333  void setOpsFlag(char flagchar, int onoff,
334  bool propagate_to_ancestors = false);
335 
336  /// sets op visibility. This is smarter than just truning the display
337  /// flag. It also adds to the visible children parameter of the ancestors
338  /// so that the bundle nodes become visibile.
339  void setOpsVisibility( bool onoff );
340 
341  /// Syncs (if sync_flag == true) and unsyncs (if sync_flag == false )
342  /// the HDA definitions of the nodes contained in this bundle.
343  void syncOpOTLs( bool sync_flag,
344  bool propagate_to_ancestors = false);
345 
346 private:
347  /// Tests a single pattern to see if it the pattern catches anything that
348  /// is not in the bundle.
349  bool testPattern(UT_String pattern, const OP_Node* node);
350 
351  /// The bundle is defined by the asterisk pattern, so we can do faster
352  /// checks which don't require building the node list.
353  bool checkAsteriskPattern(int unique_id) const;
354 
355  /// Finds the longest common prefix and the longest common suffix of an
356  /// array of patterns and then combines then with single level wildcard
357  /// separators.
358  /// Ex.: paths = ("/obj/box_object1/section1/obj1",
359  /// "/obj/sphere_object2/section2/obj1")
360  /// will result in:
361  /// prefix = /obj/
362  /// suffix = /obj1
363  /// resultpattern = /obj/%/obj1
364  ///
365  void combineIxes(UT_StringArray& paths,
366  UT_String* resultpattern,
367  UT_String* prefix, UT_String* suffix);
368 
369  /// Constructs a pattern that will match all of the nodes at one specific
370  /// depth
371  void constructSinglePattern(UT_String* resultpattern,
372  UT_StringArray& paths);
373 
374  /// This function will determine whether each level of the regex is
375  /// is independent of the subsequent levels, if they are independent, they can
376  /// be isolated and handled separately.
377  UT_String checkLevelIndependence(
378  UT_Array<UT_StringArray>* pathsbylevel,
379  UT_String prefix, UT_String suffix);
380 
381  /// This function takes independent chunks of the regex and shortens them
382  /// as possible.
383  UT_String shortenIndependents(
384  UT_Array<UT_StringArray>& pathsbylevel,
385  UT_String prefix, UT_String suffix);
386 
387  /// Constructs an array where the the members of the Bundle are separated
388  /// by the depth of their full path.
389  /// Ex.: If the bundle contains ("/obj", "/obj/box1", "/obj/box2")
390  /// The resulting array would be:
391  /// pathsbylength(0) = empty
392  /// pathsbylength(1) = ("/obj")
393  /// pathsbylength(2) = ("/obj/box1", "/obj/box2")
394  void getPathsByLength(
395  UT_Array<UT_StringArray>* pathsbylength);
396 
397  /// Precondition: all strings in paths must be the same depth
398  /// Will populate a list of paths by level. The nth entry of the ref array
399  /// contains a list of all of the substrings at the n'th level of depth from
400  /// each element of paths.
401  void getPathsByLevel(UT_StringArray& paths,
402  UT_Array<UT_StringArray>* pathsbylevel,
403  UT_String prefix, UT_String suffix);
404 
405  /// Converts the smart bundle to a normal bundle by removing
406  /// its defining pattern (if any). The member list in the bundle
407  /// remains the same. A bundle with no defining pattern is already
408  /// a normal bundle.
409  void convertToNormalBundle();
410 
411  /// Checks whether the specified node matches both the
412  /// filter and the pattern of the bundle.
413  bool isNodeValid( OP_Node *node,
414  const OP_Node *relativeto ) const;
415  /// Removes duplicate nodes in the member list.
416  void removeDuplicates();
417 
418  /// Iterates through the nodes (and parameters) that registered the
419  /// interest in the bundle and notifies them of the bundle change.
420  void notifyOpsOfChange( OP_BundleEvent::OP_EventType type );
421 
422  /// Resets the notification flag, so any changes to the bundle will
423  /// trigger event notifications, because the bundle is being evaluated.
424  void bundleEvaluated() { myNotifiedFlag = 0; }
425 
426  /// Dirties the bundle to indicate that something about the bundle has
427  /// changed, and the bundle needs re-evaluation.
428  void touch();
429 
430  /// Re-evaluate the bundle membership based on the pattern, which basically
431  /// searched for (and caches) all the nodes that match the pattern.
432  void buildPattern();
433 
434  /// Refreshes the bundle membership nodes, if necessary.
435  void refreshPattern() {
436  if (myPatternDirty && myPattern)
437  buildPattern();
438  }
439  /// Refreshes the bundle membership nodes if necessary and removes any
440  /// duplicate nodes tha may have been doubly-added to the bundle.
441  void refresh() { refreshPattern(); removeDuplicates(); }
442 
443  /// Marks the sort order as dirty.
444  void dirtyAllSorts()
445  { myPathSortDirty = myPtrSortDirty = 1; }
446 
447  /// Returns true if this bundle contains a node that is a parent of the
448  /// node given by unique_id and also matches the filter. In other words,
449  /// returns true if this bundle contains unique_id implicitly by containing
450  /// its parent subnet which has a representative matching the filter.
451  bool containsAsRepresentative(int unique_id);
452 
453 
454 private:
455  /// Unique bundle name.
456  char *myName;
457 
458  /// Pattern string that defines the bundle.
459  /// If null, the bundle is not defined by pattern.
460  UT_String *myPattern;
461 
462  /// Pattern object capable of matching the nodes; it is computed based
463  /// on the myPattern member and then cached here. If this member is
464  /// null, the bundle still may be a pattern bundle that has not been
465  /// evaluated (expanded) yet.
466  OP_BundlePattern *myBundlePattern;
467 
468  const OP_BundleFilter *myFilter; // filter for member nodes
469  UT_Array<int> myNodes; // member nodes
470  UT_Array<int> myInterests; // nodes interested in bndle
471  UT_Array<int> myParmInterests; // parms interested in bndle
472  UT_Array<int> myNodeInterests; // .. nodes that own parms
473  int myRefCount; // bundle reference count
474  int myPatternNode; // root of node search tree
475  int myRelativeNode; // reolves relative paths
476  int myTouchTime; // increments at each change
477  int myRemoveDups; // duplication removal flag
478 
479  // object that notifies about bundle events
480  UT_NotifierImpl<OP_BundleEvent&> myEventNotifier;
481 
482  uint myInternal:1, // Internal bundle or user defined
483  myExpanding:1, // Recursion flag check
484  myPatternDirty:1, // Pattern expansion is out of date
485  myPatternSubnetInclusion:1, // Whether, unless explicitly
486  // excluded, subnet contents are
487  // included with the subnet.
488  // locked bundle does not add any newly created nodes that
489  // match the filter; the unlocked bundle does.
490  myLockedFlag:1, // Bundle is locked
491  myPathSortDirty:1, // Is path sort dirty
492  myPtrSortDirty:1, // Is pointer sort dirty
493  myNotifiedFlag:1, // I've already notified objects
494  myPickedFlag:1, // bundle is picked (selected)
495  myBulkAdding:1; // Performing bulk addition
496 };
497 
498 #endif
int isInternal() const
Definition: OP_Bundle.h:98
myNodes
Definition: UT_RTreeImpl.h:708
int getTouchTime() const
Definition: OP_Bundle.h:218
const char * getName() const
Obtains the unique name of the bungle.
Definition: OP_Bundle.h:92
void setBundlePatternDirty()
Mark the bundle pattern as dirty.
Definition: OP_Bundle.h:174
const OP_BundlePattern * getBundlePattern() const
Definition: OP_Bundle.h:168
const char * getStringPattern() const
Returns the pattern originally set on the bundle.
Definition: OP_Bundle.h:160
Definition: core.h:760
void bumpRefCount(int dir)
Definition: OP_Bundle.h:250
OP_Bundle & myBundle
Definition: OP_Bundle.h:82
GLuint const GLchar * name
Definition: glcorearb.h:786
GLushort pattern
Definition: glad.h:2583
const OP_BundleFilter * getFilter()
Returns the current node filter.
Definition: OP_Bundle.h:149
OIIO_UTIL_API bool rename(string_view from, string_view to, std::string &err)
int isLocked() const
Definition: OP_Bundle.h:222
#define OP_API
Definition: OP_API.h:10
int getPicked() const
Returns the current pick (selected) flag.
Definition: OP_Bundle.h:318
UT_NotifierImpl< OP_BundleEvent & > & getEventNotifier()
Definition: OP_Bundle.h:323
int getRefCount() const
Returns the current reference count.
Definition: OP_Bundle.h:253
bool isSmart() const
Definition: OP_Bundle.h:182
bool OIIO_UTIL_API contains(string_view a, string_view b)
Does 'a' contain the string 'b' within it?
type
Definition: core.h:1059
unsigned int uint
Definition: SYS_Types.h:45
int getSubnetInclusionFlag() const
Obtains the subnet inclusion flag.
Definition: OP_Bundle.h:194
OP_BundleEvent(OP_EventType type, OP_Bundle &bundle)
Definition: OP_Bundle.h:77
OP_EventType myEventType
Definition: OP_Bundle.h:81
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1297