Author Topic: Trap copy/pasteclip event?  (Read 403 times)

0 Members and 1 Guest are viewing this topic.

Atook

  • Swamp Rat
  • Posts: 815
Trap copy/pasteclip event?
« on: December 02, 2016, 03:52:51 pm »
I want to trap any copied entities of mine created during copy/pasteclip and strip some xdata from the copied objects. I donít want to change any entities created by my code.

I can use the Database.ObjectAppended ObjectEventHandler, but that would fire even when my code creates new objects, unless I filter for that as well. Iím leery of adding too much to the database eventhandler for performance reasons. Creating object eventhandlers might work, but it seems like a bad way of doing it.

Whatís the best way of doing this? Is there a good way to trap commands such as copy/pasteclip and handle the new entities?

Atook

  • Swamp Rat
  • Posts: 815
Re: Trap copy/pasteclip event?
« Reply #1 on: December 05, 2016, 02:27:45 am »
Here's what I've come up with so far, seems like a weird way of doing it. See any glaring mistakes or a better way executing?
  • Add command and database eventhandlers to all new documents
  • check for a copy command
  • grab any objectIDs added to the database
  • After the copy command completes, filter through everything added, and change/delete objects as necessary

Code - C#: [Select]
  1. public class AIDApplication : IExtensionApplication
  2. {
  3. private bool filterEntities = false;
  4.  
  5. public void Initialize()
  6. {
  7. // add document handler to every document we open
  8. Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager.DocumentActivated += AddDocumentHandlers;
  9. }
  10.  
  11. private void callback_ObjectAppended(object sender, ObjectEventArgs e)
  12. {
  13. if (filterEntities && objectsForFilter!=null)
  14. { // add the objects to a collection do deal with when the command ends
  15. objectsForFilter.Add(e.DBObject.ObjectId);
  16. }
  17. }
  18.  
  19. private  void AddDocumentHandlers(object sender, DocumentCollectionEventArgs e)
  20. {
  21. // make sure there's an active document to copyt styles to
  22. if (Active.Document == null) return;
  23. Active.Document.CommandWillStart += doc_CommandWillStart;
  24. Active.Document.CommandEnded += doc_CommandEnded;
  25. Active.Database.ObjectAppended += callback_ObjectAppended;
  26. }
  27. private void doc_CommandWillStart(object sender, CommandEventArgs e)
  28. {
  29. Debug.WriteLine(string.Format("Command {0} will start.", e.GlobalCommandName));
  30. if (e.GlobalCommandName.ToUpper()=="COPY")
  31. {
  32. filterEntities = true;
  33. objectsForFilter = new ObjectIdCollection();
  34. }
  35. }
  36. void doc_CommandEnded(object sender, CommandEventArgs e)
  37. {
  38. // deal with any objects that need it.
  39. if (objectsForFilter == null) return;
  40. foreach (ObjectId id in objectsForFilter)
  41. {
  42. int pipeID = XData.ReadInt(id, AID_AppName.PIPE);
  43. if (pipeID >= 0)
  44. {
  45. // we have a pipe, maybe do something about it
  46. Debug.WriteLine("Pipe added to database not by our code, fix it");
  47. // strip xData
  48. XData.DeleteXData(id, AID_AppName.LABEL_HANDLE);
  49.  
  50. // set color to bylayer
  51. Utililty.SetColor(id, 256);
  52. }
  53. string arrowID = XData.ReadString(id, AID_AppName.FLOW_ARROW);
  54. if (arrowID.Length > 0)
  55. {
  56. // erase it.
  57. Utililty.Erase(id);
  58. }
  59.  
  60. }
  61. objectsForFilter.Clear();
  62. filterEntities = false;
  63. Debug.WriteLine(string.Format("Command {0} Ended.", e.GlobalCommandName));
  64. }
  65. }
  66.  
« Last Edit: December 05, 2016, 03:31:22 am by Atook »

MexicanCustard

  • Swamp Rat
  • Posts: 666
Re: Trap copy/pasteclip event?
« Reply #2 on: December 05, 2016, 01:02:57 pm »
Don't forget to loop through any open documents in your initialize method.
Code - C#: [Select]
  1. foreach (var document in Application.DocumentManager.Cast<Document>())
  2. {
  3.    document.CommandWillStart += doc_CommandWillStart;
  4.    document.CommandEnded += doc_CommandEnded;
  5.    //etc.
  6. }
AMEP 2017 64bit Win 10

Bobby C. Jones

  • Bull Frog
  • Posts: 490
  • Cry havoc and let loose the dogs of war.
Re: Trap copy/pasteclip event?
« Reply #3 on: December 05, 2016, 02:59:11 pm »
Probably irrelevant as I imagine your filterEntitties flag is preventing any noticeable overhead, but a pattern I typically use in this situation is to subscribe and unsubscribe to the object appended event in the command start and end events.
Bobby C. Jones

Atook

  • Swamp Rat
  • Posts: 815
Re: Trap copy/pasteclip event?
« Reply #4 on: December 06, 2016, 02:56:30 pm »
Thanks for the comments.
Bobby, you're right, I had that thought as I was thinking about how to accomplish this task. Any overhead is too much when it comes to reactors, I'm essentially re-writing a COM app that had terrible reactor performance, and I don't want to repeat that mistake.

MC, my code is being loaded via bundle, so the doc collection should be empty when the Initialization code runs. Your comment made me realize that users might possibly not load the bundle and netload later creating problems, better safe than sorry.

As it stands, the updated code looks something like this:
Code - C#: [Select]
  1. public class AIDApplication : IExtensionApplication
  2. {
  3. public ObjectIdCollection objectsForFilter;
  4.  
  5.  
  6. public void Initialize()
  7. {
  8. docManager.DocumentCreated += AddDocumentHandlers;
  9. docManager.DocumentToBeDestroyed += RemoveDocumentHandlers;
  10. // add document handlers to all existing documents (shouldn't happen if we load from bundle)
  11. foreach (var doc in docManager.Cast<Document>())
  12. {
  13. doc.CommandWillStart += doc_CommandWillStart;
  14. doc.CommandEnded += doc_CommandEnded;
  15. }
  16. }
  17.  
  18. /// <summary>
  19. /// When objects are added to the database, check them and see if they need to be handled
  20. /// </summary>
  21. /// <param name="sender">The source of the event.</param>
  22. /// <param name="e">The <see cref="ObjectEventArgs"/> instance containing the event data.</param>
  23. private void callback_ObjectAppended(object sender, ObjectEventArgs e)
  24. {
  25. if (objectsForFilter!=null)
  26. {
  27. objectsForFilter.Add(e.DBObject.ObjectId);
  28. }
  29. }
  30.  
  31. /// <summary>
  32. /// Add event handlers to the command events and the objectAppended
  33. /// </summary>
  34. /// <param name="sender">The sender.</param>
  35. /// <param name="e">The <see cref="DocumentCollectionEventArgs"/> instance containing the event data.</param>
  36. private void AddDocumentHandlers(object sender, DocumentCollectionEventArgs e)
  37. {
  38. if (Active.Document == null) return;
  39. Active.Document.CommandWillStart += doc_CommandWillStart;
  40. Active.Document.CommandEnded += doc_CommandEnded;
  41. }
  42.  
  43. /// <summary>
  44. /// Removes the document handlers.
  45. /// </summary>
  46. /// <param name="sender">The sender.</param>
  47. /// <param name="e">The <see cref="Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs" /> instance containing the event data.</param>
  48. private void RemoveDocumentHandlers(object sender, DocumentCollectionEventArgs e)
  49. {
  50. if (Active.Document == null) return;
  51. Active.Document.CommandWillStart -= doc_CommandWillStart;
  52. Active.Document.CommandEnded -= doc_CommandEnded;
  53. }
  54.  
  55. /// <summary>
  56. /// Handles the CommandWillStart event of the document.
  57. /// Checks to see if copy command is starting
  58. /// </summary>
  59. /// <param name="sender">The source of the event.</param>
  60. /// <param name="e">The <see cref="CommandEventArgs"/> instance containing the event data.</param>
  61. private void doc_CommandWillStart(object sender, CommandEventArgs e)
  62. {
  63. Debug.WriteLine(string.Format("Command {0} will start.", e.GlobalCommandName));
  64. if (e.GlobalCommandName.ToUpper()=="COPY" || e.GlobalCommandName.ToUpper()=="PASTECLIP")
  65. {
  66. objectsForFilter = new ObjectIdCollection();
  67. Active.Database.ObjectAppended += callback_ObjectAppended;
  68. }
  69. }
  70.  
  71. /// <summary>
  72. /// Command Ended
  73. /// </summary>
  74. /// <param name="sender">The source of the event.</param>
  75. /// <param name="e">The <see cref="CommandEventArgs"/> instance containing the event data.</param>
  76. void doc_CommandEnded(object sender, CommandEventArgs e)
  77. {
  78. Active.Database.ObjectAppended -= callback_ObjectAppended;
  79. if (objectsForFilter == null) return;
  80. // if we have objects to check for do cool stuff
  81. foreach (ObjectId id in objectsForFilter)
  82. {
  83. // Do cool stuff
  84. }
  85. objectsForFilter.Clear();
  86. Debug.WriteLine(string.Format("Command {0} Ended.", e.GlobalCommandName));
  87. }
  88.  
  89. }
  90.  
« Last Edit: December 06, 2016, 07:41:59 pm by Atook »

n.yuan

  • Bull Frog
  • Posts: 223
Re: Trap copy/pasteclip event?
« Reply #5 on: December 06, 2016, 06:11:09 pm »
I'd hook up AddDocumentHandler with DocumentCollection.DocumentCreated event, not DocumentActivated event, because DocumentActivated event can occur many times during the life span of a document, such as each time you display a modal dialog/message box, when the dialog box/message box is dismissed, DocuemtActivated event fires So, your code would add doc_CommandWillStart and doc_CommandEnded event handlers to the database multiple times.

Atook

  • Swamp Rat
  • Posts: 815
Re: Trap copy/pasteclip event?
« Reply #6 on: December 06, 2016, 07:44:05 pm »
I'd hook up AddDocumentHandler with DocumentCollection.DocumentCreated event...

Nice catch Yuan, this was actually causing the code to crash, I assume from adding the same handler multiple times, I've updated the code above to show the DocumentCreated event.

huiz

  • Swamp Rat
  • Posts: 763
  • Certified Prof C3D
Re: Trap copy/pasteclip event?
« Reply #7 on: December 13, 2016, 09:45:49 am »
The Clipboard Manager was an ADN Plugin of the Month once:

http://through-the-interface.typepad.com/through_the_interface/2009/09/clipboard-manager-octobers-adn-plugin-of-the-month-now-live-on-autodesk-labs.html

Sourcecode is available too somewhere, I might have a copy probably if you need. It's VB.NET unfortunately.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.