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