Author Topic: Purge Tools  (Read 13912 times)

0 Members and 1 Guest are viewing this topic.

Chuck Gabriel

  • Guest
Purge Tools
« on: November 14, 2008, 09:29:14 AM »
I wrote this a while back, and I thought it was generic enough that someone else might find it useful.

Code: [Select]
using System;
using System.Text;
using System.Collections.Generic;

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;

[assembly: ExtensionApplication(typeof(cgabriel.PurgeTools))]
[assembly: CommandClass(typeof(cgabriel.PurgeTools))]

namespace cgabriel
{
    public class PurgeTools : IExtensionApplication
    {

        public void Initialize() { }
        public void Terminate() { }

        public static bool purgeItems(Database db, ObjectIdCollection tableIds, bool silent)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

            bool itemsPurged = false;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ObjectIdCollection purgeableIds = new ObjectIdCollection();
                foreach (ObjectId tableId in tableIds)
                {
                    SymbolTable table = (SymbolTable)tr.GetObject(tableId, OpenMode.ForRead, false);
                    foreach (ObjectId recordId in table)
                        purgeableIds.Add(recordId);
                }

                db.Purge(purgeableIds);

                if (purgeableIds.Count != 0)
                {
                    itemsPurged = true;
                    foreach (ObjectId id in purgeableIds)
                    {
                        SymbolTableRecord record = (SymbolTableRecord)tr.GetObject(id, OpenMode.ForWrite);
                        string recordName = record.Name;
                        if (!silent)
                        {
                            if (!recordName.Contains("|"))
                            {
                                ed.WriteMessage("\nPurging " +
                                    record.GetType().Name + " " + recordName);
                            }
                        }
                        record.Erase();
                    }
                }
                tr.Commit();
            }

            return itemsPurged;
        }

        public static bool purgeAll(Database db, bool silent)
        {
            ObjectIdCollection tableIds = new ObjectIdCollection();
            tableIds.Add(db.BlockTableId);
            tableIds.Add(db.DimStyleTableId);
            tableIds.Add(db.LayerTableId);
            tableIds.Add(db.LinetypeTableId);
            tableIds.Add(db.RegAppTableId);
            tableIds.Add(db.TextStyleTableId);
            tableIds.Add(db.UcsTableId);
            tableIds.Add(db.ViewportTableId);
            tableIds.Add(db.ViewTableId);
            return purgeItems(db, tableIds, silent);
        }

        [CommandMethod("PurgeTools", "PurgeAll", CommandFlags.Modal | CommandFlags.DocExclusiveLock)]
        public static void purgeAll()
        {
            while (purgeAll(Application.DocumentManager.MdiActiveDocument.Database, false))
                continue;
        }
    }
}

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8698
  • AKA Daniel
Re: Purge Tools
« Reply #1 on: November 15, 2008, 08:49:20 AM »
Nice Work Chuck!

Can you explain what this line does?


Code: [Select]
                 
 if (!recordName.Contains("|"))
    {
        ed.WriteMessage("\nPurging " +
        record.GetType().Name + " " + recordName);
    }
« Last Edit: November 15, 2008, 08:53:41 AM by Daniel »

Chuck Gabriel

  • Guest
Re: Purge Tools
« Reply #2 on: November 15, 2008, 09:04:33 AM »
I found that the purge method was identifying xref-dependent objects as purgeable, and while deleting those objects doesn't seem to cause any corruption, I thought it might panic some users to see messages saying that those items were being purged.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8698
  • AKA Daniel
Re: Purge Tools
« Reply #3 on: November 15, 2008, 10:31:58 AM »
Thank you!  :kewl:

Glenn R

  • Guest
Re: Purge Tools
« Reply #4 on: November 15, 2008, 02:00:23 PM »
Chuckster - nice work as usual. :)

Chuck Gabriel

  • Guest
Re: Purge Tools
« Reply #5 on: November 15, 2008, 03:28:22 PM »
Thanks guys.  Please don't be shy about telling me if I did something bone-headed.

Spike Wilbury

  • Guest
Re: Purge Tools
« Reply #6 on: November 15, 2008, 03:52:52 PM »
Thanks guys.  Please don't be shy about telling me if I did something bone-headed.

OK, you asked for the true - here it goes:

Please do it all again - and don't use this : if (purgeableIds.Count != 0) - anymore, eh!

 :evil:

 :angel:
 :lol:
 :-P
 :ugly:

 :lmao:  :lmao:  :lmao:

Alexander Rivilis

  • Bull Frog
  • Posts: 214
  • Programmer from Kyiv (Ukraine)
Re: Purge Tools
« Reply #7 on: November 15, 2008, 04:04:32 PM »
Hi. Chuck!
It will be more correctly to use this form of purge method:
Code: [Select]
Autodesk.AutoCAD.DatabaseServices.Database.Purge(Autodesk.AutoCAD.DatabaseServices.ObjectIdGraph)From ObjectARX Docs:
Quote
This version of the purge() method works in one pass. The method looks for references between the objects passed in so that it does not need to be called multiple times. In other words, if a Layer and a Linetype are passed in, and the only reference to the Linetype is from the Layer, then the graph returned will indicate that both the Layer and the Linetype can be purged. (The older AcDbObjectIdArray version of purge() would first indicate that only the Layer could be purged. Then a second call, after erasing the Layer, would say that the Linetype could be purged.)

A graph is returned so that you do not need to erase all the objects passed back, just like in the other purge(). However, if you want to selectively erase only part of the objects passed back, you must only erase root-type nodes on the graph. In other words, from the above example, the graph passed back would contain both the Layer and Linetype nodes, but there would be an edge from the Layer to the Linetype. Thus only the Layer would be a root-type node, with no incoming edges. That means that you could erase the Layer by itself, but not the Linetype. If you want to erase the Linetype, then you must also erase the Layer. That's why the return data is in a graph.

Notes

Since the AcDbObjectIdGraph version (this method) does more checking, it is slower than the AcDbObjectIdArray version.
If only one type of symbol is being checked through purge(), and it is not a BTR (which can have references to each other), then the older, faster AcDbObjectIdArray purge() should be used.
Only use this version in cases where there were loops before. In other words, if the types of symbols being passed in can reference each other, then the purge(AcDbObjectIdArray) function would have had to have been called multiple times. Even though this function is slower, since it only has to be called once, it ends up being faster for this inter-reference case.
If you intend to always erase everything returned, then you do not have to examine the graph. You can just iterate on graph nodes and erase the objects, but you must erase all of them. The graph edges only need to be examined if part of the graph is to be erased, to make sure that no edges, or inter-references, are left dangling. In such a case, only nodes with no incoming edges (root-type nodes) can be erased
« Last Edit: November 15, 2008, 04:18:57 PM by Alexander Rivilis »

Chuck Gabriel

  • Guest
Re: Purge Tools
« Reply #8 on: November 15, 2008, 04:54:07 PM »
Alexander,

Thanks for the feedback.

The reason I didn't use that overload is because when I used the native code version in the past, it seemed to be leaving items in the graph that should not have been purged.

See this thread.

Was I doing something wrong or maybe just misunderstanding something?

Luis - there really should be an isEmpty method for all collections, but you were just yankin my chain, weren't you.

Spike Wilbury

  • Guest
Re: Purge Tools
« Reply #9 on: November 15, 2008, 05:15:18 PM »
Luis - there really should be an isEmpty method for all collections, but you were just yankin my chain, weren't you.

Something like that Chuck.... and yes about why not the isEmpty();

But, can you/or did you test it by simple calling:

Code: [Select]
foreach (ObjectId id in purgeableIds)
{
..
}
If there is something on the collection, it will be process no?

:)

Chuck Gabriel

  • Guest
Re: Purge Tools
« Reply #10 on: November 15, 2008, 05:18:34 PM »
I could have done that, but I wanted to return a boolean indicating whether anything was purged, so I put in the check.  I guess I could have just done:

Code: [Select]
return purgeableIds.Count > 0;

at the end of the routine.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Purge Tools
« Reply #11 on: November 15, 2008, 05:21:25 PM »

 ... but purgeableIds would be out of scope , yes ?
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Purge Tools
« Reply #12 on: November 15, 2008, 05:22:51 PM »

Great looking routine Chuck.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Chuck Gabriel

  • Guest
Re: Purge Tools
« Reply #13 on: November 15, 2008, 05:23:09 PM »

 ... but purgeableIds would be out of scope , yes ?

It is right now, but the declaration could be moved outside of the transaction.  Thanks for the heads up.

Chuck Gabriel

  • Guest
Re: Purge Tools
« Reply #14 on: November 15, 2008, 05:24:45 PM »
Great feedback, by the way, everybody.