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 UT_StringHolder& 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  /// The ignore case flag determines whether node name matching against the
198  /// pattern is case-insensitive.
199  void setIgnoreCase(bool onoff);
200 
201  /// Obtains the ignore case flag.
202  bool getIgnoreCase() const
203  { return myIgnoreCase; }
204 
205  /// Adds the node to the bundle and sends out a notification that a node
206  /// has been added.
207  int addOp(OP_Node *op);
208  int addOp(int unique_id);
209 
210  /// Adds the nodes in the list to the bundle and sends out a
211  /// notification that nodes have been added. If filter or a pattern is set,
212  /// only the nodes that match them will be added.
213  /// @return Returns the number of added nodes .
214  int addOpList(const OP_NodeList &list);
215 
216  /// Removes the node from the bundle and sends out a notification event.
217  int removeOp(OP_Node *op);
218  int removeOp(int unique_id);
219 
220  /// Processes a node when its type (or representative type) has changed.
221  /// The bundle gets marked as dirty if necessary.
222  void refilterOp(OP_Node &node);
223 
224  /// Returns the touch time, which is an integer that gets incremented
225  /// each time the bundle contents changes.
226  int getTouchTime() const { return myTouchTime; }
227 
228  /// Returns a flag that indicates if the bundle tries to automatically add
229  /// newly created nodes to itself.
230  int isLocked() const { return myLockedFlag; }
231  void setLocked(bool onoff);
232 
233  /// Returns the number of member nodes.
234  int entries();
235 
236  /// Returns the i-th member of the bundle. The order is arbitrary, but the
237  /// index should not exceed the number of total entries.
238  OP_Node *getNode(int idx);
239 
240  /// Returns the root node at which the search begins when matching the
241  /// pattern. Only the ancestors (children, grandchildren - that is nodes
242  /// contained in some way by the root) are considered when matching the
243  /// pattern.
244  const OP_Node *getPatternNode() const;
245 
246  /// Returns the node used to resolve relative paths in the pattern.
247  const OP_Node *getRelativeNode() const;
248 
249  /// Sorts the member nodes alphanumerically by node path.
250  void sortByPath();
251 
252  /// Sorts the member nodes by numerical value of the node pointer.
253  void sortByPointer();
254 
255  /// Changes (ie, increases or decreases) the reference count by the given
256  /// amount. When the count decreases to zero, the bundle list (ie, the owner
257  /// of all the bundles) will delete the bundle.
258  void bumpRefCount(int dir) { myRefCount += dir; }
259 
260  /// Returns the current reference count.
261  int getRefCount() const { return myRefCount; }
262 
263  /// Determines whether or not a node is contained in the bundle. If the
264  /// check_representative flag is true, then the node's parents will be
265  /// checked for containment inside the bundle.
266  int contains(const OP_Node *op, bool check_representative);
267  int contains(int unique_id, bool check_representative);
268 
269  /// Builds a string that specifies all the members of the bundle.
270  void buildString(UT_WorkBuffer &buffer, OP_Node *cwd = 0,
271  char delim = ' ');
272 
273  /// Obtains all the bundle member ids.
274  void getMembers(UT_Array<int> &list);
275 
276  /// Obtains all the bundle members as a node list.
277  void getMembers(UT_Array<OP_Node *> &list);
278 
279  /// Obtains the union of the member nodes from all the given bundles.
280  /// The nodes in the result list are unique.
281  static void getAllMembers(const UT_Array<OP_Bundle *> &bundles,
282  UT_Array<OP_Node *> &nodes);
283 
284  /// For undo mechanism only. Don't go mucking with the array please
285  /// @private
286  const UT_Array<int> &undoGetMembers() const { return myNodes; }
287  void undoSetMembers(UT_Array<int> &nodes);
288 
289  /// For undo mechanism only. Don't emit events whenever you feel like
290  /// (otherwise it would be private)
291  /// @private
292  void emitEvent( OP_BundleEvent::OP_EventType type );
293 
294  /// Adds a node interest to the bundle. If the bundle changes, it will
295  /// alert all the nodes that expressed interest in it by calling
296  /// bundleChanged() on it. This is a separate notification mechanism
297  /// from passing the OP_BundleEvent via myEventNotifier.
298  /// @param add_id The node id of the interested node.
299  void addInterest(int add_id);
300 
301  /// Removes the node interest from the bundle.
302  /// @param remove_id The node id that is no longer interested in bundle.
303  void removeInterest(int remove_id);
304 
305  /// Adds a parameter interest to the bundle. If the bundle changes,
306  /// it will alert all the parameter channels by calling parmChanged()
307  /// on the node with parm id. This is a separate notification mechanism
308  /// from passing the OP_BundleEvent via myEventNotifier.
309  /// @param add_id The node id of the interested node.
310  /// @param parm_id The id (index) of the referencing parameter
311  void addParmInterest(int node_id, int parm_id);
312 
313  /// Removes the parameter interest from the bundle.
314  /// @param add_id The node id of the interested node.
315  /// @param parm_id The id (index) of the referencing parameter
316  void removeParmInterest(int node_id, int parm_id);
317 
318  /// Processes the given group after it has changed. If any bundles
319  /// reference this group, the will be marked as dirty.
320  static void notifyOpsOfGroupChange(OP_Group *group);
321 
322  /// Sets the picked (selected) flag to on/off.
323  int setPicked(int on_off);
324 
325  /// Returns the current pick (selected) flag.
326  int getPicked() const { return myPickedFlag; }
327 
328  /// Returns an object that emmits events originating from the bundle
329  /// when something about the bundle changes.
331  &getEventNotifier() { return myEventNotifier; }
332 
333  /// Converts the normal bundle to a smart bundle by using the members
334  /// of the bundle to constuct a pattern that will match all of the
335  /// current members and only the current members.
336  void convertToSmartBundle(UT_String* finalpattern);
337 
338 
339 public: // convenience methods that operate on all members of a bundle
340  /// Sets the flag on on all the members of this bundle.
341  void setOpsFlag(char flagchar, int onoff,
342  bool propagate_to_ancestors = false);
343 
344  /// sets op visibility. This is smarter than just truning the display
345  /// flag. It also adds to the visible children parameter of the ancestors
346  /// so that the bundle nodes become visibile.
347  void setOpsVisibility( bool onoff );
348 
349  /// Syncs (if sync_flag == true) and unsyncs (if sync_flag == false )
350  /// the HDA definitions of the nodes contained in this bundle.
351  void syncOpOTLs( bool sync_flag,
352  bool propagate_to_ancestors = false);
353 
354 private:
355  /// Tests a single pattern to see if it the pattern catches anything that
356  /// is not in the bundle.
357  bool testPattern(UT_String pattern, const OP_Node* node);
358 
359  /// The bundle is defined by the asterisk pattern, so we can do faster
360  /// checks which don't require building the node list.
361  bool checkAsteriskPattern(int unique_id) const;
362 
363  /// Finds the longest common prefix and the longest common suffix of an
364  /// array of patterns and then combines then with single level wildcard
365  /// separators.
366  /// Ex.: paths = ("/obj/box_object1/section1/obj1",
367  /// "/obj/sphere_object2/section2/obj1")
368  /// will result in:
369  /// prefix = /obj/
370  /// suffix = /obj1
371  /// resultpattern = /obj/%/obj1
372  ///
373  void combineIxes(UT_StringArray& paths,
374  UT_String* resultpattern,
375  UT_String* prefix, UT_String* suffix);
376 
377  /// Constructs a pattern that will match all of the nodes at one specific
378  /// depth
379  void constructSinglePattern(UT_String* resultpattern,
380  UT_StringArray& paths);
381 
382  /// This function will determine whether each level of the regex is
383  /// is independent of the subsequent levels, if they are independent, they can
384  /// be isolated and handled separately.
385  UT_String checkLevelIndependence(
386  UT_Array<UT_StringArray>* pathsbylevel,
387  UT_String prefix, UT_String suffix);
388 
389  /// This function takes independent chunks of the regex and shortens them
390  /// as possible.
391  UT_String shortenIndependents(
392  UT_Array<UT_StringArray>& pathsbylevel,
393  UT_String prefix, UT_String suffix);
394 
395  /// Constructs an array where the the members of the Bundle are separated
396  /// by the depth of their full path.
397  /// Ex.: If the bundle contains ("/obj", "/obj/box1", "/obj/box2")
398  /// The resulting array would be:
399  /// pathsbylength(0) = empty
400  /// pathsbylength(1) = ("/obj")
401  /// pathsbylength(2) = ("/obj/box1", "/obj/box2")
402  void getPathsByLength(
403  UT_Array<UT_StringArray>* pathsbylength);
404 
405  /// Precondition: all strings in paths must be the same depth
406  /// Will populate a list of paths by level. The nth entry of the ref array
407  /// contains a list of all of the substrings at the n'th level of depth from
408  /// each element of paths.
409  void getPathsByLevel(UT_StringArray& paths,
410  UT_Array<UT_StringArray>* pathsbylevel,
411  UT_String prefix, UT_String suffix);
412 
413  /// Converts the smart bundle to a normal bundle by removing
414  /// its defining pattern (if any). The member list in the bundle
415  /// remains the same. A bundle with no defining pattern is already
416  /// a normal bundle.
417  void convertToNormalBundle();
418 
419  /// Checks whether the specified node matches both the
420  /// filter and the pattern of the bundle.
421  bool isNodeValid( OP_Node *node,
422  const OP_Node *relativeto ) const;
423  /// Removes duplicate nodes in the member list.
424  void removeDuplicates();
425 
426  /// Iterates through the nodes (and parameters) that registered the
427  /// interest in the bundle and notifies them of the bundle change.
428  void notifyOpsOfChange( OP_BundleEvent::OP_EventType type );
429 
430  /// Resets the notification flag, so any changes to the bundle will
431  /// trigger event notifications, because the bundle is being evaluated.
432  void bundleEvaluated() { myNotifiedFlag = 0; }
433 
434  /// Dirties the bundle to indicate that something about the bundle has
435  /// changed, and the bundle needs re-evaluation.
436  void touch();
437 
438  /// Re-evaluate the bundle membership based on the pattern, which basically
439  /// searched for (and caches) all the nodes that match the pattern.
440  void buildPattern();
441 
442  /// Refreshes the bundle membership nodes, if necessary.
443  void refreshPattern() {
444  if (myPatternDirty && myPattern)
445  buildPattern();
446  }
447  /// Refreshes the bundle membership nodes if necessary and removes any
448  /// duplicate nodes tha may have been doubly-added to the bundle.
449  void refresh() { refreshPattern(); removeDuplicates(); }
450 
451  /// Marks the sort order as dirty.
452  void dirtyAllSorts()
453  { myPathSortDirty = myPtrSortDirty = 1; }
454 
455  /// Returns true if this bundle contains a node that is a parent of the
456  /// node given by unique_id and also matches the filter. In other words,
457  /// returns true if this bundle contains unique_id implicitly by containing
458  /// its parent subnet which has a representative matching the filter.
459  bool containsAsRepresentative(int unique_id);
460 
461 
462 private:
463  /// Unique bundle name.
464  UT_StringHolder myName;
465 
466  /// Pattern string that defines the bundle.
467  /// If null, the bundle is not defined by pattern.
468  UT_String *myPattern;
469 
470  /// Pattern object capable of matching the nodes; it is computed based
471  /// on the myPattern member and then cached here. If this member is
472  /// null, the bundle still may be a pattern bundle that has not been
473  /// evaluated (expanded) yet.
474  OP_BundlePattern *myBundlePattern;
475 
476  const OP_BundleFilter *myFilter; // filter for member nodes
477  UT_Array<int> myNodes; // member nodes
478  UT_Array<int> myInterests; // nodes interested in bndle
479  UT_Array<int> myParmInterests; // parms interested in bndle
480  UT_Array<int> myNodeInterests; // .. nodes that own parms
481  int myRefCount; // bundle reference count
482  int myPatternNode; // root of node search tree
483  int myRelativeNode; // reolves relative paths
484  int myTouchTime; // increments at each change
485  int myRemoveDups; // duplication removal flag
486 
487  // object that notifies about bundle events
488  UT_NotifierImpl<OP_BundleEvent&> myEventNotifier;
489 
490  uint myInternal:1, // Internal bundle or user defined
491  myExpanding:1, // Recursion flag check
492  myPatternDirty:1, // Pattern expansion is out of date
493  myPatternSubnetInclusion:1, // Whether, unless explicitly
494  // excluded, subnet contents are
495  // included with the subnet.
496  // locked bundle does not add any newly created nodes that
497  // match the filter; the unlocked bundle does.
498  myLockedFlag:1, // Bundle is locked
499  myPathSortDirty:1, // Is path sort dirty
500  myPtrSortDirty:1, // Is pointer sort dirty
501  myNotifiedFlag:1, // I've already notified objects
502  myPickedFlag:1, // bundle is picked (selected)
503  myBulkAdding:1, // Performing bulk addition
504  myIgnoreCase:1; // Case-insensitive pattern matching
505 };
506 
507 #endif
int isInternal() const
Definition: OP_Bundle.h:98
myNodes
Definition: UT_RTreeImpl.h:708
bool getIgnoreCase() const
Obtains the ignore case flag.
Definition: OP_Bundle.h:202
int getTouchTime() const
Definition: OP_Bundle.h:226
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
GLuint buffer
Definition: glcorearb.h:660
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
void bumpRefCount(int dir)
Definition: OP_Bundle.h:258
const UT_StringHolder & getName() const
Obtains the unique name of the bungle.
Definition: OP_Bundle.h:92
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:230
#define OP_API
Definition: OP_API.h:10
int getPicked() const
Returns the current pick (selected) flag.
Definition: OP_Bundle.h:326
UT_NotifierImpl< OP_BundleEvent & > & getEventNotifier()
Definition: OP_Bundle.h:331
int getRefCount() const
Returns the current reference count.
Definition: OP_Bundle.h:261
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?
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