1/****************************************************************************************
2
3 Copyright (C) 2015 Autodesk, Inc.
4 All rights reserved.
5
6 Use of this software is subject to the terms of the Autodesk license agreement
7 provided at the time of installation or download, or which otherwise accompanies
8 this software in either electronic or hard copy form.
9
10****************************************************************************************/
11
12//! \file fbxusernotification.h
13#ifndef _FBXSDK_UTILS_USER_NOTIFICATION_H_
14#define _FBXSDK_UTILS_USER_NOTIFICATION_H_
15
16#include <fbxsdk/fbxsdk_def.h>
17
18#include <fbxsdk/core/base/fbxarray.h>
19#include <fbxsdk/core/base/fbxstring.h>
20#include <fbxsdk/core/base/fbxmultimap.h>
21
22#include <fbxsdk/fbxsdk_nsbegin.h>
23
24class FbxLogFile;
25class FbxMessageEmitter;
26class FbxUserNotificationFilteredIterator;
27
28/** This class defines one entry object held by the FbxUserNotification class.
29 * \nosubgrouping
30 * An entry object is a message to show error, warning or information.
31 * Direct manipulation of this object should not be required. At most, access to
32 * its members can be granted for querying purposes.
33 */
34class FBXSDK_DLL FbxAccumulatorEntry
35{
36public:
37 /** Category of the accumulator entry.
38 */
39 enum EClass
40 {
41 eError=1, //!< Error message entry.
42 eWarning=2, //!< Warning message entry.
43 eInformation=4, //!< Information message entry.
44 eAny=7 //!< Entry that does not belong to above class. Cannot be used as a class ID
45 };
46
47 /** Constructor.
48 * \param pAEClass Specify the category for this entry.
49 * \param pName Identifies this entry (more than one object can have the same name).
50 * \param pDescr The description of the entry. This is the common message. The details
51 * are added separately by the FbxUserNotification classes.
52 * \param pDetail A list of detail string that will be copied into the local array.
53 * \param pMuteState Whether this entry is muted.
54 * \remarks By default the object is muted so it does not get processed by the low level
55 * output routines of the UserNotification accumulator. The entry gets activated
56 * (unmuted) by the calls to AddDetail() in the accumulator.
57 */
58 FbxAccumulatorEntry(EClass pAEClass, const FbxString& pName, const FbxString& pDescr,
59 FbxString pDetail="", bool pMuteState=true);
60
61 /** Copy Constructor.
62 * \param pAE Another FbxAccumulatorEntry object to be copied.
63 * \param pSkipDetails Flag to skip details.
64 */
65 FbxAccumulatorEntry(const FbxAccumulatorEntry& pAE, bool pSkipDetails);
66
67 //! Destructor.
68 ~FbxAccumulatorEntry();
69
70 //! Returns the category class of this entry.
71 EClass GetClass() const;
72
73 //! Returns the name of this entry.
74 FbxString GetName() const;
75
76 //! Returns the description of this entry.
77 FbxString GetDescription() const;
78
79 //! Returns the number of details stored.
80 int GetDetailsCount() const;
81
82 /** Returns a pointer to one specific detail string (or NULL if the id is invalid).
83 * Detail string is dynamic. One entry can have multiple detail strings to hold extra information.
84 * For example, if one entry message is related to many FBX nodes, user can add these nodes' name as details.
85 * \param id The detail id.
86 * \return Pointer to the specific detail.
87 */
88 const FbxString* GetDetail(int id) const;
89
90 //! Returns True if this entry is muted.
91 bool IsMuted() const;
92
93private:
94 FbxArray<FbxString*>& GetDetails();
95 void Mute(bool pState);
96
97 bool mMute;
98 EClass mAEClass;
99 FbxString mName;
100 FbxString mDescr;
101 FbxArray<FbxString*> mDetails;
102
103 friend class FbxUserNotification;
104};
105
106
107/** This class accumulates user notifications and sends them to any device opened by the derived classes.
108 * If this class is not derived, the data can only be sent to a log file. To send data to a log file,
109 * it must be opened before attempting to send data, otherwise, the messages will be lost.
110 */
111class FBXSDK_DLL FbxUserNotification
112{
113public:
114 /**
115 * Create and initialize user notification object for the SDK manager.
116 * One SDK manager has one global user notification object.
117 * If the SDK manager already has global user notification object, the function will do nothing.
118 *
119 * \param pManager
120 * \param pLogFileName Name of the log file that will be open in the directory
121 * defined by the GetLogFilePath method.
122 * \param pSessionDescription This string is used to separate session logs in the file.
123 * \return the global user notification object owned by the SDK manager.
124 */
125 static FbxUserNotification* Create(FbxManager* pManager,
126 const FbxString& pLogFileName,
127 const FbxString& pSessionDescription);
128
129 /**
130 * Destroy the global user notification object owned by the SDK manager.
131 */
132 static void Destroy(FbxManager* pManager);
133
134 /** Instantiate a FbxUserNotification but leave it uninitialized. The caller must
135 * explicitly call InitAccumulator to initialize it and ClearAccumulator when finished
136 * using it.
137 * \param pManager
138 * \param pLogFileName Name of the log file that will be open in the directory
139 * defined by the GetLogFilePath method.
140 * \remarks If pLogFileName is an empty string the log file does not get created and any
141 * output sent to it is lost.
142 * \param pSessionDescription This string is used to separate session logs in the file.
143 * \remarks If the specified log file already exists, messages are appended to it. This
144 * class never deletes the log file. Derived classes may delete the log file
145 * before opening (it must be done in the constructor because the log file is
146 * opened in the InitAccumulator) or at the end of the processing in the
147 * PostTerminate method.
148 */
149 FbxUserNotification(FbxManager* pManager,
150 FbxString const& pLogFileName,
151 FbxString const& pSessionDescription);
152
153 //! Destructor.
154 virtual ~FbxUserNotification();
155
156 /**
157 * Accumulator is to hold the notification entries. User can add entries to it.
158 * This method must be called before using the Accumulator. It opens the log file and
159 * calls AccumulatorInit followed by OpenExtraDevices. Failing to call this method
160 * will prevent other actions except ClearAccumulator, GetLogFileName and GetLogFilePath.
161 */
162 void InitAccumulator();
163
164 /** This method must be called when the Accumulator is no longer needed. It calls
165 * CloseExtraDevices, followed by the AccumulatorClear, and then closes the log file.
166 */
167 void ClearAccumulator();
168
169 /** IDs for pre-defined message entries.
170 */
171 enum EEntryID
172 {
173 eBindPoseInvalidObject,
174 eBindPoseInvalidRoot,
175 eBindPoseNotAllAncestorsNodes,
176 eBindPoseNotAllDeformingNodes,
177 eBindPoseNotAllAncestorsDefinitionNodes,
178 eBindPoseRelativeMatrix,
179 eEmbedMediaNotify,
180 eFileIONotify, //!< this is generic for reader and writer to log notifications.
181 eFileIONotifyMaterial,
182 eFileIONotifyDXFNotSupportNurbs,
183 eEntryStartID //!< Starting ID for any Accumulator entry added by derived classes.
184 };
185
186 /**
187 * \name Accumulator Management
188 */
189 //@{
190 /** Adds one entry into the accumulator.
191 * \param pID This entry unique ID.
192 * \param pName This entry name.
193 * \param pDescr The description of this entry.
194 * \param pClass The category of this entry.
195 * \return The ID of the newly allocated entry. This ID is pEntryId.
196 */
197 int AddEntry(const int pID, const FbxString& pName, const FbxString& pDescr, FbxAccumulatorEntry::EClass pClass=FbxAccumulatorEntry::eWarning);
198
199 /** Completes the accumulator entry (there can be more that one detail for each entry) and implicitly defines
200 * the sequence of events. Each call to this method is internally recorded, making it possible to output each
201 * notification in the order they have been defined. Also, when a detail is added to an entry, it is automatically unmuted
202 * so it can be sent to the devices (muted FbxAccumulatorEntry objects are not processed).
203 * \param pEntryId The entry index (as returned by AddEntry).
204 * \return The id of the detail in the recorded sequence of events. This Id should be used when the call to
205 * Output has the eSequencedDetails set as a source. If an error occurs, the returned value is -1
206 */
207 int AddDetail(int pEntryId);
208
209 /** Completes the accumulator entry (there can be more that one detail for each entry) and implicitly defines
210 * the sequence of events. Each call to this method is internally recorded, making it possible to output each
211 * notification in the order they have been defined. Also, when a detail is added to an entry, it is automatically unmuted
212 * so it can be sent to the devices (muted FbxAccumulatorEntry objects are not processed).
213 * \param pEntryId The entry index (as returned by AddEntry).
214 * \param pString The detail string to add to the entry.
215 * \return The id of the detail in the recorded sequence of events. This Id should be used when the call to
216 * Output has the eSequencedDetails set as a source. If an error occurs, the returned value is -1
217 */
218 int AddDetail(int pEntryId, FbxString pString);
219
220 /** Completes the accumulator entry (there can be more that one detail for each entry) and implicitly defines
221 * the sequence of events. Each call to this method is internally recorded, making it possible to output each
222 * notification in the order they have been defined. Also, when a detail is added to an entry, it is automatically unmuted
223 * so it can be sent to the devices (muted FbxAccumulatorEntry objects are not processed).
224 * \param pEntryId The entry index (as returned by AddEntry).
225 * \param pNode The node to add to the entry.
226 * \return The id of the detail in the recorded sequence of events. This Id should be used when the call to
227 * Output has the eSequencedDetails set as a source. If an error occurs, the returned value is -1
228 */
229 int AddDetail(int pEntryId, FbxNode* pNode);
230
231 //! Returns the number of AccumulatorEntries currently stored in this accumulator.
232 int GetNbEntries() const;
233
234 /** Get the specified FbxAccumulatorEntry.
235 * \param pEntryId ID of the entry to retrieve.
236 * \return Pointer to the specified entry, otherwise \c NULL if either the id is invalid or the Accumulator
237 * is not properly initialized.
238 */
239 const FbxAccumulatorEntry* GetEntry(int pEntryId);
240
241 /** Get the FbxAccumulatorEntry at the specified index.
242 * \param pEntryIndex index of the entry to retrieve.
243 * \return Pointer to the specified entry, otherwise \c NULL if either the index is invalid or the Accumulator
244 * is not properly initialized..
245 */
246 const FbxAccumulatorEntry* GetEntryAt(int pEntryIndex) const;
247
248 //! Returns the number of Details recorded so far in this accumulator.
249 int GetNbDetails() const;
250
251 /** Get the specified detail.
252 * \param pDetailId Index of the detail. This is the id-th detail of type pClass as inserted
253 * when the AddDetail
254 * \param pAE Pointer to the FbxAccumulatorEntry object that contains the requested detail.
255 * The returned valued can be NULL if an error occurred.
256 * \return The index of the detail to be used when calling the GetDetail of the FbxAccumulatorEntry.
257 * \remarks A value of -1 is acceptable and means that the FbxAccumulatorEntry has no details. However,
258 * if pAE is NULL, the return value is meaningless.
259 */
260 int GetDetail(int pDetailId, const FbxAccumulatorEntry*& pAE) const;
261
262 //@}
263
264 /**
265 * \name Accumulator Output
266 */
267 //@{
268 /** Specify send what kind of data to output device.
269 */
270 enum EOutputSource
271 {
272 eAccumulatorEntry, //!< Entry with its details.
273 eSequencedDetails //!< Details in the recorded order.
274 };
275
276 /** Send the accumulator entries to the output devices.
277 * This method needs to be explicitly called by the program that uses this
278 * class.
279 * \param pOutSrc Specify which data has to be sent to the output devices. Set to SEQUENCED_DETAILS
280 * to send the Details in the recorded order. Set to ACCUMULATOR_ENTRY to send
281 * each entry with its details regardless of the order in which the events occurred.
282 * \param pIndex If this parameter >= 0, only send the specified entry/detail index to the output devices.
283 * Otherwise send all of them.
284 * \param pExtraDevicesOnly If this parameter is True, the output is not sent to the log file.
285 * \remarks The pExtraDevicesOnly parameter is ignored if the log file has been disabled.
286 */
287 bool Output(EOutputSource pOutSrc=eAccumulatorEntry, int pIndex = -1, bool pExtraDevicesOnly = false);
288
289 /** Send the accumulator entry to the output devices.
290 * \param pId Send the entry/detail that matching pIdx to the output devices,
291 * otherwise send all of them.
292 * \param pOutSrc Specify which data has to be sent to the output devices. Set to SEQUENCED_DETAILS
293 * to send the Details in the recorded order. Set to ACCUMULATOR_ENTRY to send
294 * each entry with its details regardless of the order in which the events occurred..
295 * \param pExtraDevicesOnly If this parameter is True, the output is not sent to the log file.
296 */
297 bool OutputById(EEntryID pId, EOutputSource pOutSrc=eAccumulatorEntry, bool pExtraDevicesOnly = false);
298
299 /** Send an immediate entry to the output devices.
300 * This method bypasses the accumulator by sending the entry directly to the output devices
301 * and discarding it right after. The internal accumulator lists are left unchanged by this call.
302 * \param pName This entry name.
303 * \param pDescr The description of this entry.
304 * \param pClass The category of this entry.
305 * \param pExtraDevicesOnly If this parameter is True, the output is not sent to the log file.
306 * \remarks The pExtraDevicesOnly parameter is ignored if the log file has been disabled.
307 */
308 bool Output(const FbxString& pName, const FbxString& pDescr, FbxAccumulatorEntry::EClass pClass, bool pExtraDevicesOnly = false);
309
310 /** Sends the content of the iterator to the output devices.
311 * This method bypasses the accumulator by sending each entry in the iterator directly to
312 * the output devices. The internal accumulator lists are left unchanged by this call.
313 * \param pAEFIter The Filtered FbxAccumulatorEntry iterator object.
314 * \param pExtraDevicesOnly If this parameter is True, the output is not sent to the log file.
315 * \remarks The pExtraDevicesOnly parameter is ignored if the log file has been disabled.
316 */
317 bool Output(FbxUserNotificationFilteredIterator& pAEFIter, bool pExtraDevicesOnly = false);
318
319 /** Set log message emitter.
320 * \param pLogMessageEmitter The new log message emitter.
321 */
322 void SetLogMessageEmitter(FbxMessageEmitter * pLogMessageEmitter);
323
324 /**
325 * \name Utilities
326 */
327 //@{
328 /** Returns the absolute path to the log file. If this method is not overridden in a derived class, it
329 * returns the TEMP directory.
330 * \param pPath The returned path.
331 */
332 virtual void GetLogFilePath(FbxString& pPath);
333
334 /** Returns the log file name. */
335 inline FbxString GetLogFileName() { return mLogFileName; }
336 //@}
337
338protected:
339 /**
340 * Identify one detail in all accumulator entries by record the entry object and its detail id.
341 */
342 class AESequence
343 {
344 public:
345 AESequence(FbxAccumulatorEntry* pAE, int pDetailId) :
346 mAE(pAE),
347 mDetailId(pDetailId)
348 {
349 };
350
351 //! Return the entry object the detail belongs to.
352 FbxAccumulatorEntry* AE() { return mAE; }
353 //! Return the detail id in the entry object
354 int DetailId() { return mDetailId; }
355
356 private:
357 FbxAccumulatorEntry* mAE;
358 int mDetailId;
359 };
360
361 friend class FbxUserNotificationFilteredIterator;
362
363 /** Allow a derived class to finalize processing AFTER the log file handle has been
364 * deleted. This may be required if the log file needs to be moved or shown.
365 * \returns True if the object is properly cleaned.
366 */
367 virtual bool PostTerminate();
368
369 /** Allow the implementation class to perform accumulator initializations before
370 * the Extra devices are opened. By default this method does nothing.
371 */
372 virtual void AccumulatorInit();
373
374 /** Allow the implementation class to perform accumulator clear after the Extra devices are
375 * closed. By default this method does nothing.
376 */
377 virtual void AccumulatorClear();
378
379 /** Allow the implementation class to opens its output devices (called by InitAccumulator).
380 * By default this method does nothing.
381 */
382 virtual void OpenExtraDevices();
383
384 /** Allow the implementation class to send all the accumulator entries to the devices.
385 * By default this method loop trough all the elements of the received array and
386 * call the SendToExtraDevices method with the appropriate FbxAccumulatorEntry element and id.
387 * \param pOutputNow Flag indicates whether to output now.
388 * \param pEntries Accumulator entries to output.
389 * \return \c true if successful, \c false otherwise.
390 */
391 virtual bool SendToExtraDevices(bool pOutputNow, FbxArray<FbxAccumulatorEntry*>& pEntries);
392
393 /** Allow the implementation class to send all the accumulator entries to the devices.
394 * By default this method loop trough all the elements of the received array and
395 * call the SendToExtraDevices method with the appropriate FbxAccumulatorEntry element and id.
396 * \param pOutputNow Flag indicates whether to output now.
397 * \param pAESequence Accumulator entries to output.
398 * \return \c true if successful, \c false otherwise.
399 */
400 virtual bool SendToExtraDevices(bool pOutputNow, FbxArray<AESequence*>& pAESequence);
401
402 /** Allow the implementation class to send one accumulator entry to the devices.
403 * By default this method does nothing.
404 * \param pOutputNow Flag indicates whether to output now.
405 * \param pAccEntry Accumulator entry to output.
406 * \param pDetailId Detail id.
407 * \return \c true if successful, \c false otherwise.
408 * \remarks Derived methods should check for the IsMuted() state to decide if the accumulator
409 * entry should get through or get discarded. See AddDetail for more details.
410 */
411 virtual bool SendToExtraDevices(bool pOutputNow, const FbxAccumulatorEntry* pAccEntry, int pDetailId = -1);
412
413
414 /** Allow the implementation class to close it's output devices (called in the ClearAccumulator)
415 * By default this method does nothing.
416 */
417 virtual void CloseExtraDevices();
418
419 //! Clears the Accumulator list, remove all user notification entries..
420 void ResetAccumulator();
421
422 //! Clears the Sequence list.
423 void ResetSequence();
424
425 /** Send the pIdth element of the accumulator or sequence list to the log file.
426 * \param pOutSrc The output source, accumulator or sequence list.
427 * \param pId Element id.
428 */
429 void SendToLog(EOutputSource pOutSrc, int pId);
430
431 /** Send the accumulator entry to the log file.
432 * \param pAccEntry The accumulator entry.
433 * \param pDetailId Detail id.
434 */
435 void SendToLog(const FbxAccumulatorEntry* pAccEntry, int pDetailId = -1);
436
437private:
438 FbxString mLogFileName;
439 FbxString* mLog;
440 FbxLogFile* mLogFile;
441 FbxMessageEmitter* mLogMessageEmitter;
442
443 bool mProperlyInitialized;
444 FbxString mSessionDescription;
445 bool mProperlyCleaned;
446
447 FbxMultiMap mAccuHT; // The set establish a relationship between an FbxAccumulatorEntry and it's ID
448 FbxArray<FbxAccumulatorEntry*> mAccu; // The array defines the order the FbxAccumulatorEntry objects have been
449 // added to the accumulator (calls to AddEntry)
450 // Both structures share the same pointers.
451 FbxArray<AESequence*> mAESequence;
452 FbxManager* mSdkManager;
453};
454
455/** This class iterates through the accumulated messages depending on the configuration
456 * flags (filter). The iterator keeps a local copy of the data extracted from the
457 * accumulator.
458 */
459class FBXSDK_DLL FbxUserNotificationFilteredIterator
460{
461public:
462 /** Constructor.
463 * \param pAccumulator This reference is only used during construction for retrieving
464 * the data required to fill the iterator.
465 * \param pFilterClass The bitwise combination of the EClass identifiers. An FbxAccumulatorEntry
466 * element is copied from the accumulator if its Class matches one of the
467 * bits of this flag.
468 * \param pSrc Specify which data format is extracted from the accumulator.
469 * \param pNoDetail This parameter is used ONLY if pSrc == eAccumulatorEntry and, if set to
470 * false, the details of the FbxAccumulatorEntry are also sent to the output
471 * devices. If left to its default value, only the description of the
472 * FbxAccumulatorEntry is sent.
473 */
474 FbxUserNotificationFilteredIterator(FbxUserNotification& pAccumulator,
475 int pFilterClass,
476 FbxUserNotification::EOutputSource pSrc = FbxUserNotification::eSequencedDetails,
477 bool pNoDetail = true);
478
479 virtual ~FbxUserNotificationFilteredIterator();
480
481 //! Returns the number of elements contained in this iterator.
482 int GetNbItems() const;
483
484 //! Put the iterator in its reset state.
485 void Reset();
486
487 /** Get this iterator's first item.
488 * \return NULL if the iterator is empty.
489 */
490 FbxAccumulatorEntry* const First();
491
492 /** Get this iterator's previous item.
493 * \return NULL if the iterator reached the beginning (or is empty).
494 * \remarks This method will also return NULL if it is called before
495 * or immediately after a call to First() and reset the iterator to
496 * its reset state (meaning that a call to First() is mandatory
497 * to be able to iterate again).
498 */
499 FbxAccumulatorEntry* const Previous();
500
501 /** Get this iterator's next item.
502 * \return NULL if the iterator reached the end (or is empty).
503 * \remarks This method will also return NULL if it is called while
504 * the iterator is in its reset state (called before
505 * First() or after a preceding call to Previous() reached
506 * beyond the beginning).
507 */
508 FbxAccumulatorEntry* const Next();
509
510protected:
511 // Called in the constructor.
512 virtual void BuildFilteredList(FbxUserNotification& pAccumulator);
513
514 int mIterator;
515 int mFilterClass;
516 bool mNoDetail;
517 FbxUserNotification::EOutputSource mAccuSrcData;
518 FbxArray<FbxAccumulatorEntry*> mFilteredAE;
519};
520
521#include <fbxsdk/fbxsdk_nsend.h>
522
523#endif /* _FBXSDK_UTILS_USER_NOTIFICATION_H_ */
524