Pietari Posted December 5, 2014 Share Posted December 5, 2014 Every now and then I open my drawings and wonder "huh, who did that". Well of course nobody has done anything. Even "it must have been you who did that". I have often wondered if there was a possibility to have some xData added to any changed object. I believe it would require a reactor and some xData code. I am aware of these possibilities and of their power but I have never really understood the concept of reactors and xData. Maybe any of you want to help out? It would be cool that any object placed newly in the drawing and any modified object in the drawing would have an xData wich contains (getvar 'LOGINNAME). So at any given point I am able to retrieve who lastly modified the object. If someone deletes objects, then of course it is lost, but thats okay. Thanks for any help on this one, it may contribute to others as well. (maybe there are other ways to explore but I have no clue) Quote Link to comment Share on other sites More sharing options...
Lee Mac Posted December 5, 2014 Share Posted December 5, 2014 (edited) The following is an initial draft of a possible application to achieve this: [color=GREEN];; Last Modification Logging Utility - Lee Mac[/color] [color=GREEN];; Stores the username/date/command as xdata attached to every modified object.[/color] ([color=BLUE]setq[/color] lastmod:appid [color=MAROON]"LMAC_lastmod"[/color]) ([color=BLUE]defun[/color] c:lastmod ( [color=BLUE]/[/color] ent lst ) ([color=BLUE]while[/color] ([color=BLUE]progn[/color] ([color=BLUE]setvar[/color] 'errno 0) ([color=BLUE]setq[/color] ent ([color=BLUE]car[/color] ([color=BLUE]entsel[/color] [color=MAROON]"\nSelect object to view modification data <exit>: "[/color]))) ([color=BLUE]cond[/color] ( ([color=BLUE]=[/color] 7 ([color=BLUE]getvar[/color] 'errno)) ([color=BLUE]princ[/color] [color=MAROON]"\nMissed, try again."[/color]) ) ( ([color=BLUE]null[/color] ent) [color=BLUE]nil[/color]) ( ([color=BLUE]null[/color] ([color=BLUE]setq[/color] lst ([color=BLUE]mapcar[/color] '[color=BLUE]cdr[/color] ([color=BLUE]cdadr[/color] ([color=BLUE]assoc[/color] -3 ([color=BLUE]entget[/color] ent ([color=BLUE]list[/color] lastmod:appid))))))) ([color=BLUE]princ[/color] [color=MAROON]"\nSelected object does not contain modification data."[/color]) ) ( ([color=BLUE]princ[/color] ([color=BLUE]strcat[/color] [color=MAROON]"\nObject last modified by "[/color] ([color=BLUE]car[/color] lst) [color=MAROON]" at "[/color] ([color=BLUE]cadr[/color] lst) [color=MAROON]" using the "[/color] ([color=BLUE]caddr[/color] lst) [color=MAROON]" command."[/color]))) ) ) ) ([color=BLUE]princ[/color]) ) ([color=BLUE]defun[/color] c:lastmodclear ( [color=BLUE]/[/color] idx sel ) ([color=BLUE]if[/color] ([color=BLUE]setq[/color] sel ([color=BLUE]ssget[/color] [color=MAROON]"_:L"[/color] ([color=BLUE]list[/color] ([color=BLUE]list[/color] -3 ([color=BLUE]list[/color] lastmod:appid))))) ([color=BLUE]repeat[/color] ([color=BLUE]setq[/color] idx ([color=BLUE]sslength[/color] sel)) ([color=BLUE]entmod[/color] ([color=BLUE]append[/color] ([color=BLUE]entget[/color] ([color=BLUE]ssname[/color] sel ([color=BLUE]setq[/color] idx ([color=BLUE]1-[/color] idx)))) ([color=BLUE]list[/color] ([color=BLUE]list[/color] -3 ([color=BLUE]list[/color] lastmod:appid))))) ) ) ([color=BLUE]princ[/color]) ) ([color=BLUE]defun[/color] c:lastmodon [color=BLUE]nil[/color] (lastmod:remove) ([color=BLUE]vlr-command-reactor[/color] [color=MAROON]"lastmod"[/color] '( ([color=BLUE]:vlr-commandwillstart[/color] . lastmod:com:start) ([color=BLUE]:vlr-commandended[/color] . lastmod:com:ended) ([color=BLUE]:vlr-commandcancelled[/color] . lastmod:com:clear) ([color=BLUE]:vlr-commandfailed[/color] . lastmod:com:clear) ) ) ([color=BLUE]setq[/color] lastmod:obj:rtr ([color=BLUE]vlr-object-reactor[/color] ( ([color=BLUE]lambda[/color] ( sel [color=BLUE]/[/color] idx lst ) ([color=BLUE]if[/color] sel ([color=BLUE]repeat[/color] ([color=BLUE]setq[/color] idx ([color=BLUE]sslength[/color] sel)) ([color=BLUE]setq[/color] lst ([color=BLUE]cons[/color] ([color=BLUE]vlax-ename->vla-object[/color] ([color=BLUE]ssname[/color] sel ([color=BLUE]setq[/color] idx ([color=BLUE]1-[/color] idx)))) lst)) ) ) ) ([color=BLUE]ssget[/color] [color=MAROON]"_X"[/color]) ) [color=MAROON]"lastmod"[/color] '( ([color=BLUE]:vlr-modified[/color] . lastmod:obj:modified) ([color=BLUE]:vlr-subobjmodified[/color] . lastmod:obj:modified) ) ) ) ([color=BLUE]regapp[/color] lastmod:appid) ([color=BLUE]princ[/color] [color=MAROON]"\nObject modification logging enabled."[/color]) ([color=BLUE]princ[/color]) ) ([color=BLUE]defun[/color] c:lastmodoff [color=BLUE]nil[/color] (lastmod:remove) ([color=BLUE]princ[/color] [color=MAROON]"\nObject modification logging disabled."[/color]) ([color=BLUE]princ[/color]) ) ([color=BLUE]defun[/color] lastmod:remove [color=BLUE]nil[/color] ([color=BLUE]foreach[/color] obj ([color=BLUE]apply[/color] '[color=BLUE]append[/color] ([color=BLUE]mapcar[/color] '[color=BLUE]cdr[/color] ([color=BLUE]vlr-reactors[/color] [color=BLUE]:vlr-object-reactor[/color] [color=BLUE]:vlr-command-reactor[/color]))) ([color=BLUE]if[/color] ([color=BLUE]=[/color] [color=MAROON]"lastmod"[/color] ([color=BLUE]vlr-data[/color] obj)) ([color=BLUE]vlr-remove[/color] obj)) ) ([color=BLUE]setq[/color] lastmod:obj:rtr [color=BLUE]nil[/color] lastmod:entlast [color=BLUE]nil[/color] lastmod:objlist [color=BLUE]nil[/color] ) ) ([color=BLUE]defun[/color] lastmod:obj:modified ( obj rtr arg ) ([color=BLUE]setq[/color] lastmod:objlist ([color=BLUE]cons[/color] obj lastmod:objlist)) ([color=BLUE]princ[/color]) ) ([color=BLUE]defun[/color] lastmod:com:start ( rtr com [color=BLUE]/[/color] tmp ) ([color=BLUE]setq[/color] lastmod:entlast ([color=BLUE]entlast[/color])) ([color=BLUE]while[/color] ([color=BLUE]setq[/color] tmp ([color=BLUE]entnext[/color] lastmod:entlast)) ([color=BLUE]setq[/color] lastmod:entlast tmp) ) ([color=BLUE]princ[/color]) ) ([color=BLUE]defun[/color] lastmod:com:ended ( rtr com [color=BLUE]/[/color] ent obj ) ([color=BLUE]setq[/color] com ([color=BLUE]strcase[/color] ([color=BLUE]car[/color] com)) ent ([color=BLUE]if[/color] lastmod:entlast ([color=BLUE]entnext[/color] lastmod:entlast) ([color=BLUE]entnext[/color])) ) ([color=BLUE]foreach[/color] obj lastmod:objlist (lastmod:addxdata ([color=BLUE]vlax-vla-object->ename[/color] obj) com) ) ([color=BLUE]while[/color] ent ([color=BLUE]if[/color] ([color=BLUE]vlax-write-enabled-p[/color] ([color=BLUE]setq[/color] obj ([color=BLUE]vlax-ename->vla-object[/color] ent))) ([color=BLUE]progn[/color] (lastmod:addxdata ent com) ([color=BLUE]vlr-owner-add[/color] lastmod:obj:rtr obj) ) ) ([color=BLUE]setq[/color] ent ([color=BLUE]entnext[/color] ent)) ) ([color=BLUE]setq[/color] lastmod:objlist [color=BLUE]nil[/color] lastmod:entlast [color=BLUE]nil[/color] ) ([color=BLUE]princ[/color]) ) ([color=BLUE]defun[/color] lastmod:clear ( rtr arg ) ([color=BLUE]setq[/color] lastmod:objlist [color=BLUE]nil[/color] lastmod:entlast [color=BLUE]nil[/color] ) ([color=BLUE]princ[/color]) ) ([color=BLUE]defun[/color] lastmod:addxdata ( ent com [color=BLUE]/[/color] enx ) ([color=BLUE]if[/color] ([color=BLUE]and[/color] ([color=BLUE]=[/color] 'ename ([color=BLUE]type[/color] ent)) ([color=BLUE]setq[/color] enx ([color=BLUE]entget[/color] ent)) ([color=BLUE]not[/color] ([color=BLUE]wcmatch[/color] ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 0 enx)) [color=MAROON]"VERTEX,ATTRIB,SEQEND"[/color])) ) ([color=BLUE]entmod[/color] ([color=BLUE]append[/color] ([color=BLUE]entget[/color] ent) ([color=BLUE]list[/color] ([color=BLUE]list[/color] -3 ([color=BLUE]list[/color] lastmod:appid ([color=BLUE]cons[/color] 1000 ([color=BLUE]getvar[/color] 'loginname)) ([color=BLUE]cons[/color] 1000 ([color=BLUE]menucmd[/color] [color=MAROON]"m=$(edtime,0,yyyy-mo-dd hh:mm:ss)"[/color])) ([color=BLUE]cons[/color] 1000 com) ) ) ) ) ) ) ) ([color=BLUE]vl-load-com[/color]) ([color=BLUE]princ[/color]) Type 'LASTMODON' to enable modification logging, and 'LASTMODOFF' to disable logging. Type 'LASTMOD' to view the last modification data for an object. Type 'LASTMODCLEAR' to remove the logged modification data for a set of objects. When enabled, a Command Reactor & Object Reactor will run silently in the background and will attach xdata to modified objects containing the username, date/time of the modification, and the name of the last command used. The code has only been briefly tested, so expect some bugs. Lee Edited December 6, 2014 by Lee Mac Quote Link to comment Share on other sites More sharing options...
Pietari Posted December 5, 2014 Author Share Posted December 5, 2014 Hi Lee, Thanks for the reply & possible solution. I have tested it and used this code to retrieve the xData: (Found here) (defun c:xdread ( / en xd ) (if (setq en (car (entsel "\nSelect entity to read xdata:"))) (if (setq xd (cdr (assoc -3 (entget en '("*"))))) (foreach a xd (foreach x a (print x)) ) (princ "\nEntity has no xdata.") ) ) (princ) ) Your code works like expected / hoped for. Only the way to retrieve the xData back is kind of simple now but it is good enough. I can at least find out who has modified certain objects! About possible bugs, I have found 1 so far: when te reactor is active it errors on any command: Command: *Cancel* Command: REC RECTANG Specify first corner point or [Chamfer/Elevation/Fillet/Thickness/Width]: Specify other corner point or [Area/Dimensions/Rotation]: ; error: bad argument type: lentityp nil Command: L LINE Specify first point: Specify next point or [Angle/Length/Undo]: Specify next point or [Angle/Length/Undo]: ; error: bad argument type: lentityp nil Command: PL PLINE Specify start point: Current line-width is 0.0000 Specify next point or [Arc/Halfwidth/Length/Undo/Width]: Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]: Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]: ; error: bad argument type: lentityp nil Command: C CIRCLE Specify center point for circle or [3P/2P/Ttr (tan tan radius)]: Specify radius of circle or [Diameter] <184.4649>: ; error: bad argument type: lentityp nil Command: ARC Specify start point of arc or [Center]: Specify second point of arc or [Center/End]: Specify end point of arc: ; error: bad argument type: lentityp nil Command: ARC Specify start point of arc or [Center]: *Cancel* Command: *Cancel* Command: XL XLINE Specify a point or [Hor/Ver/Ang/Bisect/Offset]: Specify through point: Specify through point: ; error: bad argument type: lentityp nil Command: Command: Command: _ellipse Specify axis endpoint of ellipse or [Arc/Center]: _c Specify center of ellipse: Specify endpoint of axis: Specify distance to other axis or [Rotation]: ; error: bad argument type: lentityp nil Command: e ERASE Select objects: Specify opposite corner: 2 found Select objects: ; error: bad argument type: lentityp nil MOVE Select objects: 1 found Select objects: Specify base point or [Displacement] <Displacement>: Specify second point of displacement or <use first point as displacement>: ; error: bad argument type: lentityp nil Command: CO COPY Select objects: 1 found Select objects: Current settings: Copy mode = Multiple Specify base point or [Displacement/mOde] <Displacement>: Specify second point of displacement or <use first point as displacement>: Specify second point or [Exit/Undo] <Exit>: *Cancel* Command: COPY Select objects: 1 found Select objects: Current settings: Copy mode = Multiple Specify base point or [Displacement/mOde] <Displacement>: Specify second point of displacement or <use first point as displacement>: Specify second point or [Exit/Undo] <Exit>: ; error: bad argument type: lentityp nil I dont know if it could be fixed / done... but it is a good start, thanks! Quote Link to comment Share on other sites More sharing options...
Lee Mac Posted December 5, 2014 Share Posted December 5, 2014 Thank you for the feedback Pietari, please try the updated code above. I have now added another command: LASTMOD to enable you to view the modification data for a selected object. (FWIW, you could also have used the XDLIST command). Lee Quote Link to comment Share on other sites More sharing options...
BIGAL Posted December 6, 2014 Share Posted December 6, 2014 Another possibility is you can record every time a dwg is opened who opened it and what commands were executed runs fine on a server based system, interesting to look at how many commands v's time in dwg commands hopefully = production. Productivity_Analisys_Tool.lsp by Konstantin Gerasimov, kosio_gerasimov@abv.bg Quote Link to comment Share on other sites More sharing options...
Pietari Posted December 6, 2014 Author Share Posted December 6, 2014 @ Bigal: that solution has crossed my mind as well but I'd rather explore the xData options, thanks anyway! @ Lee: First of all thank you for the effort, you have really understood what I mean. The program does exactly what it is supposed to do. I will put this code in our users acad.lsp file or my own startup routines. At any given point I can look and say "YOU DID IT!" This solution maybe combined with the solution suggested by Bigal would make it possible to build up a history. Meaning: if a block is inserted, I can see who initially put it in the drawing. If that block would be moved, etc. it would keep track of who did what and when. By the way, I noticed that when you modify a blocks attibutes, there is no xData added to the blok itself. So a change of attribute values is not working. Maybe xData can only be stored to an object itself and not a block. Manu kudo's to you Lee!! Quote Link to comment Share on other sites More sharing options...
Lee Mac Posted December 6, 2014 Share Posted December 6, 2014 First of all thank you for the effort, you have really understood what I mean.The program does exactly what it is supposed to do. I will put this code in our users acad.lsp file or my own startup routines. At any given point I can look and say "YOU DID IT!" Many thanks Pietari - it was an interesting application to write! By the way, I noticed that when you modify a blocks attibutes, there is no xData added to the blok itself.So a change of attribute values is not working. I have now updated the above code to ensure changes to block attributes and 3D polyline vertices are also logged. I have also added a new command: LASTMODCLEAR to enable you to remove the logged modification data for a selection of objects if necessary. Manu kudo's to you Lee!! Thanks! Quote Link to comment Share on other sites More sharing options...
BlackBox Posted December 6, 2014 Share Posted December 6, 2014 I have tested it and used this code to retrieve the xData: (Found here) (defun c:xdread ( / en xd ) (if (setq en (car (entsel "\nSelect entity to read xdata:"))) (if (setq xd (cdr (assoc -3 (entget en '("*"))))) (foreach a xd (foreach x a (print x)) ) (princ "\nEntity has no xdata.") ) ) (princ) ) You may also find MgdDbg to be useful for this and other querying tasks. Cheers Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.