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;
}
}
}
if (!recordName.Contains("|"))
{
ed.WriteMessage("\nPurging " +
record.GetType().Name + " " + recordName);
}
Thanks guys. Please don't be shy about telling me if I did something bone-headed.
Autodesk.AutoCAD.DatabaseServices.Database.Purge(Autodesk.AutoCAD.DatabaseServices.ObjectIdGraph)
From ObjectARX Docs: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
Luis - there really should be an isEmpty method for all collections, but you were just yankin my chain, weren't you.
foreach (ObjectId id in purgeableIds)
{
..
}
If there is something on the collection, it will be process no?return purgeableIds.Count > 0;
... but purgeableIds would be out of scope , yes ?