1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_USD_USD_NOTICE_H
25 #define PXR_USD_USD_NOTICE_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/usd/api.h"
29 #include "pxr/usd/usd/common.h"
30 #include "pxr/usd/usd/object.h"
31 
32 #include "pxr/usd/sdf/changeList.h"
33 #include "pxr/usd/sdf/path.h"
34 #include "pxr/base/tf/notice.h"
35 
36 PXR_NAMESPACE_OPEN_SCOPE
37 
38 
39 /// \class UsdNotice
40 ///
41 /// Container class for Usd notices
42 ///
43 class UsdNotice {
44 public:
45 
46     /// Base class for UsdStage notices.
47     class StageNotice : public TfNotice {
48     public:
49         USD_API
50         StageNotice(const UsdStageWeakPtr &stage);
51         USD_API
52         virtual ~StageNotice();
53 
54         /// Return the stage associated with this notice.
GetStage()55         const UsdStageWeakPtr &GetStage() const { return _stage; }
56 
57     private:
58         UsdStageWeakPtr _stage;
59     };
60 
61     /// \class StageContentsChanged
62     ///
63     /// Ultra-conservative notice sent when the given UsdStage's contents
64     /// have changed in any way.  This notice is sent when \em any authoring
65     /// is performed in any of the stage's participatory layers, in the
66     /// thread performing the authoring, \em after the affected UsdStage
67     /// has reconfigured itself in response to the authored changes.
68     ///
69     /// Receipt of this notice should cause clients to disregard any cached
70     /// values for properties or metadata.  It does not \em necessarily imply
71     /// invalidation of UsdPrim s.
72     ///
73     class StageContentsChanged : public StageNotice {
74     public:
StageContentsChanged(const UsdStageWeakPtr & stage)75         explicit StageContentsChanged(const UsdStageWeakPtr& stage)
76             : StageNotice(stage) {}
77         USD_API virtual ~StageContentsChanged();
78     };
79 
80     /// \class ObjectsChanged
81     ///
82     /// Notice sent in response to authored changes that affect UsdObjects.
83     ///
84     /// The kinds of object changes are divided into two categories: "resync"
85     /// and "changed-info".  "Resyncs" are potentially structural changes that
86     /// invalidate entire subtrees of UsdObjects (including prims and
87     /// properties).  For example, if the path "/foo" is resynced, then all
88     /// subpaths like "/foo/bar" and "/foo/bar.baz" may be arbitrarily changed.
89     /// In contrast, "changed-info" means that a nonstructural change has
90     /// occurred, like an attribute value change or a value change to a metadata
91     /// field not related to composition.
92     ///
93     /// When a prim is resynced, say "/foo/bar", it might have been created or
94     /// destroyed.  In that case "/foo"'s list of children will have changed,
95     /// but we *do not* consider "/foo" to be resynced.  If we did, it would
96     /// mean clients would have to consider all of "/foo/bar"'s siblings (and
97     /// their descendants) to be resynced which might be egregious
98     /// overinvalidation.
99     ///
100     /// This notice provides API for two client use-cases.  Clients interested
101     /// in testing whether specific objects are affected by the changes should
102     /// use the AffectedObject() method (and the ResyncedObject() and
103     /// ChangedInfoOnly() methods).  Clients that wish to reason about all
104     /// changes as a whole should use the GetResyncedPaths() and
105     /// GetChangedInfoOnlyPaths() methods.
106     ///
107     class ObjectsChanged : public StageNotice {
108         using _PathsToChangesMap =
109             std::map<SdfPath, std::vector<const SdfChangeList::Entry*>>;
110 
111         friend class UsdStage;
ObjectsChanged(const UsdStageWeakPtr & stage,const _PathsToChangesMap * resyncChanges,const _PathsToChangesMap * infoChanges)112         ObjectsChanged(const UsdStageWeakPtr &stage,
113                        const _PathsToChangesMap *resyncChanges,
114                        const _PathsToChangesMap *infoChanges)
115             : StageNotice(stage)
116             , _resyncChanges(resyncChanges)
117             , _infoChanges(infoChanges) {}
118     public:
119         USD_API virtual ~ObjectsChanged();
120 
121         /// Return true if \p obj was possibly affected by the layer changes
122         /// that generated this notice.  This is the case if either the object
123         /// is subject to a resync or has changed info.  Equivalent to:
124         /// \code
125         /// ResyncedObject(obj) or ChangedInfoOnly(obj)
126         /// \endcode
AffectedObject(const UsdObject & obj)127         bool AffectedObject(const UsdObject &obj) const {
128             return ResyncedObject(obj) || ChangedInfoOnly(obj);
129         }
130 
131         /// Return true if \p obj was resynced by the layer changes that
132         /// generated this notice.  This is the case if the object's path or an
133         /// ancestor path is present in GetResyncedPrimPaths().
134         USD_API bool ResyncedObject(const UsdObject &obj) const;
135 
136         /// Return true if \p obj was changed but not resynced by the layer
137         /// changes that generated this notice.
138         USD_API bool ChangedInfoOnly(const UsdObject &obj) const;
139 
140         /// \class PathRange
141         /// An iterable range of paths to objects that have changed.
142         ///
143         /// Users may use this object in range-based for loops, or use the
144         /// iterators to access additional information about each changed
145         /// object.
146         class PathRange
147         {
148         public:
149             /// \class iterator
150             class iterator : public boost::iterator_adaptor<
151                 iterator,                           // crtp base,
152                 _PathsToChangesMap::const_iterator, // base iterator
153                 const SdfPath&                      // value type
154             >
155             {
156             public:
iterator()157                 iterator()
158                     : iterator_adaptor_(base_type()) {}
159 
160                 /// Return the set of changed fields in layers that affected
161                 /// the object at the path specified by this iterator.  See
162                 /// UsdNotice::ObjectsChanged::GetChangedFields for more
163                 /// details.
164                 USD_API TfTokenVector GetChangedFields() const;
165 
166                 /// Return true if the object at the path specified by this
167                 /// iterator has any changed fields, false otherwise.  See
168                 /// UsdNotice::ObjectsChanged::HasChangedFields for more
169                 /// details.
170                 USD_API bool HasChangedFields() const;
171 
172             private:
173                 friend class PathRange;
174                 friend class boost::iterator_core_access;
175 
iterator(base_type baseIter)176                 iterator(base_type baseIter)
177                     : iterator_adaptor_(baseIter) {}
dereference()178                 inline reference dereference() const {
179                     return base()->first;
180                 }
181             };
182 
183             using const_iterator = iterator;
184 
PathRange()185             PathRange() : _changes(nullptr) { }
186 
187             /// Explicit conversion to SdfPathVector for convenience
SdfPathVector()188             explicit operator SdfPathVector() const {
189                 return SdfPathVector(begin(), end());
190             }
191 
192             /// Return true if this range contains any paths, false otherwise.
empty()193             bool empty() const {
194                 return !_changes || _changes->empty();
195             }
196 
197             /// Return the number of paths in this range.
size()198             size_t size() const {
199                 return _changes ? _changes->size() : 0;
200             }
201 
202             /// Return iterator to the start of this range.
begin()203             iterator begin() const {
204                 return iterator(_changes->cbegin());
205             }
206 
207             /// Return iterator to the start of this range.
cbegin()208             const_iterator cbegin() const {
209                 return iterator(_changes->cbegin());
210             }
211 
212             /// Return the end iterator for this range.
end()213             iterator end() const {
214                 return iterator(_changes->cend());
215             }
216 
217             /// Return the end iterator for this range.
cend()218             const_iterator cend() const {
219                 return iterator(_changes->cend());
220             }
221 
222             /// Return an iterator to the specified \p path in this range if
223             /// it exists, or end() if it does not.  This is potentially more
224             /// efficient than std::find(begin(), end()).
find(const SdfPath & path)225             const_iterator find(const SdfPath& path) const {
226                 return const_iterator(_changes->find(path));
227             }
228 
229         private:
230             friend class ObjectsChanged;
PathRange(const _PathsToChangesMap * changes)231             explicit PathRange(const _PathsToChangesMap* changes)
232                 : _changes(changes)
233             { }
234 
235             const _PathsToChangesMap* _changes;
236         };
237 
238         /// Return the set of paths that are resynced in lexicographical order.
239         /// Resyncs imply entire subtree invalidation of all descendant prims
240         /// and properties, so this set is minimal regarding ancestors and
241         /// descendants.  For example, if the path '/foo' appears in this set,
242         /// the entire subtree at '/foo' is resynced so the path '/foo/bar' will
243         /// not appear, but it should be considered resynced.
244         USD_API PathRange GetResyncedPaths() const;
245 
246         /// Return the set of paths that have only info changes (those that do
247         /// not affect the structure of cached UsdPrims on a UsdStage) in
248         /// lexicographical order.  Info changes do not imply entire subtree
249         /// invalidation, so this set is not minimal regarding ancestors and
250         /// descendants, as opposed to GetResyncedPaths().  For example, both
251         /// the paths '/foo' and '/foo/bar' may appear in this set.
252         USD_API PathRange GetChangedInfoOnlyPaths() const;
253 
254         /// Return the set of changed fields in layers that affected \p obj.
255         ///
256         /// This set will be empty for objects whose paths are not in
257         /// GetResyncedPaths() or GetChangedInfoOnlyPaths().
258         ///
259         /// If a field is present in this set, it does not necessarily mean the
260         /// composed value of that field on \p obj has changed.  For example, if
261         /// a metadata value on \p obj is overridden in a stronger layer and
262         /// is changed in a weaker layer, that field will appear in this set.
263         /// However, since the value in the stronger layer did not change,
264         /// the composed value returned by GetMetadata() will not have changed.
265         USD_API TfTokenVector GetChangedFields(const UsdObject &obj) const;
266 
267         /// \overload
268         USD_API TfTokenVector GetChangedFields(const SdfPath &path) const;
269 
270         /// Return true if there are any changed fields that affected \p obj,
271         /// false otherwise.  See GetChangedFields for more details.
272         USD_API bool HasChangedFields(const UsdObject &obj) const;
273 
274         /// \overload
275         USD_API bool HasChangedFields(const SdfPath &path) const;
276 
277     private:
278         const _PathsToChangesMap *_resyncChanges;
279         const _PathsToChangesMap *_infoChanges;
280     };
281 
282     /// \class StageEditTargetChanged
283     ///
284     /// Notice sent when a stage's EditTarget has changed.  Sent in the
285     /// thread that changed the target.
286     ///
287     class StageEditTargetChanged : public StageNotice {
288     public:
StageEditTargetChanged(const UsdStageWeakPtr & stage)289         explicit StageEditTargetChanged(const UsdStageWeakPtr &stage)
290             : StageNotice(stage) {}
291         USD_API virtual ~StageEditTargetChanged();
292     };
293 
294     /// \class LayerMutingChanged
295     ///
296     /// Notice sent after a set of layers have been newly muted or unmuted.
297     /// Note this does not necessarily mean the specified layers are currently
298     /// loaded.
299     ///
300     /// LayerMutingChanged notice is sent before any UsdNotice::ObjectsChanged
301     /// or UsdNotice::StageContentsChanged notices are sent resulting from
302     /// muting or unmuting of layers.
303     ///
304     /// Note that LayerMutingChanged notice is sent even if the
305     /// muting/unmuting layer does not belong to the current stage, or is a
306     /// layer that does belong to the current stage but is not yet loaded
307     /// because it is behind an unloaded payload or unselected variant.
308     class LayerMutingChanged : public StageNotice {
309     public:
LayerMutingChanged(const UsdStageWeakPtr & stage,const std::vector<std::string> & mutedLayers,const std::vector<std::string> & unmutedLayers)310         explicit LayerMutingChanged(const UsdStageWeakPtr &stage,
311                 const std::vector<std::string>& mutedLayers,
312                 const std::vector<std::string>& unmutedLayers)
313             : StageNotice(stage),
314              _mutedLayers(mutedLayers),
315              _unMutedLayers(unmutedLayers) {}
316 
317         USD_API virtual ~LayerMutingChanged();
318 
319         /// Returns the identifier of the layers that were muted.
320         ///
321         /// The stage's resolver context must be bound when looking up
322         /// layers using the returned identifiers to ensure the same layers
323         /// that would be used by the stage are found.
GetMutedLayers()324         const std::vector<std::string>& GetMutedLayers() const {
325             return _mutedLayers;
326         }
327 
328         /// Returns the identifier of the layers that were unmuted.
329         ///
330         /// The stage's resolver context must be bound when looking up
331         /// layers using the returned identifiers to ensure the same layers
332         /// that would be used by the stage are found.
GetUnmutedLayers()333         const std::vector<std::string>& GetUnmutedLayers() const {
334             return _unMutedLayers;
335         }
336 
337     private:
338         const std::vector<std::string>& _mutedLayers;
339         const std::vector<std::string>& _unMutedLayers;
340     };
341 
342 };
343 
344 
345 PXR_NAMESPACE_CLOSE_SCOPE
346 
347 #endif // PXR_USD_USD_NOTICE_H
348