using System;
using System.Collections.Generic;
using System.IO;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
public class Commands
{
/// <summary>
/// Copies all layouts from a specified source DWG file into the current drawing,
/// including all objects within each layout while preserving their positions.
/// If a layout name already exists in the current drawing, a suffix is appended to avoid conflicts.
/// </summary>
[CommandMethod("22CopyLayoutsFromDwg")]
public void CopyLayoutsFromDwg()
{
Document currentDocument = Application.DocumentManager.MdiActiveDocument;
Database destinationDatabase = currentDocument.Database;
Editor editor = currentDocument.Editor;
// Prompt the user for the source DWG file using a file dialog
PromptOpenFileOptions options = new PromptOpenFileOptions("\nSelect the source DWG file:");
options.Filter = "Drawing files (*.dwg)|*.dwg";
options.PreferCommandLine = false;
PromptFileNameResult promptResult = editor.GetFileNameForOpen(options);
if (promptResult.Status != PromptStatus.OK)
{
return;
}
string sourceFilePath = promptResult.StringResult;
// Validate the file existence
if (!File.Exists(sourceFilePath))
{
editor.WriteMessage("\nThe specified file does not exist.");
return;
}
// Open the source database in read-only mode
using (Database sourceDatabase = new Database(false, true))
{
sourceDatabase.ReadDwgFile(sourceFilePath, FileOpenMode.OpenForReadAndAllShare, true, null);
sourceDatabase.CloseInput(true);
// Start transactions for both databases
using (Transaction sourceTx = sourceDatabase.TransactionManager.StartTransaction())
using (Transaction destTx = destinationDatabase.TransactionManager.StartTransaction())
{
// Access layout dictionaries
DBDictionary sourceLayouts = (DBDictionary)sourceTx.GetObject(sourceDatabase.LayoutDictionaryId, OpenMode.ForRead);
DBDictionary destinationLayouts = (DBDictionary)destTx.GetObject(destinationDatabase.LayoutDictionaryId, OpenMode.ForWrite);
LayoutManager layoutManager = LayoutManager.Current;
foreach (DBDictionaryEntry layoutEntry in sourceLayouts)
{
// Skip the Model layout
if (layoutEntry.Key == "Model")
{
continue;
}
Layout sourceLayout = (Layout)sourceTx.GetObject(layoutEntry.Value, OpenMode.ForRead);
// Determine a unique name for the new layout
string newLayoutName = layoutEntry.Key;
int suffix = 1;
while (destinationLayouts.Contains(newLayoutName))
{
newLayoutName = layoutEntry.Key + "_" + suffix++;
}
// Create the new layout using LayoutManager
ObjectId destinationLayoutId = layoutManager.CreateLayout(newLayoutName);
// Open the new layout for write
Layout destinationLayout = (Layout)destTx.GetObject(destinationLayoutId, OpenMode.ForWrite);
// Copy properties from source layout
destinationLayout.CopyFrom(sourceLayout);
// Get source and destination block table records
BlockTableRecord sourceBlockTableRecord = (BlockTableRecord)sourceTx.GetObject(sourceLayout.BlockTableRecordId, OpenMode.ForRead);
BlockTableRecord destinationBlockTableRecord = (BlockTableRecord)destTx.GetObject(destinationLayout.BlockTableRecordId, OpenMode.ForWrite);
// Collect objects to clone and track viewports for freeze settings
ObjectIdCollection objectsToClone = new ObjectIdCollection();
Dictionary<ObjectId, List<string>> viewportFrozenLayers = new Dictionary<ObjectId, List<string>>();
foreach (ObjectId objectId in sourceBlockTableRecord)
{
using (DBObject obj = sourceTx.GetObject(objectId, OpenMode.ForRead))
{
if (obj is Viewport viewport && viewport.Number == 1)
{
continue; // Skip the paper space viewport to avoid duplication and corruption
}
objectsToClone.Add(objectId);
// Capture frozen layers only for non-paper space viewports
if (obj is Viewport vp && vp.Number != 1)
{
List<string> frozenLayerNames = new List<string>();
ObjectIdCollection frozenLayerIds = vp.GetFrozenLayers();
foreach (ObjectId layerId in frozenLayerIds)
{
LayerTableRecord layer = (LayerTableRecord)sourceTx.GetObject(layerId, OpenMode.ForRead);
frozenLayerNames.Add(layer.Name);
}
viewportFrozenLayers.Add(objectId, frozenLayerNames);
}
}
}
if (objectsToClone.Count > 0)
{
IdMapping idMapping = new IdMapping();
destinationDatabase.WblockCloneObjects(objectsToClone, destinationBlockTableRecord.ObjectId, idMapping, DuplicateRecordCloning.Replace, false);
// Reapply frozen layers to cloned viewports
LayerTable lt = (LayerTable)destTx.GetObject(destinationDatabase.LayerTableId, OpenMode.ForRead);
foreach (var kvp in viewportFrozenLayers)
{
ObjectId sourceVpId = kvp.Key;
List<string> frozenNames = kvp.Value;
IdPair pair = idMapping.Lookup(sourceVpId);
if (pair != null)
{
ObjectId destVpId = pair.Value;
Viewport destViewport = (Viewport)destTx.GetObject(destVpId, OpenMode.ForWrite);
ObjectIdCollection destLayerIds = new ObjectIdCollection();
foreach (ObjectId layerId in lt)
{
LayerTableRecord ltr = (LayerTableRecord)destTx.GetObject(layerId, OpenMode.ForRead);
if (frozenNames.Contains(ltr.Name))
{
destLayerIds.Add(layerId);
}
}
destViewport.FreezeLayersInViewport(destLayerIds.GetEnumerator());
}
}
}
}
destTx.Commit();
// sourceTx.Commit() not needed as no writes, dispose will handle
}
}
editor.WriteMessage("\nLayouts copied successfully.");
}
}