AcDbAssocManager.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2015 Autodesk, Inc. All rights reserved.
  4. //
  5. // Use of this software is subject to the terms of the Autodesk license
  6. // agreement provided at the time of installation or download, or which
  7. // otherwise accompanies this software in either electronic or hard copy form.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. //
  11. // CREATED BY: Jiri Kripac April 2007
  12. //
  13. // DESCRIPTION:
  14. //
  15. // AcDbAssocManager class.
  16. //
  17. //////////////////////////////////////////////////////////////////////////////
  18. #pragma once
  19. #include "AcString.h"
  20. #include "AcDbAssocGlobal.h"
  21. #pragma pack (push, 8)
  22. #pragma warning( push )
  23. #pragma warning( disable : 4275 ) //suppress compilation warning 4275
  24. //"An exported class was derived from
  25. // a class that was not exported"
  26. /// <summary> <para>
  27. /// This class currently just contains static methods to evaluate the top-level
  28. /// network of a given database and to add/remove global evaluation callbacks.
  29. /// </para> <para>
  30. /// There is currently no need to create an object of AcDbAssocManager class and
  31. /// add it to the database, but this object is still derived from AcDbObject,
  32. /// in case in the future there is a need to have a database-resident instance
  33. /// of AcDbAssocManager class that might keep additional data.
  34. /// </para> </summary>
  35. ///
  36. class ACDB_PORT AcDbAssocManager : public AcDbObject
  37. {
  38. public:
  39. ACRX_DECLARE_MEMBERS(AcDbAssocManager);
  40. /// <summary> Default constructor. </summary>
  41. ///
  42. AcDbAssocManager();
  43. /// <summary><para>
  44. /// Evaluates the top-level AcDbAssocNetwork of the given database, using the
  45. /// global evaluation callback. The top-level network owns subnetworks, such
  46. /// as subnetworks owned by the individual AcDbBlockTableRecords. Notice that
  47. /// the top-level network owns its subentworks in logical sense, but not
  48. /// necessarily in AutoCAD database ownership sense. See addAction() and
  49. /// getInstanceFromObject() methods of AcDbAssocNetwork class for more details.
  50. /// </para><para>
  51. /// Evaluating the top-level network evaluates all the subnetworks that need
  52. /// to be evaluated.
  53. /// </para><para>
  54. /// When a sub-network owned by an AcDbBlockTableRecord becomes empty, i.e.
  55. /// containing no actions, is is erased at the end of the evaluation of the
  56. /// top-level network. Also, when the top-level network becomes empty, it is
  57. /// erased. When an AcDbAssoc2dConstraintGroup becomes empty, i.e. not having
  58. /// any dependencies on AcDbEntities, it is erased at the end of its evaluation.
  59. /// </para><para>
  60. /// The client code needs to explicitly evaluate the top-level network when
  61. /// it adds several new actions in a row. When an action is added, and the
  62. /// action depends on another action that has just been added to the network,
  63. /// the network should be evaluated before adding the next action. The reason
  64. /// is that the action being added may need some information that is calculated
  65. /// by evaluating the other action that has already been added to the network.
  66. /// If the other action is not evaluated, the action being added will not have
  67. /// this information available and may not be connect correctly to and interact
  68. /// correctly with the other action.
  69. /// </para><para>
  70. /// In most other cases the client code does not need to evaluate the top-level
  71. /// network explicitly. It is happening automatically on document lock mode
  72. /// change and also during dragging, on every drag sample.
  73. /// </para></summary>
  74. /// <param name="pDatabase"> Database whose top-level network is to be evaluated. </param>
  75. /// <param name="pCallback"> Optional AcDbAssocEvaluationCallback that is
  76. /// added to the global callback before the evaluation and removed after the
  77. /// evaluation is completed. </param>
  78. /// <param name="callbackOrder"> Order of the optional AcDbAssocEvaluationCallback. </param>
  79. /// <returns> Returns true if any evaluation happened, false otherwise. </returns>
  80. ///
  81. static bool evaluateTopLevelNetwork(AcDbDatabase* pDatabase,
  82. AcDbAssocEvaluationCallback* pCallback = NULL,
  83. int callbackOrder = 0);
  84. /// <summary> <para>
  85. /// Returns the global AcDbAssocEvaluationCallback that is used while dragging,
  86. /// when evaluating the top-level associative network on document lock mode
  87. /// change, or anytime AcDbAssocManager::evaluateTopLevelNetwork() is explicitly
  88. /// called by the client code.
  89. /// </para> <para>
  90. /// It is actually an object of AcDbAssocEvaluationMultiCallback class
  91. /// (this class is currently not exposed, but may be expossed if needed)
  92. /// that keeps a vector of AcDbAssocEvaluationCallbacks and sequentially calls
  93. /// all the individual callbacks. The returned AcDbAssocEvaluationMultiCallback
  94. /// object must not be modified or deleted by the caller.
  95. /// </para> <para>
  96. /// During dragging, the dragging evaluation callback is temporarily inserted
  97. /// into this global multi-callback with order 0 and is removed after the
  98. /// dragging is finished.
  99. /// </para> </summary>
  100. /// <returns> The global AcDbAssocEvaluationMultiCallback object. </returns>
  101. ///
  102. static AcDbAssocEvaluationCallback* globalEvaluationMultiCallback();
  103. /// <summary>
  104. /// Adds the given user-provided AcDbAssocEvaluationCallback to the global
  105. /// AcDbAssocEvaluationMultiCallback.
  106. /// </summary>
  107. /// <param name="pCallback">
  108. /// The user-provided evaluation callback. The callback does not become owned
  109. /// by the global AcDbAssocEvaluationMultiCallback, it is just referenced by it.
  110. /// </param>
  111. /// <param name="order">
  112. /// Specifies the ordering of the user-provided callbacks in the global
  113. /// AcDbAssocEvaluationMultiCallback. The lower-order callbacks are called
  114. /// before the higher-order callbacks. The drag callback is inserted with
  115. /// order 0, i.e. callbacks with negative order will be called before
  116. /// it and callbacks with positive order will be called after it.
  117. /// </param>
  118. /// <returns>
  119. /// Acad::eInvalidInput if pCallback pointer is NULL, otherwise Acad::eOk.
  120. /// </returns>
  121. ///
  122. static Acad::ErrorStatus addGlobalEvaluationCallback(AcDbAssocEvaluationCallback* pCallback, int order);
  123. /// <summary>
  124. /// Removes the given user-provided evaluation callback from the global
  125. /// AcDbAssocEvaluationMultiCallback.
  126. /// </summary>
  127. /// <param name="pCallback">
  128. /// The user-provided evaluation callback to be removed.
  129. /// </param>
  130. /// <returns>
  131. /// Acad::eInvalidInput if pCallback pointer not found in the global
  132. /// AcDbAssocEvaluationMultiCallback, otherwise Acad::eOk.
  133. /// </returns>
  134. ///
  135. static Acad::ErrorStatus removeGlobalEvaluationCallback(AcDbAssocEvaluationCallback* pCallback);
  136. /// <summary>
  137. /// Returns all evaluation callbacks kept in the global AcDbAssocEvaluationMultiCallback.
  138. /// </summary>
  139. /// <param name="callbacks"> The returned evaluation callbacks. </param>
  140. /// <param name="orders"> The returned evaluation callback orders. </param>
  141. ///
  142. static void getGlobalEvaluationCallbacks(AcArray<AcDbAssocEvaluationCallback*>& callbacks,
  143. AcArray<int>& orders);
  144. /// <summary>
  145. /// Returns true if action evaluation is currently in progress for the given
  146. /// database.
  147. /// </summary>
  148. ///
  149. static bool isActionEvaluationInProgress(const AcDbDatabase*);
  150. /// <summary><para>
  151. /// Allows the custom action body's evaluateOverride() code or any other code to request
  152. /// one more evaluation of the top-level network of a database, even if the top-level network
  153. /// is already currently being evaluated, all actions to evaluate have already been transitively
  154. /// collected, and are currently being evaluated. It does it by waiting till the current top-level
  155. /// network evaluation has been completed, setting the requested newStatus of the actions and
  156. /// dependencies by calling AcDbAssocAction/Dependency::setStatus() on them, and evaluating the
  157. /// same top-level network again.
  158. /// </para><para>
  159. /// The objectId may be of an action (the most common case), dependency, or of an arbitrary object.
  160. /// The meaning is the same as in AcDbActionsToEvaluateCallback::needsToEvaluate() callback method,
  161. /// i.e. if it is an arbitrary object, not an action or a dependency, it calls setStatus() on
  162. /// all dependencies on that object.
  163. /// </para><para>
  164. /// The newStatus needs to be one of kChangedDirectlyAssocStatus, kChangedTransitivelyAssocStatus,
  165. /// or kChangedNoDifferenceAssocStatus. If it is kErasedAssocStatus, the action, dependency or
  166. /// object is erased before the top-level network is evaluated again.
  167. /// </para><para>
  168. /// If not in the middle of evaluation of the top level network of the same database as is the
  169. /// database of the objectId, this call just directly sets the status of the action or dependency,
  170. /// or of all dependencies on the objects, if objectId is of an arbitrary object. It does not
  171. /// trigger the top-level network evaluation of the database, but the status of actions and
  172. /// dependencies has been changed, so that when the top-level network evaluation happens later,
  173. /// these actions will get evaluated.
  174. /// </para><para>
  175. /// Eventually this method might get called automatically anytime AcDbAssocAction/Dependency::setStatus()
  176. /// is called in the middle of evaluation of the same database, and newStatus is an evaluation
  177. /// request or kErasedAssocStatus. But until it happens automatically, it is up to the client code
  178. /// to explicitly call this method when needed, to trigger one more evaluation of the same
  179. /// top-level network as is currently being evaluated.
  180. /// </para></summary>
  181. ///
  182. static Acad::ErrorStatus requestToEvaluate(const AcDbObjectId& objectId,
  183. AcDbAssocStatus newStatus = kChangedDirectlyAssocStatus,
  184. bool ownedActionsAlso = true);
  185. /// <summary>
  186. /// Returns the current AcDbAssocEvaluationCallback if action evaluation is in
  187. /// progress for the given database, or NULL otherwise.
  188. /// </summary>
  189. ///
  190. static AcDbAssocEvaluationCallback* getCurrentEvaluationCallback(const AcDbDatabase*);
  191. /// <summary>
  192. /// Returns true iff the given database has some associative data, in particular
  193. /// if there is a global AcDbAssocNetwork for the whole database. See the
  194. /// related AcDbAssocNetwork::getInstanceFromDatabase() method.
  195. /// </summary>
  196. ///
  197. static bool hasAssocNetwork(const AcDbDatabase* pDatabase);
  198. /// <summary>
  199. /// Returns the action of the given database that is currently being evaluated,
  200. /// or AcDbObjectId::kNull is no evaluation of the top-level network of the database
  201. /// is happening.
  202. /// </summary>
  203. ///
  204. static AcDbObjectId currentlyEvaluatedAction(const AcDbDatabase*);
  205. /// <summary>
  206. /// Audits the associative data in the database and tries to fix the errors
  207. /// that might have happened during round-trip, due to lazy-erase, etc.
  208. /// </summary>
  209. /// <param name="pDatabase"> AcDbDatabase whose associative data is to be audited. </param>
  210. /// <param name="traverseWholeDatabase"> If true, all objects in the database
  211. /// are visited and checked, and therefore loaded into memory. </param>
  212. ///
  213. static Acad::ErrorStatus auditAssociativeData(AcDbDatabase* pDatabase, bool traverseWholeDatabase);
  214. /// <summary><para>
  215. /// If the given database is a host database, sets an internal flag indicating
  216. /// that AcDbAssocActions in the host database may need to sync-up with changed
  217. /// objects in changed XREF database(s). If the given database is an XREF database,
  218. /// sets an internal flag indicating that that AcDbAssocActions in the host database
  219. /// need to unconditionally sync up with objects in this XREF database. It also sets
  220. /// the flag in the host database.
  221. /// </para?<para>
  222. /// This method is automatically called during XREF attach, XREF reload and other
  223. /// XREF-releated operations during which contents of XREFs may change. This method
  224. /// generally does not need to be called by client code.
  225. /// </para></summary>
  226. /// <param name="pDatabase"> Host or XREF database. </param>
  227. ///
  228. static Acad::ErrorStatus markSyncUpWithXrefsNeeded(AcDbDatabase* pDatabase);
  229. /// <summary>
  230. /// If the given host database does not have a flag set indicating that it may
  231. /// need to sync-up with changed XREFs (see markSyncUpWithXrefsNeeded() mthod),
  232. /// this method does nothing and returns. Otherwise it visits all BTRs in the
  233. /// host database that represent XREF databases. If associative data in the host
  234. /// database are out-of-sync with the current version of the XREF database,
  235. /// marks all dependencies of AcDbAssocActions in the host database on objects
  236. /// in the XREF database with kChangedDirectlyAssocStatus so that these actions
  237. /// later evaluate and sync-up with objects in the current version of the
  238. /// XREF database.
  239. /// <remarks>
  240. /// As this operation is trivial when no sync-up with XREFs is needed,
  241. /// it may be called frequently w/o any performance penalty. It is called
  242. /// during every evaluation triggered by a document lock mode change, roughly
  243. /// corresponding to the beginning and end of every command.
  244. /// </remarks>
  245. /// </summary>
  246. /// <param name="pHostDatabase"> Host database. XREF databases are ignored. </param>
  247. ///
  248. static Acad::ErrorStatus syncUpWithXrefs(AcDbDatabase* pHostDatabase);
  249. /// <summary>
  250. /// This is an internal method that initializes the Associative Framework
  251. /// subsystem. Must be called before the subsystem is first used and may
  252. /// safely be called more than once. There is no need for the client code
  253. /// to call this method.
  254. /// </summary>
  255. /// <returns> Should always return Acad::eOk. </returns>
  256. ///
  257. static Acad::ErrorStatus initialize();
  258. /// <summary>
  259. /// This is an internal method that uninitializes the Associative Framework
  260. /// subsystem during AutoCAD shutdown. Client code must not call this method.
  261. /// </summary>
  262. ///
  263. static void uninitialize();
  264. /// <summary>
  265. /// Enable/disable the progress meter while evaluating the top-level network.
  266. /// Once set, it stays enabled/disabled for all evaluations of all databases,
  267. /// until it is set again.
  268. /// </summary>
  269. /// <param name="enableIt"> Enable or disable the prgress meter. </param>
  270. /// <param name="progressLabel"> Text label to display. </param>
  271. ///
  272. static void enableProgressMeter(bool enableIt, const AcString& progressLabel = AcString());
  273. }; // class AcDbAssocManager
  274. /// <summary>
  275. /// The constructor disables or enables all top-level network evaluations for the
  276. /// given database. The destructor reverts back to the previous state. By default
  277. /// the database evaluations are enabled and there should not be many reasons to
  278. /// forcefully disable all evaluations.
  279. /// </summary>
  280. ///
  281. class ACDB_PORT AcDbAssocNetworkEvaluationDisabler
  282. {
  283. public:
  284. explicit AcDbAssocNetworkEvaluationDisabler(AcDbDatabase*, bool disableIt = true);
  285. ~AcDbAssocNetworkEvaluationDisabler();
  286. static bool isDisabled(const AcDbDatabase*);
  287. private:
  288. AcDbDatabase* mpDatabase;
  289. bool mPreviouslyDisabled;
  290. };
  291. #pragma warning( pop )
  292. #pragma pack (pop)