Saturday, June 18, 2011

Set Layouts in Order

When creating a new layout in AutoCAD, the newly created layout is appended to AutoCAD drawing editor as last layout tab. Sometimes, a user may want to sort the layout tabs in certain order, such as ascending/descending by the layout name, or whatever order the user wants.

AutoCAD editor itself provides a way to manually sort layout tab by right-clicking a layout tab and select "Move or copy..." context menu. This way, user can change a layout tab's order one at a time. It would be tedious work if the user has to re-order many layout tabs.

Sometimes, one may create many layouts programmatically and want to sort their tabs in certain way, most likely, sort them by layout names.

Here is some code that sorts layout tabs by the layout names. The code actually does is to get a string list/array from all layouts' name, then sort/re-order the string list/array, and finally set a Layout's TabOrder property according to its name's order in the string list/array.

    1 using System.Collections.Generic;
    2 using System.Linq;
    3 
    4 using Autodesk.AutoCAD.ApplicationServices;
    5 using Autodesk.AutoCAD.DatabaseServices;
    6 using Autodesk.AutoCAD.Runtime;
    7 using Autodesk.AutoCAD.EditorInput;
    8 
    9 [assembly: CommandClass(typeof(OrderLayout.MyCommands))]
   10 
   11 namespace OrderLayout
   12 {
   13     public class MyCommands
   14     {
   15         [CommandMethod("OrderLayout")]
   16         public static void OrderAllLayouts()
   17         {
   18             Document dwg = Application.DocumentManager.MdiActiveDocument;
   19             Editor ed = dwg.Editor;
   20 
   21             //Get user input of sorting direction
   22             PromptKeywordOptions opt =
   23                 new PromptKeywordOptions("\nEnter sorting order: ");
   24             opt.Keywords.Add("Asc");
   25             opt.Keywords.Add("Desc");
   26             opt.AppendKeywordsToMessage = true;
   27 
   28             PromptResult res = ed.GetKeywords(opt);
   29             if (res.Status == PromptStatus.OK)
   30             {
   31                 string order = res.StringResult;
   32 
   33                 //Sort the layouts
   34                 SetLayoutOrder(order);
   35 
   36                 ed.Regen();
   37             }
   38             else
   39             {
   40                 ed.WriteMessage("\n*Cancel*\n");
   41             }
   42         }
   43 
   44         [CommandMethod("NewLayout")]
   45         public static void CreateNewLayout()
   46         {
   47             Document dwg = Application.DocumentManager.MdiActiveDocument;
   48             Editor ed = dwg.Editor;
   49 
   50             //Get new layout name from user
   51             PromptStringOptions opt =
   52                 new PromptStringOptions("\nEnter a new layout name: ");
   53 
   54             PromptResult res = res = ed.GetString(opt);
   55             if (res.Status == PromptStatus.OK)
   56             {
   57                 string lName = res.StringResult;
   58 
   59                 //Create new layout
   60                 CreateLayout(lName);
   61 
   62                 ed.Regen();
   63             }
   64             else
   65             {
   66                 ed.WriteMessage("\n*Cancel*\n");
   67             }
   68         }
   69 
   70         [CommandMethod("ClearLayout")]
   71         public static void ClearAllLayout()
   72         {
   73             Document dwg = Application.DocumentManager.MdiActiveDocument;
   74             Editor ed = dwg.Editor;
   75 
   76             //Remove all layout.
   77             //Note, depending Acad configuration, after this method running,
   78             //all layouts should be removed. However, AutoCAD may always create
   79             //a layout named as "Layout1" right after this command execution.
   80             ClearLayouts();
   81 
   82             ed.WriteMessage("All layouts have been removed.");
   83         }
   84 
   85         #region private methods - miscellaneous, create and remove layout
   86 
   87         //This method returns a layout name list ("Model" excluded)
   88         private static string[] GetLayoutNames()
   89         {
   90             List<Layout> lays = new List<Layout>();
   91 
   92             Database db = HostApplicationServices.WorkingDatabase;
   93             using (Transaction tran = db.TransactionManager.StartTransaction())
   94             {
   95                 DBDictionary lDic =
   96                     (DBDictionary)tran.GetObject(db.LayoutDictionaryId,
   97                     OpenMode.ForRead);
   98 
   99                 foreach (DBDictionaryEntry entry in lDic)
  100                 {
  101                     ObjectId id = (ObjectId)entry.Value;
  102                     lays.Add(tran.GetObject(id, OpenMode.ForRead) as Layout);
  103                 }
  104 
  105                 tran.Commit();
  106             }
  107 
  108             int c = lays.Count;
  109 
  110             return (from l in lays
  111                     where l.LayoutName.ToUpper() != "MODEL"
  112                     select l.LayoutName).ToArray();
  113         }
  114 
  115         private static Layout GetLayoutFromId(ObjectId id, Transaction tran)
  116         {
  117             return tran.GetObject(id, OpenMode.ForRead) as Layout;
  118         }
  119 
  120         private static void CreateLayout(string layoutName)
  121         {
  122             //Get Layout list
  123             string[] layouts = GetLayoutNames();
  124             if (LayoutExists(layoutName, layouts)) return;
  125 
  126             LayoutManager mgr = LayoutManager.Current;
  127             mgr.CreateLayout(layoutName);
  128         }
  129 
  130         private static void ClearLayouts()
  131         {
  132             //Get Layout list
  133             string[] layouts = GetLayoutNames();
  134 
  135             LayoutManager mgr = LayoutManager.Current;
  136             foreach (string l in layouts)
  137             {
  138                 mgr.DeleteLayout(l);
  139             }
  140         }
  141 
  142         private static bool LayoutExists(string lName, string[] layouts)
  143         {
  144             return (from l in layouts
  145                     where l.ToUpper() == lName.ToUpper()
  146                     select l).Count() > 0;
  147         }
  148 
  149         #endregion
  150 
  151         #region private methods - Sort layout in order
  152 
  153         private static void SetLayoutOrder(string order)
  154         {
  155             //Get Layout list
  156             string[] layouts = GetLayoutNames();
  157             string[] sortedLayouts;
  158 
  159             if (order.ToUpper() == "ASC")
  160                 sortedLayouts = (from l in layouts
  161                                  orderby l ascending select l).ToArray();
  162             else
  163                 sortedLayouts = (from l in layouts
  164                                  orderby l descending select l).ToArray();
  165 
  166             Database db = HostApplicationServices.WorkingDatabase;
  167 
  168             using (Transaction tran = db.TransactionManager.StartTransaction())
  169             {
  170                 LayoutManager mgr = LayoutManager.Current;
  171 
  172                 //First layout tab order should be 1
  173                 //because "Model" layout tab's order is always 0
  174                 int tab = 1;
  175                 foreach (string l in sortedLayouts)
  176                 {
  177                     ObjectId id = mgr.GetLayoutId(l);
  178 
  179                     Layout lay = tran.GetObject(id, OpenMode.ForWrite) as Layout;
  180                     lay.TabOrder = tab;
  181 
  182                     tab++;
  183                 }
  184 
  185                 tran.Commit();
  186             }
  187         }
  188 
  189         #endregion
  190     }
  191 }

In the above vode, command "NewLayout" and "ClearLayout" are just for the convenience of testing the "OrderLayout" command. To see the layout sorting effect, use "NewLayout" command to create a few randomly named layouts. Then run "OrderLayout" command.

As you can see, the trick of sorting layouts lies in getting a layout name list and re-order it in a desired order, then setting Layout.TabOrder property according to its name's order in the re-ordered layout name list. If you need to sort the layouts in specific order (not just ascending or descending by its name), you may want to build a UI that allows user to line up layouts' name in any order he/she wants to. Then you can obtain a String list/array ordered in the order user sets. Afterwards, you know how to set Layout's TabOrder property, as the code shows here.

No comments:

Post a Comment